Asyncify Xhci::execute_transfer.

This commit is contained in:
4lDO2
2020-03-26 19:17:31 +01:00
parent 443b160b6d
commit bae238bbef
2 changed files with 63 additions and 52 deletions
+1 -2
View File
@@ -357,14 +357,13 @@ impl Xhci {
}
let command_ring = self.cmd.lock().unwrap();
let ring = &command_ring.ring;
EventTrbFuture::Pending {
state: FutureState {
// This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization).
is_isoch_or_vf: false,
state_kind: StateKind::CommandCompletion {
phys_ptr: ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb)
phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb)
},
message: Arc::new(Mutex::new(None)),
},
+62 -50
View File
@@ -306,7 +306,9 @@ impl Xhci {
}
/// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the
/// TRB (it could be a NO-OP in the worst case).
pub fn execute_transfer<D>(
/// The function is also required to set the Interrupt on Completion flag, or this function
/// will never complete.
pub async fn execute_transfer<D>(
&mut self,
port_num: usize,
endp_num: u8,
@@ -318,6 +320,14 @@ impl Xhci {
D: FnMut(&mut Trb, bool) -> ControlFlow,
{
let port_state = self.port_state_mut(port_num)?;
let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) {
(Some(c), Some(i)) => (c, i),
_ => return Err(Error::new(EIO)),
};
let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?;
let slot = port_state.slot;
let endp_state = port_state
.endpoint_states
@@ -338,57 +348,43 @@ impl Xhci {
.ok_or(Error::new(EBADF))?),
};
loop {
let future = loop {
let (trb, cycle) = ring.next();
match d(trb, cycle) {
ControlFlow::Break => break,
ControlFlow::Break => {
break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb);
}
ControlFlow::Continue => continue,
}
}
};
self.dbs[usize::from(slot)].write(Self::endp_doorbell(
self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell(
endp_num,
self.endp_desc(port_num, endp_num)?,
endp_desc,
if has_streams { stream_id } else { 0 },
));
let cloned_trb = {
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - {} Waiting for event", name);
}
let trbs = future.await;
let event_trb = trbs.event_trb;
let transfer_trb = trbs.src_trb.unwrap();
// FIXME: EDTLA if event data was set
if event.completion_code() != TrbCompletionCode::ShortPacket as u8
&& event.transfer_length() != 0
{
println!(
"Event trb didn't yield a short packet, but some bytes were not transferred"
);
}
handle_transfer_event_trb("EXECUTE_TRANSFER", &event_trb, &transfer_trb)?;
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::Transfer as u8
{
println!(
"Custom transfer event failed with {:#0x} {:#0x} {:#0x}",
event.data.read(),
event.status.read(),
event.control.read()
);
}
// TODO: Handle event data
println!("EVENT DATA: {:?}", event.event_data());
// FIXME: EDTLA if event data was set
if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8
&& event_trb.transfer_length() != 0
{
println!(
"Event trb didn't yield a short packet, but some bytes were not transferred"
);
return Err(Error::new(EIO));
}
let cloned_trb = event.clone();
event.reserved(false);
// TODO: Handle event data
println!("EVENT DATA: {:?}", event_trb.event_data());
cloned_trb
};
self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3));
Ok(cloned_trb)
Ok(event_trb)
}
fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> {
self.execute_control_transfer(
@@ -435,6 +431,8 @@ impl Xhci {
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle);
}).await;
self.event_handler_finished();
handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb)
}
@@ -512,9 +510,12 @@ impl Xhci {
}
}
fn port_state(&self, port: usize) -> Result<chashmap::ReadGuard<'_, usize, PortState>> {
fn port_state(&self, port: usize) -> Result<chashmap::ReadGuard<'_, usize, super::PortState>> {
self.port_states.get(&port).ok_or(Error::new(EBADF))
}
fn port_state_mut(&self, port: usize) -> Result<chashmap::WriteGuard<'_, usize, super::PortState>> {
self.port_states.get_mut(&port).ok_or(Error::new(EBADF))
}
async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> {
let mut req: ConfigureEndpointsReq =
serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?;
@@ -725,6 +726,7 @@ impl Xhci {
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
trb.configure_endpoint(slot, input_context_physical, cycle)
}).await;
self.event_handler_finished();
handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?;
@@ -739,7 +741,7 @@ impl Xhci {
Ok(())
}
fn transfer_read(
async fn transfer_read(
&mut self,
port_num: usize,
endp_idx: u8,
@@ -753,9 +755,9 @@ impl Xhci {
} else {
DeviceReqData::NoData
},
)
).await
}
fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> {
async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> {
self.transfer(
port_num,
endp_idx,
@@ -764,7 +766,7 @@ impl Xhci {
} else {
DeviceReqData::NoData
},
)
).await
}
const fn def_control_endp_doorbell() -> u32 {
1
@@ -791,7 +793,7 @@ impl Xhci {
(u32::from(db_task_id) << 16) | u32::from(db_target)
}
// TODO: Rename DeviceReqData to something more general.
fn transfer(
async fn transfer(
&mut self,
port_num: usize,
endp_idx: u8,
@@ -913,7 +915,8 @@ impl Xhci {
ControlFlow::Break
}
},
)?;
).await?;
self.event_handler_finished();
let bytes_transferred = buf.len() as u32 - event.transfer_length();
@@ -1615,6 +1618,7 @@ impl Xhci {
} else {
1
};
let raw = self
.dev_ctx
.contexts
@@ -1626,6 +1630,7 @@ impl Xhci {
.a
.read()
& super::context::ENDPOINT_CONTEXT_STATUS_MASK;
Ok(match raw {
0 => EndpointStatus::Disabled,
1 => EndpointStatus::Enabled,
@@ -1698,6 +1703,7 @@ impl Xhci {
(true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?)
}
};
let stream_id = 1u16;
let doorbell = Self::endp_doorbell(
endp_num,
endp_desc,
@@ -1712,9 +1718,6 @@ impl Xhci {
self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?;
let stream_id = 1u16;
self.dbs.lock().unwrap()[slot as usize].write(doorbell);
Ok(())
}
@@ -1765,6 +1768,7 @@ impl Xhci {
slot,
)
}).await;
self.event_handler_finished();
handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb)
}
@@ -1802,7 +1806,7 @@ impl Xhci {
// Yield the result directly because no bytes have to be sent or received
// beforehand.
let (completion_code, bytes_transferred) =
self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?;
self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?;
if bytes_transferred > 0 {
return Err(Error::new(EIO));
}
@@ -2005,6 +2009,14 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()
Err(Error::new(EIO))
}
}
fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> {
if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 {
Ok(())
} else {
println!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb);
Err(Error::new(EIO))
}
}
use std::ops::{Add, Div, Rem};
pub fn div_round_up<T>(a: T, b: T) -> T
where