Fix the IRQ reactor when doing subsequent cmds.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user