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.
This commit is contained in:
4lDO2
2020-03-28 15:52:39 +01:00
parent e58245b280
commit ddf71d48e6
4 changed files with 51 additions and 31 deletions
+29 -22
View File
@@ -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<Trb>,
@@ -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<Option<()>> {
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::<usize>() {
// 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<Output = NextEventTrb> + Send + Sync + 'static {
pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future<Output = NextEventTrb> + 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).
+11 -4
View File
@@ -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::<Vec<_>>());
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<Xhci>, irq_file: Option<File>) {
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()
}));
}
+3 -1
View File
@@ -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::<Trb>() {
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
}
/*
+8 -4
View File
@@ -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)
}