From ddf71d48e60d881de020dee8be6ef221b834f976 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 15:52:39 +0100 Subject: [PATCH] Get the Enable Slot cmd working, asynchronously! This is the first command that actually worked by calling the IRQ reactor and then getting a response. While this may not be that much on its own, it means the async/await model actually works in this context. Now the major problem is getting rid of all the deadlocks, and later remove block_on(future) in the Scheme impl, and instead go async with future spawning instead. --- xhcid/src/xhci/irq_reactor.rs | 51 ++++++++++++++++++++--------------- xhcid/src/xhci/mod.rs | 15 ++++++++--- xhcid/src/xhci/ring.rs | 4 ++- xhcid/src/xhci/scheme.rs | 12 ++++++--- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 81299046a6..9371bc33c6 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -13,7 +13,7 @@ use crossbeam_channel::{Sender, Receiver}; use futures::Stream; use syscall::Io; -use event::EventQueue; +use event::{Event, EventQueue}; use super::Xhci; use super::ring::Ring; @@ -21,6 +21,7 @@ use super::trb::{Trb, TrbCompletionCode, TrbType}; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). +#[derive(Debug)] pub struct State { waker: task::Waker, kind: StateKind, @@ -28,6 +29,7 @@ pub struct State { is_isoch_or_vf: bool, } +#[derive(Debug)] pub struct NextEventTrb { pub event_trb: Trb, pub src_trb: Option, @@ -103,11 +105,10 @@ impl IrqReactor { std::thread::yield_now(); } fn run_polling(mut self) { + println!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { - self.handle_requests(); - let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); let index = event_ring_guard.ring.next_index(); @@ -124,34 +125,32 @@ impl IrqReactor { } if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + self.handle_requests(); self.acknowledge(trb.clone()); self.update_erdp(); } } fn run_with_irq_file(mut self) { + println!("Running IRQ reactor with IRQ file and event queue"); + let hci_clone = Arc::clone(&self.hci); 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(); event_queue.add(irq_fd, move |_| -> io::Result> { - + println!("IRQ event queue notified"); let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); - - self.handle_requests(); - - if bytes_read < mem::size_of::() { - // continue the loop when the next IRQ arrives - return Ok(None); - } - + let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received + println!("no interrupt pending"); return Ok(None); } + println!("IRQ reactor received an IRQ"); + let _ = self.irq_file.as_mut().unwrap().write(&buffer); // TODO: More event rings, probably even with different IRQs. @@ -169,15 +168,22 @@ impl IrqReactor { return Ok(None); } else { count += 1 } + println!("Found event TRB: {:?}", trb); + if self.check_event_ring_full(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.update_erdp(); } }).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) { @@ -185,17 +191,22 @@ impl IrqReactor { 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"); + println!("Updated ERDP to {:#0x}", dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter()); + self.states.extend(self.receiver.try_iter().inspect(|req| println!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { let mut index = 0; loop { + if index >= self.states.len() { return } + match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { + StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { + println!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event @@ -218,6 +229,7 @@ impl IrqReactor { event_trb: trb.clone(), }); + println!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); } 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); @@ -264,9 +276,6 @@ impl IrqReactor { _ => { index += 1; - if index >= self.states.len() { - break; - } continue; } } @@ -405,13 +414,11 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } - pub fn next_command_completion_event_trb(&self, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } - - let command_ring = self.cmd.lock().unwrap(); - + dbg!(command_ring.trbs.physical()); EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4cd98ae907..b67e123832 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -356,7 +356,7 @@ impl Xhci { println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); @@ -368,7 +368,7 @@ impl Xhci { int.imod.write(0); println!(" - Enable interrupts"); - int.iman.writef(1 << 1, true); + int.iman.writef(1 << 1 | 1, true); } self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); @@ -395,7 +395,7 @@ impl Xhci { println!(" - XHCI initialized"); if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); + self.op.get_mut().unwrap().set_cie(true); } Ok(()) @@ -441,7 +441,9 @@ impl Xhci { pub async fn probe(&self) -> Result<()> { println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); - for i in 0..self.ports.lock().unwrap().len() { + let port_count = { self.ports.lock().unwrap().len() }; + + for i in 0..port_count { let (data, state, speed, flags) = { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) @@ -460,6 +462,8 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); + + println!("Got slot type: {}", slot_ty); let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); @@ -843,7 +847,10 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); + println!("About to start IRQ reactor"); + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + println!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index f6e6ee0696..67cafcf080 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -102,8 +102,10 @@ impl Ring { if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } + let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; + let trbs_base_phys_ptr = self.trbs.physical() as u64; - let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; + let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index f605de6ee4..c21436677d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -230,12 +230,16 @@ impl Xhci { ) -> (Trb, Trb) { let next_event = { let mut command_ring = self.cmd.lock().unwrap(); + let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); - let (cmd, cycle) = command_ring.next(); - f(cmd, cycle); + { + let command_trb = &mut command_ring.trbs[cmd_index]; + f(command_trb, cycle); + } // get the future here before awaiting, to destroy the lock before deadlock - self.next_command_completion_event_trb(&cmd) + let command_trb = &command_ring.trbs[cmd_index]; + self.next_command_completion_event_trb(&*command_ring, command_trb) }; self.dbs.lock().unwrap()[0].write(0); @@ -244,7 +248,7 @@ impl Xhci { let event_trb = trbs.event_trb; let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); - assert_eq!(command_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + assert_eq!(event_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); (event_trb, command_trb) }