From f3d2d3e2d1a24a67509f6eb6845a19cb21773f5e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 22:38:22 +0100 Subject: [PATCH] Fix the IRQ reactor when doing subsequent cmds. --- xhcid/src/xhci/irq_reactor.rs | 37 +++++++++++++++++++++++------------ xhcid/src/xhci/mod.rs | 5 ++++- xhcid/src/xhci/scheme.rs | 24 ++++++++++++----------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 9371bc33c6..61d7f548a7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -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> { 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; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b67e123832..b81f0b38bf 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -470,6 +470,7 @@ impl Xhci { let mut input = Dma::::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); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c21436677d..c722986af7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -213,17 +213,11 @@ impl Xhci { hid_descs: hid_descs.into_iter().collect(), }) } - pub fn execute_command_noreply(&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( &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); }