From 4dedbac4e550b9794b44ba68e8e79e720ff02526 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Tue, 5 Nov 2024 17:35:57 +0000 Subject: [PATCH] Fixed the deadlock by only addressing devices in response to attach requests.... --- audio/ihdad/src/main.rs | 2 +- inputd/src/main.rs | 4 +- xhcid/src/main.rs | 16 +- xhcid/src/xhci/device_enumerator.rs | 221 +++++++++++++ xhcid/src/xhci/irq_reactor.rs | 151 +++++++-- xhcid/src/xhci/mod.rs | 474 +++++++++++++++++++--------- xhcid/src/xhci/port.rs | 1 + xhcid/src/xhci/scheme.rs | 35 +- xhcid/src/xhci/trb.rs | 25 +- 9 files changed, 733 insertions(+), 196 deletions(-) create mode 100644 xhcid/src/xhci/device_enumerator.rs diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index e79ee9a18f..b467e33699 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -104,7 +104,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "audio", "pcie", "ihda", - log::LevelFilter::Debug, + log::LevelFilter::Info, log::LevelFilter::Info, ); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 870ce8a432..be8ae15f6b 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -432,8 +432,8 @@ pub fn main() { "misc", "inputd", "inputd", - log::LevelFilter::Trace, - log::LevelFilter::Trace, + log::LevelFilter::Info, + log::LevelFilter::Debug, ); let mut args = std::env::args().skip(1); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index dc280e6636..ae876f9643 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -47,6 +47,7 @@ use pcid_interface::{ use common::io::Io; use event::{Event, RawEventQueue}; +use log::info; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; @@ -204,7 +205,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "host", &name, log::LevelFilter::Info, - log::LevelFilter::Debug, + log::LevelFilter::Info, ); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); @@ -214,8 +215,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ptr .as_ptr() as usize; - let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); - // TODO: fix interrutps: get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle, address); + //TODO: Fix interrupts. println!(" + XHCI {}", pci_config.func.display()); @@ -227,17 +228,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("xhcid: failed to notify parent"); - let hci = Arc::new( + let mut hci = Arc::new( Xhci::new(scheme_name, address, interrupt_method, pcid_handle) .expect("xhcid: failed to allocate device"), ); + xhci::start_irq_reactor(&hci, irq_file); - futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); + xhci::start_device_enumerator(&hci); + + hci.poll(); //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); - libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - let todo = Arc::new(Mutex::new(Vec::::new())); //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs new file mode 100644 index 0000000000..9109ee4c56 --- /dev/null +++ b/xhcid/src/xhci/device_enumerator.rs @@ -0,0 +1,221 @@ +use crate::xhci::port::PortFlags; +use crate::xhci::scheme::Handle::Port; +use crate::xhci::Xhci; +use common::io::Io; +use crossbeam_channel; +use crossbeam_channel::RecvError; +use log::{debug, error, info, trace, warn}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use syscall::EAGAIN; + +//enum HubPortState{ +// PoweredOff, +// Disabled, +// Disconnected, +// Reset, +// Enabled, +// Error, +// Polling, +// Compliance, +// Loopback +//} +// +//impl HubPortState{ +// pub fn from_port_flags(flags: PortFlags, protocol_version: (u8, u8)) -> Self{ +// let pp = flags.contains(PortFlags::PORT_PP); +// let ccs = flags.contains(PortFlags::PORT_CCS); +// let ped = flags.contains(PortFlags::PORT_PED); +// let pr = flags.contains(PortFlags::PORT_PR); +// +// match protocol_version { +// (2, _) | (1, _) => { +// match (pp, ccs, ped, pr) { +// (false, false, false, false) => { HubPortState::PoweredOff }, +// (true, false, false, false) => { HubPortState::Disconnected }, +// (true, true, false, true) => { HubPortState::Reset }, +// (true, true, false, false) => { HubPortState::Disabled }, +// (true, true, true, false) => { HubPortState::Enabled }, +// (true, true, true, true) => unreachable!(), //PED shouldnt be set when PR is set +// (false, _, _, _) => unreachable!(), //None of the other bits should be set when the port is off +// _ => unreachable!() //This state shouldn't be valid. +// } +// } +// (3, _) => { +// //TO-DO: USB3 state machine. +// HubPortState::PoweredOff +// }, +// (_, _) => unreachable!() //We don't support protocols > 3 yet. +// } +// } +//} +// +//struct RootHubPortStateMachine{ +// hci: Arc, +// port_num: u8, +// port_index: usize, +// protocol_major_version: u8, +// protocol_minor_version: u8, +// state: HubPortState +//} +// +//impl RootHubPortStateMachine{ +// fn new(port_num: u8, hci: Arc) -> Self{ +// +// let hci = hci.clone(); +// let port_index = (port_num - 1) as usize; +// +// //TODO: Get actual protocol version +// let (maj, min) = (2u8, 0u8); +// +// //TODO: Get actual flags +// let flags = PortFlags::all(); +// +// RootHubPortStateMachine{ +// hci, +// port_num, +// port_index, +// protocol_major_version: maj, +// protocol_minor_version: min, +// state: HubPortState::from_port_flags(flags, (maj, min)) +// } +// } +// +// fn execute(&mut self, port_num: u8){ +// //TO-DO: Implement the state machine. +// } +//} + +pub struct DeviceEnumerationRequest { + pub port_number: u8, +} + +pub struct DeviceEnumerator { + hci: Arc, + request_queue: crossbeam_channel::Receiver, +} + +impl DeviceEnumerator { + pub fn new(hci: Arc) -> Self { + let request_queue = hci.device_enumerator_receiver.clone(); + DeviceEnumerator { hci, request_queue } + } + + pub fn run(&mut self) { + loop { + trace!("Start Device Enumerator Loop"); + let request = match self.request_queue.recv() { + Ok(req) => req, + Err(err) => { + panic!("Failed to received an enumeration request! error: {}", err) + } + }; + + let port_array_index = request.port_number - 1; + + let (len, flags) = { + let ports = self.hci.ports.lock().unwrap(); + + let len = ports.len(); + + if port_array_index as usize >= len { + warn!( + "Received out of bounds Device Enumeration request for port {}", + request.port_number + ); + continue; + } + + (len, ports[port_array_index as usize].flags()) + }; + + if flags.contains(PortFlags::PORT_CCS) { + info!( + "Received Device Connect Port Status Change Event with port flags {:?}", + flags + ); + //If the port isn't enabled (i.e. it's a USB2 port), we need to reset it if it isn't resetting already + //A USB3 port won't generate a Connect Status Change until it's already enabled, so this check + //will always be skipped for USB3 ports + if !flags.contains(PortFlags::PORT_PED) { + let disabled_state = flags.contains(PortFlags::PORT_PP) + && flags.contains(PortFlags::PORT_CCS) + && !flags.contains(PortFlags::PORT_PED) + && !flags.contains(PortFlags::PORT_PR); + + if !disabled_state { + panic!( + "Port {} isn't in the disabled state! Current flags: {:?}", + request.port_number, flags + ); + } else { + debug!( + "Port {} has entered the disabled state.", + request.port_number + ); + } + + //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT + info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", request.port_number); + self.hci.reset_port((port_array_index as usize)); + + let mut ports = self.hci.ports.lock().unwrap(); + let port = &mut ports[port_array_index as usize]; + + port.portsc.writef(PortFlags::PORT_PRC.bits(), true); + + std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition. + + let flags = port.flags(); + + let enabled_state = flags.contains(PortFlags::PORT_PP) + && flags.contains(PortFlags::PORT_CCS) + && flags.contains(PortFlags::PORT_PED) + && !flags.contains(PortFlags::PORT_PR); + + if !enabled_state { + warn!( + "Port {} isn't in the enabled state! Current flags: {:?}", + request.port_number, flags + ); + } else { + debug!( + "Port {} is in the enabled state. Proceeding with enumeration", + request.port_number + ); + } + } + + let result = futures::executor::block_on(self.hci.attach_device(port_array_index)); + match result { + Ok(_) => { + info!("Device on port {} was attached", port_array_index); + } + Err(err) => { + if err.errno == EAGAIN { + info!("Received a device connect notification for an already connected device. Ignoring...") + } else { + warn!("processing of device attach request failed! Error: {}", err); + } + } + } + } else { + info!( + "Device Enumerator received Detach request on port {} which is in state {}", + request.port_number, + self.hci.get_pls((port_array_index) as usize) + ); + let result = + futures::executor::block_on(self.hci.detach_device(port_array_index as usize)); + match result { + Ok(_) => { + info!("Device on port {} was detached", port_array_index); + } + Err(err) => { + warn!("processing of device attach request failed! Error: {}", err); + } + } + } + } + } +} diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a42728d4cc..6a1bd86908 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,24 +1,28 @@ +use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; +use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Mutex}; -use std::task; +use std::{io, mem, task, thread}; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Receiver, Sender}; +use futures::Stream; use log::{debug, error, info, trace, warn}; -use event::RawEventQueue; - use super::doorbell::Doorbell; use super::event::EventRing; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::Xhci; - +use super::{port, Xhci}; +use crate::xhci::device_enumerator::DeviceEnumerationRequest; +use crate::xhci::port::PortFlags; +use crate::xhci::scheme::AnyDescriptor::Device; use common::io::Io as _; +use event::{Event, EventQueue, RawEventQueue}; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). @@ -87,8 +91,8 @@ impl StateKind { pub struct IrqReactor { hci: Arc, irq_file: Option, - receiver: Receiver, - + irq_receiver: Receiver, + device_enumerator_sender: Sender, states: Vec, // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps // the event ring should be owned here? @@ -97,11 +101,15 @@ pub struct IrqReactor { pub type NewPendingTrb = State; impl IrqReactor { - pub fn new(hci: Arc, receiver: Receiver, irq_file: Option) -> Self { + pub fn new(hci: Arc, irq_file: Option) -> Self { + let device_enumerator_sender = hci.device_enumerator_sender.clone(); + let irq_receiver = hci.irq_reactor_receiver.clone(); + Self { hci, irq_file, - receiver, + irq_receiver, + device_enumerator_sender, states: Vec::new(), } } @@ -133,24 +141,65 @@ impl IrqReactor { continue 'trb_loop; } - trace!("Found event TRB: {:?}", event_trb); + trace!( + "Found event TRB at index {} with type {} and cycle bit {}: {:?}", + event_trb_index, + event_trb.trb_type(), + event_trb.cycle() as u8, + event_trb + ); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); - hci_clone.event_handler_finished(); continue 'trb_loop; } + trace!("Handling requests"); self.handle_requests(); - self.acknowledge(event_trb.clone()); + trace!("Requests handled"); + + match event_trb.trb_type() { + _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { + trace!("Received a port status change!"); + self.handle_port_status_change(event_trb.clone()) + } //TODO Handle the other unprompted events + _ => { + self.acknowledge(event_trb.clone()); + } + } event_trb.reserved(false); self.update_erdp(&*event_ring); + hci_clone.event_handler_finished(); event_trb_index = event_ring.ring.next_index(); } } + + fn mask_interrupts(&mut self) { + let mut run = self.hci.run.lock().unwrap(); + + debug!("Masking interrupts!"); + + if !run.ints[0].iman.readf(1 << 1) { + warn!("Attempted to mask interrupts when they were already disabled!") + } + + run.ints[0].iman.writef(1 << 1, false); + } + + fn unmask_interrupts(&mut self) { + let mut run = self.hci.run.lock().unwrap(); + + debug!("unmasking interrupts!"); + if run.ints[0].iman.readf(1 << 1) { + warn!("Attempted to unmask interrupts when they were already enabled!") + } + + run.ints[0].iman.writef(1 << 1, true); + } + fn run_with_irq_file(mut self) { debug!("Running IRQ reactor with IRQ file and event queue"); @@ -162,6 +211,7 @@ impl IrqReactor { .subscribe(irq_fd as usize, 0, event::EventFlags::READ) .unwrap(); + trace!("IRQ Reactor has created its event queue."); let mut event_trb_index = { hci_clone .primary_event_ring @@ -171,6 +221,7 @@ impl IrqReactor { .next_index() }; + trace!("IRQ reactor has grabbed the next index in the event ring."); for _event in event_queue { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -188,6 +239,8 @@ impl IrqReactor { break; } + self.mask_interrupts(); + trace!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -199,41 +252,92 @@ impl IrqReactor { let mut count = 0; loop { + trace!("count: {}", count); let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } - // no more events were found, continue the loop + //hci_clone.event_handler_finished(); + self.unmask_interrupts(); return; } else { count += 1 } - trace!( - "Found event TRB type {}: {:?}", + info!( + "Found event TRB at index {} with type {} and cycle bit {}: {:?}", + event_trb_index, event_trb.trb_type(), + event_trb.cycle() as u8, event_trb ); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); - hci_clone.event_handler_finished(); + //hci_clone.event_handler_finished(); + if self.hci.interrupt_is_pending(0) { + warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") + } else { + debug!("The interrupt bit is no longer pending."); + } + self.unmask_interrupts(); return; } - self.handle_requests(); - self.acknowledge(event_trb.clone()); + + match event_trb.trb_type() { + _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { + trace!("Received a port status change!"); + self.handle_port_status_change(event_trb.clone()) + } //TODO Handle the other unprompted events + _ => { + trace!("Received a non-status trb"); + self.acknowledge(event_trb.clone()); + } + } event_trb.reserved(false); self.update_erdp(&*event_ring); + self.hci.event_handler_finished(); event_trb_index = event_ring.ring.next_index(); } + trace!("Exited event loop!"); + } + trace!("IRQ Reactor has finished handling the interrupt"); + } + + /// Handles device attach/detach events as indicated by a PortStatusChange + fn handle_port_status_change(&mut self, trb: Trb) { + if let Some(port_num) = trb.port_status_change_port_id() { + trace!("Received Port Status Change Request on port {}", port_num); + self.device_enumerator_sender + .send(DeviceEnumerationRequest { + port_number: port_num, + }) + .expect( + format!( + "Failed to transmit device numeration request on port {}", + port_num + ) + .as_str(), + ); + { + let mut ports = self.hci.ports.lock().unwrap(); + let port = &mut ports[(port_num - 1) as usize]; + port.portsc.writef(PortFlags::PORT_CSC.bits(), true); + } + } else { + warn!( + "Received a TRB of type {}, which was unexpected", + trb.trb_type() + ) } } + 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; @@ -254,7 +358,7 @@ impl IrqReactor { } fn handle_requests(&mut self) { self.states.extend( - self.receiver + self.irq_receiver .try_iter() .inspect(|req| trace!("Received request: {:X?}", req)), ); @@ -448,6 +552,7 @@ impl EventDoorbell { pub fn ring(self) { trace!("Ring doorbell {} with data {}", self.index, self.data); self.dbs.lock().unwrap()[self.index].write(self.data); + trace!("Doorbell was rung."); } } @@ -465,7 +570,7 @@ impl Future for EventTrbFuture { fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { let this = self.get_mut(); - + trace!("Start poll!"); let message = match this { &mut Self::Pending { ref state, @@ -490,12 +595,12 @@ impl Future for EventTrbFuture { if let Some(doorbell) = doorbell_opt.take() { doorbell.ring(); } - return task::Poll::Pending; } }, &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), }; + trace!("finished!"); *this = Self::Finished; task::Poll::Ready(message) } @@ -571,6 +676,10 @@ impl Xhci { trb: &Trb, doorbell: EventDoorbell, ) -> impl Future + Send + Sync + 'static { + trace!( + "Sending command at phys_ptr {:X}", + command_ring.trb_phys_ptr(self.cap.ac64(), trb) + ); if !trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 04e2f1717d..2cc2dcf0ba 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -18,15 +18,15 @@ use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::time::Duration; use std::{mem, process, slice, sync::atomic, task, thread}; - -use common::io::Io; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; -use syscall::PAGE_SIZE; +use syscall::{EAGAIN, PAGE_SIZE}; use chashmap::CHashMap; -use common::dma::Dma; +use common::{dma::Dma, io::Io}; use crossbeam_channel::{Receiver, Sender}; +use futures::AsyncReadExt; use log::{debug, error, info, trace, warn}; use serde::Deserialize; @@ -37,6 +37,7 @@ use pcid_interface::{PciFeature, PciFunctionHandle}; mod capability; mod context; +mod device_enumerator; mod doorbell; mod event; mod extended; @@ -104,6 +105,10 @@ impl Xhci { index: u8, desc: &mut Dma, ) -> Result<()> { + if self.interrupt_is_pending(0) { + warn!("EHB is already set!"); + self.force_clear_interrupt(0); + } let len = mem::size_of::(); log::debug!( "get_desc_raw port {} slot {} kind {:?} index {} len {}", @@ -154,13 +159,14 @@ impl Xhci { ) }; + debug!("Waiting for the next transfer event TRB..."); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); - + trace!("Handling the transfer event TRB!"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -265,8 +271,7 @@ pub struct Xhci { handles: CHashMap, next_handle: AtomicUsize, port_states: CHashMap, - - drivers: CHashMap, + drivers: CHashMap>, scheme_name: String, interrupt_method: InterruptMethod, @@ -279,6 +284,9 @@ pub struct Xhci { // not used, but still stored so that the thread, when created, can get the channel without the // channel being in a mutex. irq_reactor_receiver: Receiver, + device_enumerator: Mutex>>, + device_enumerator_sender: Sender, + device_enumerator_receiver: Receiver, } unsafe impl Send for Xhci {} @@ -401,6 +409,8 @@ impl Xhci { let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); + let (device_enumerator_sender, device_enumerator_receiver) = crossbeam_channel::unbounded(); + let mut xhci = Self { base: address as *const u8, @@ -419,7 +429,6 @@ impl Xhci { handles: CHashMap::new(), next_handle: AtomicUsize::new(0), port_states: CHashMap::new(), - drivers: CHashMap::new(), scheme_name, @@ -429,6 +438,9 @@ impl Xhci { irq_reactor: Mutex::new(None), irq_reactor_sender, irq_reactor_receiver, + device_enumerator: Mutex::new(None), + device_enumerator_sender, + device_enumerator_receiver, }; xhci.init(max_slots)?; @@ -528,28 +540,109 @@ impl Xhci { self.op.get_mut().unwrap().set_cie(self.cap.cic()); - // Reset ports - { - let mut ports = self.ports.lock().unwrap(); - for (i, port) in ports.iter_mut().enumerate() { - //TODO: only reset if USB 2.0? - debug!("XHCI Port {} reset", i); + self.print_port_capabilities(); - let instant = std::time::Instant::now(); + Ok(()) + } - port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); - while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { - //while ! port.flags().contains(port::PortFlags::PORT_PRC) { - if instant.elapsed().as_secs() >= 1 { - warn!("timeout"); - break; - } - std::thread::yield_now(); + pub fn get_pls(&self, port_num: usize) -> u32 { + let mut ports = self.ports.lock().unwrap(); + let port = ports.get_mut(port_num).unwrap(); + let state = port.portsc.read(); + (state >> 5) & 4 + } + + pub fn poll(&self) { + debug!("Polling Initial Devices!"); + + let len = self.ports.lock().unwrap().len(); + + for index in 0..len { + //Get the CCS and CSC flags + let (ccs, csc, flags) = { + let mut ports = self.ports.lock().unwrap(); + let port = &mut ports[index]; + let ccs = port.portsc.readf(PortFlags::PORT_CCS.bits()); + let csc = port.portsc.readf(PortFlags::PORT_CSC.bits()); + + (ccs, csc, port.flags()) + }; + + debug!("Port {} has flags {:?}", index + 1, flags); + + match (ccs, csc) { + (false, false) => { // Nothing is connected, and there was no port status change + //Do nothing + } + _ => { + //Either something is connected, or nothing is connected and a port status change was asserted. + self.device_enumerator_sender + .send(DeviceEnumerationRequest { + port_number: (index + 1) as u8, + }) + .expect("Failed to generate the port enumeration request!"); } } } + } - Ok(()) + pub fn print_port_capabilities(&self) { + let len; + { + let mut ports = self.ports.lock().unwrap(); + len = ports.len(); + } + + for port in 0..len { + let state = self.get_pls(port); + let mut flags; + { + let mut ports = self.ports.lock().unwrap(); + + flags = ports[port].flags(); + } + + match self.supported_protocol(port as u8) { + None => { + warn!("No detected supported protocol for port {}", port); + } + Some(protocol) => { + info!( + "Port {} is a USB {}.{} port with slot type {} and in current state {}: {:?}", + port + 1, + protocol.rev_major(), + protocol.rev_minor(), + protocol.proto_slot_ty(), + state, + flags + ); + } + }; + } + } + pub fn reset_port(&self, port_num: usize) { + debug!("XHCI Port {} reset", port_num); + + //TODO handle the second unwrap + let mut ports = self.ports.lock().unwrap(); + let port = ports.get_mut(port_num).unwrap(); + let instant = std::time::Instant::now(); + + let state = port.portsc.read(); + let pls = (state >> 5) & 4; + + debug!("Port Link State: {}", pls); + + port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); + debug!("Flags after setting port reset: {:?}", port.flags()); + while !port.portsc.readf(port::PortFlags::PORT_PRC.bits()) { + debug!("Ran at least once!"); + if instant.elapsed().as_secs() >= 1 { + warn!("timeout"); + break; + } + //std::thread::yield_now(); + } } pub fn setup_scratchpads(&mut self) -> Result<()> { @@ -570,6 +663,27 @@ impl Xhci { Ok(()) } + pub fn force_clear_interrupt(&self, index: usize) { + { + // If ERDP EHB bit is set, clear it before sending command + //TODO: find out why this bit is set earlier! + let mut run = self.run.lock().unwrap(); + let mut int = &mut run.ints[index]; + + if int.erdp_low.readf(1 << 3) { + int.erdp_low.writef(1 << 3, true); + } else { + warn!("Attempted to clear the interrupt bit when no interrupt was pending"); + } + } + } + + pub fn interrupt_is_pending(&self, index: usize) -> bool { + let mut run = self.run.lock().unwrap(); + let mut int = &mut run.ints[index]; + int.erdp_low.readf(1 << 3) + } + pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); @@ -577,8 +691,9 @@ impl Xhci { .execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)) .await; + trace!("Slot is enabled!"); self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(event_trb.event_slot()) } @@ -588,7 +703,7 @@ impl Xhci { .await; self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -611,121 +726,171 @@ impl Xhci { Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) } - pub async fn probe(&self) -> Result<()> { - debug!( - "XHCI capabilities: {:?}", - self.capabilities_iter().collect::>() + pub async fn attach_device(&self, port_number: u8) -> syscall::Result<()> { + let i = port_number as usize; + + if self.port_states.contains_key(&i) { + return Err(syscall::Error::new(EAGAIN)); + } + + let (data, state, speed, flags) = { + let port = &self.ports.lock().unwrap()[i]; + (port.read(), port.state(), port.speed(), port.flags()) + }; + + info!( + "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", + i, data, state, speed, flags ); - 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()) + if flags.contains(port::PortFlags::PORT_CCS) { + let slot_ty = match self.supported_protocol(i as u8) { + Some(protocol) => protocol.proto_slot_ty(), + None => { + warn!("Failed to find supported protocol information for port"); + 0 + } }; - info!( - "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", - i, data, state, speed, flags - ); - if flags.contains(port::PortFlags::PORT_CCS) { - let slot_ty = match self.supported_protocol(i as u8) { - Some(protocol) => protocol.proto_slot_ty(), - None => { - warn!("Failed to find supported protocol information for port"); - 0 - } - }; - - debug!("Slot type: {}", slot_ty); - debug!("Enabling slot."); - let slot = match self.enable_port_slot(slot_ty).await { - Ok(ok) => ok, - Err(err) => { - error!("Failed to enable slot for port {}: {}", i, err); - continue; - } - }; - - info!("Enabled port {}, which the xHC mapped to {}", i, slot); - - let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut ring = match self - .address_device(&mut input, i, slot_ty, slot, speed) - .await - { - Ok(ok) => ok, - Err(err) => { - error!("Failed to address device for port {}: {}", i, err); - continue; - } - }; - debug!("Addressed device"); - - // TODO: Should the descriptors be cached in PortState, or refetched? - - let mut port_state = PortState { - slot, - input_context: Mutex::new(input), - dev_desc: None, - cfg_idx: None, - endpoint_states: std::iter::once(( - 0, - EndpointState { - transfer: RingOrStreams::Ring(ring), - driver_if_state: EndpIfState::Init, - }, - )) - .collect::>(), - }; - self.port_states.insert(i, port_state); - - // Ensure correct packet size is used - let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; - { - let mut port_state = self.port_states.get_mut(&i).unwrap(); - - let mut input = port_state.input_context.lock().unwrap(); - - self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) - .await?; + debug!("Slot type: {}", slot_ty); + debug!("Enabling slot."); + let slot = match self.enable_port_slot(slot_ty).await { + Ok(ok) => ok, + Err(err) => { + error!("Failed to enable slot for port {}: {}", i, err); + return Err(err); } + }; - let dev_desc = self.get_desc(i, slot).await?; - self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); + info!("Enabled port {}, which the xHC mapped to {}", i, slot); - { - let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut input = port_state.input_context.lock().unwrap(); - let dev_desc = port_state.dev_desc.as_ref().unwrap(); - - self.update_default_control_pipe(&mut *input, slot, dev_desc) - .await?; + info!("Attempting to address the device"); + let mut ring = match self + .address_device(&mut input, i, slot_ty, slot, speed) + .await + { + Ok(device_ring) => device_ring, + Err(err) => { + error!("Failed to spawn driver for port {}: `{}`", i, err); + return Err(err); } + }; - match self.spawn_drivers(i) { - Ok(()) => (), - Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err), + debug!("Addressed device"); + + // TODO: Should the descriptors be cached in PortState, or refetched? + + let mut port_state = PortState { + slot, + input_context: Mutex::new(input), + dev_desc: None, + cfg_idx: None, + endpoint_states: std::iter::once(( + 0, + EndpointState { + transfer: RingOrStreams::Ring(ring), + driver_if_state: EndpIfState::Init, + }, + )) + .collect::>(), + }; + self.port_states.insert(i, port_state); + debug!("Got port states!"); + + // Ensure correct packet size is used + let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + + self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) + .await?; + } + + debug!("Got the 8 byte dev descriptor"); + + let dev_desc = self.get_desc(i, slot).await?; + debug!("Got the full device descriptor!"); + self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); + + debug!("Got the port states again!"); + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + debug!("Got the input context!"); + let dev_desc = port_state.dev_desc.as_ref().unwrap(); + + self.update_default_control_pipe(&mut *input, slot, dev_desc) + .await?; + } + + debug!("Updated the default control pipe"); + + match self.spawn_drivers(i) { + Ok(()) => (), + Err(err) => { + error!("Failed to spawn driver for port {}: `{}`", i, err) } } + } else { + warn!("Attempted to attach a device that didnt have CCS=1"); } Ok(()) } + pub async fn detach_device(&self, port_number: usize) -> Result<()> { + let port_state = self.port_states.get(&port_number); + let mut driver_process = self.drivers.get(&port_number); + + if let Some(state) = port_state { + let result = self.disable_port_slot(state.slot).await; + self.port_states.remove(&port_number); + + //TODO handle killing the child process properly. I'm not sure how + //to get a mutable reference that I can kill. + + if let Some(mutex) = driver_process { + let mut child = mutex.lock().unwrap(); + + match child.kill() { + Ok(_) => { + info!("Killing {:?}", child) + } + Err(_) => { + warn!("Failed to kill the child process!"); + } + } + } + + self.drivers.remove(&port_number); + + result + } else { + warn!( + "Attempted to detach from port {}, which wasn't previously attached.", + port_number + ); + Ok(()) + } + } + pub async fn update_max_packet_size( &self, input_context: &mut Dma, slot_id: u8, dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { - let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { - u32::from(dev_desc.packet_size) - } else { - 1u32 << dev_desc.packet_size - }; + let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_usb_vers() == 2 { + //u32::from(dev_desc.packet_size) + //} else { + // info!("USB 2 device detected. Packet size is: {}", dev_desc.packet_size); + // 1u32 << dev_desc.packet_size + //}; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; @@ -739,7 +904,7 @@ impl Xhci { .await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -750,14 +915,15 @@ impl Xhci { slot_id: u8, dev_desc: &DevDesc, ) -> Result<()> { + debug!("Updating default control pipe!"); input_context.add_context.write(1 << 1); input_context.drop_context.write(0); - let new_max_packet_size = if dev_desc.major_version() == 2 { - u32::from(dev_desc.packet_size) - } else { - 1u32 << dev_desc.packet_size - }; + let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_version() == 2 { + // u32::from(dev_desc.packet_size) + //} else { + // 1u32 << dev_desc.packet_size + //}; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; @@ -769,9 +935,10 @@ impl Xhci { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }) .await; + debug!("Completed the command to update the default control pipe"); self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -878,10 +1045,10 @@ impl Xhci { i, event_trb.completion_code() ); - self.event_handler_finished(); + //self.event_handler_finished(); return Err(Error::new(EIO)); } - self.event_handler_finished(); + //self.event_handler_finished(); Ok(ring) } @@ -952,6 +1119,7 @@ impl Xhci { // suitable here. let ps = self.port_states.get(&port).unwrap(); + trace!("Spawning driver on port: {}", port + 1); //TODO: support choosing config? let config_desc = &ps @@ -968,6 +1136,7 @@ impl Xhci { Error::new(EBADF) })?; + trace!("Got config and device descriptors on port {}", port + 1); let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; for ifdesc in config_desc.interface_descs.iter() { @@ -986,20 +1155,22 @@ impl Xhci { } else { "/usr/lib/drivers/".to_owned() + command }; - let process = process::Command::new(command) - .args( - args.into_iter() - .map(|arg| { - arg.replace("$SCHEME", &self.scheme_name) - .replace("$PORT", &format!("{}", port)) - .replace("$IF_NUM", &format!("{}", ifdesc.number)) - .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) - }) - .collect::>(), - ) - .stdin(process::Stdio::null()) - .spawn() - .or(Err(Error::new(ENOENT)))?; + let process = Mutex::new( + process::Command::new(command) + .args( + args.into_iter() + .map(|arg| { + arg.replace("$SCHEME", &self.scheme_name) + .replace("$PORT", &format!("{}", port)) + .replace("$IF_NUM", &format!("{}", ifdesc.number)) + .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) + }) + .collect::>(), + ) + .stdin(process::Stdio::null()) + .spawn() + .or(Err(Error::new(ENOENT)))?, + ); self.drivers.insert(port, process); } else { warn!( @@ -1030,7 +1201,8 @@ impl Xhci { } pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> { self.supported_protocols_iter() - .find(|supp_proto| supp_proto.compat_port_range().contains(&port)) + .find(|supp_proto| supp_proto.compat_port_range().contains(&(port + 1))) + //Increment by 1, because USB ports index themselves by 1. } pub fn supported_protocol_speeds( &self, @@ -1123,14 +1295,24 @@ impl Xhci { } } pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { - let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); debug!("About to start IRQ reactor"); *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { debug!("Started IRQ reactor thread"); - IrqReactor::new(hci_clone, receiver, irq_file).run() + IrqReactor::new(hci_clone, irq_file).run() + })); +} + +pub fn start_device_enumerator(hci: &Arc) { + let hci_clone = Arc::clone(&hci); + + debug!("About to start Device Enumerator"); + + *hci.device_enumerator.lock().unwrap() = Some(thread::spawn(move || { + debug!("Started Device Enumerator"); + DeviceEnumerator::new(hci_clone).run(); })); } @@ -1151,6 +1333,8 @@ struct DriversConfig { drivers: Vec, } +use crate::xhci::device_enumerator::{DeviceEnumerationRequest, DeviceEnumerator}; +use crate::xhci::port::PortFlags; use lazy_static::lazy_static; lazy_static! { diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index d1b4e37187..64840c438a 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -6,6 +6,7 @@ bitflags! { const PORT_PED = 1 << 1; const PORT_OCA = 1 << 3; const PORT_PR = 1 << 4; + const PORT_PLS = 1 << 5; const PORT_PP = 1 << 9; const PORT_PIC_AMB = 1 << 14; const PORT_PIC_GRN = 1 << 15; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4637672bc3..a2f780dce7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -555,20 +555,18 @@ impl Xhci { /// # Locking /// This function will lock `Xhci::cmd` and `Xhci::dbs`. pub async fn execute_command(&self, f: F) -> (Trb, Trb) { - { - // If ERDP EHB bit is set, clear it before sending command - //TODO: find out why this bit is set earlier! - let mut run = self.run.lock().unwrap(); - let mut int = &mut run.ints[0]; - if int.erdp_low.readf(1 << 3) { - int.erdp_low.writef(1 << 3, true); - } + //TODO: find out why this bit is set earlier! + if self.interrupt_is_pending(0) { + warn!("The EHB bit is already set!"); + //self.force_clear_interrupt(0); } let next_event = { let mut command_ring = self.cmd.lock().unwrap(); let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); + info!("Sending command with cycle bit {}", cycle as u8); + { let command_trb = &mut command_ring.trbs[cmd_index]; f(command_trb, cycle); @@ -657,7 +655,7 @@ impl Xhci { handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(event_trb) } @@ -824,7 +822,7 @@ impl Xhci { trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } @@ -913,7 +911,11 @@ impl Xhci { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } - async fn configure_endpoints_once(&self, port: usize, req: &ConfigureEndpointsReq) -> Result<()> { + async fn configure_endpoints_once( + &self, + port: usize, + req: &ConfigureEndpointsReq, + ) -> Result<()> { let (endp_desc_count, new_context_entries, configuration_value) = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; @@ -1148,7 +1150,7 @@ impl Xhci { }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; } @@ -1177,7 +1179,7 @@ impl Xhci { port_state.cfg_idx == Some(req.config_desc) }; - if ! already_configured { + if !already_configured { self.configure_endpoints_once(port, &req).await?; } @@ -1381,7 +1383,7 @@ impl Xhci { }, ) .await?; - self.event_handler_finished(); + //self.event_handler_finished(); let bytes_transferred = dma_buf .as_ref() @@ -1443,6 +1445,7 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { + debug!("Fetching the config descriptor at index {}", index); let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; log::debug!( "port {} slot {} config {} desc {:X?}", @@ -2198,7 +2201,7 @@ impl Scheme for Xhci { EndpointHandleTy::Data => { block_on(self.on_write_endp_data(port_num, endp_num, buf)) } - EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)), + EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -2395,7 +2398,7 @@ impl Xhci { ) }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 0705468d14..5d175ddbfa 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,8 +1,9 @@ -use crate::usb; -use common::io::{Io, Mmio}; -use std::{fmt, mem}; - use super::context::StreamContextType; +use crate::usb; +use crate::xhci::trb::TrbType::PortStatusChange; +use common::io::{Io, Mmio}; +use log::trace; +use std::{fmt, mem}; #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -196,6 +197,17 @@ impl Trb { } } + pub fn port_status_change_port_id(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::PortStatusChange as u8); + + if self.has_completion_trb_pointer() { + let data = self.read_data(); + Some(((data >> 24) & 0xFF) as u8) + } else { + None + } + } + pub fn event_slot(&self) -> u8 { (self.control.read() >> 24) as u8 } @@ -234,6 +246,7 @@ impl Trb { } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { + trace!("Enabling slot with type {}", slot_type); self.set( 0, 0, @@ -381,6 +394,10 @@ impl Trb { ); } + pub fn cycle(&self) -> bool { + self.control.readf(0x01) + } + pub fn status( &mut self, interrupter: u16,