Fix the IRQ reactor when doing subsequent cmds.

This commit is contained in:
4lDO2
2020-03-28 22:38:22 +01:00
parent ddf71d48e6
commit f3d2d3e2d1
3 changed files with 41 additions and 25 deletions
+24 -13
View File
@@ -18,6 +18,7 @@ use event::{Event, EventQueue};
use super::Xhci;
use super::ring::Ring;
use super::trb::{Trb, TrbCompletionCode, TrbType};
use super::event::EventRing;
/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back
/// by the future unless it completed).
@@ -127,7 +128,8 @@ impl IrqReactor {
self.handle_requests();
self.acknowledge(trb.clone());
self.update_erdp();
self.update_erdp(&*event_ring_guard);
}
}
fn run_with_irq_file(mut self) {
@@ -137,6 +139,8 @@ impl IrqReactor {
let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue");
let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd();
let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() };
event_queue.add(irq_fd, move |_| -> io::Result<Option<()>> {
println!("IRQ event queue notified");
let mut buffer = [0u8; 8];
@@ -160,34 +164,36 @@ impl IrqReactor {
let mut count = 0;
'trb_loop: loop {
let trb = event_ring.next();
let event_trb = &mut event_ring.ring.trbs[event_trb_index];
if trb.completion_code() == TrbCompletionCode::Invalid as u8 {
if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 {
if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") }
// no more events were found, continue the loop
return Ok(None);
} else { count += 1 }
println!("Found event TRB: {:?}", trb);
println!("Found event TRB: {:?}", event_trb);
if self.check_event_ring_full(trb.clone()) {
if self.check_event_ring_full(event_trb.clone()) {
println!("Had to resize event TRB, retrying...");
hci_clone.event_handler_finished();
return Ok(None);
}
self.handle_requests();
self.acknowledge(trb.clone());
trb.reserved(false);
self.acknowledge(event_trb.clone());
self.update_erdp();
event_trb.reserved(false);
self.update_erdp(&*event_ring);
event_trb_index = event_ring.ring.next_index();
}
}).expect("xhcid: failed to catch irq events");
//event_queue.trigger_all(Event { fd: 0, flags: 0 }).expect("irq reactor failed to trigger events");
event_queue.run().expect("xhcid: failed to run IRQ event queue");
}
fn update_erdp(&self) {
let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp();
fn update_erdp(&self, event_ring: &EventRing) {
let dequeue_pointer_and_dcs = event_ring.erdp();
let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE;
assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring");
@@ -202,7 +208,7 @@ impl IrqReactor {
let mut index = 0;
loop {
if index >= self.states.len() { return }
if index >= self.states.len() { break }
match self.states[index].kind {
StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) {
@@ -210,7 +216,7 @@ impl IrqReactor {
let state = self.states.remove(index);
// Before waking, it's crucial that the command TRB that generated this event
// be fetched before removing this event TRB from the queue.
// is fetched before removing this event TRB from the queue.
let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) {
Some(command_trb) => {
let t = command_trb.clone();
@@ -231,6 +237,8 @@ impl IrqReactor {
println!("Waking up future with waker: {:?}", state.waker);
state.waker.wake();
return;
} else if trb.completion_trb_pointer().is_none() {
println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb);
continue;
@@ -249,6 +257,7 @@ impl IrqReactor {
event_trb: trb.clone(),
});
state.waker.wake();
return;
} else if trb.transfer_event_trb_pointer().is_none() {
// Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full.
//
@@ -272,6 +281,7 @@ impl IrqReactor {
StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => {
let state = self.states.remove(index);
state.waker.wake();
return;
}
_ => {
@@ -280,6 +290,7 @@ impl IrqReactor {
}
}
}
println!("Lost event TRB: {:?}", trb);
}
fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) {
let mut index = 0;
+4 -1
View File
@@ -470,6 +470,7 @@ impl Xhci {
let mut input = Dma::<InputContext>::zeroed()?;
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?;
println!("Addressed device");
// TODO: Should the descriptors be cached in PortState, or refetched?
@@ -538,7 +539,7 @@ impl Xhci {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
}).await;
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb);
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
self.event_handler_finished();
Ok(())
@@ -633,9 +634,11 @@ impl Xhci {
let input_context_physical = input_context.physical();
println!("pre_address_device");
let (event_trb, _) = self.execute_command(|trb, cycle| {
trb.address_device(slot, input_context_physical, false, cycle)
}).await;
println!("post_address_device");
if event_trb.completion_code() != TrbCompletionCode::Success as u8 {
println!("Failed to address device at slot {} (port {})", slot, i);
+13 -11
View File
@@ -213,17 +213,11 @@ impl Xhci {
hid_descs: hid_descs.into_iter().collect(),
})
}
pub fn execute_command_noreply<F: FnOnce(&mut Trb, bool)>(&self, f: F) {
let mut command_ring = self.cmd.lock().unwrap();
let (cmd, cycle) = command_ring.next();
f(cmd, cycle);
self.dbs.lock().unwrap()[0].write(0);
// TODO: It's still possible not to reset the TRB, right?
}
/// Pushes a command TRB to the command ring, rings the doorbell, and then awaits its Command
/// Completion Event.
///
/// # Locking
/// This function will lock `Xhci::cmd` and `Xhci::dbs`.
pub async fn execute_command<F: FnOnce(&mut Trb, bool)>(
&self,
f: F,
@@ -242,7 +236,9 @@ impl Xhci {
self.next_command_completion_event_trb(&*command_ring, command_trb)
};
println!("Ringing doorbell");
self.dbs.lock().unwrap()[0].write(0);
println!("Doorbell rung");
let trbs = next_event.await;
let event_trb = trbs.event_trb;
@@ -1988,7 +1984,13 @@ impl Xhci {
_ => return Err(Error::new(EBADF)),
}
}
/// Notifies the xHC that the current event handler has finished, so that new interrupts can be
/// sent. This is required after each invocation of `Self::execute_command`.
///
/// # Locking
/// This function locks `Xhci::run`.
pub fn event_handler_finished(&self) {
println!("Event handler finished");
// write 1 to EHB to clear it
self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true);
}