Fixed the deadlock by only addressing devices in response to attach requests....

This commit is contained in:
Timothy Finnegan
2024-11-05 17:35:57 +00:00
committed by Jeremy Soller
parent 3f33cb96e7
commit 4dedbac4e5
9 changed files with 733 additions and 196 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
"audio",
"pcie",
"ihda",
log::LevelFilter::Debug,
log::LevelFilter::Info,
log::LevelFilter::Info,
);
+2 -2
View File
@@ -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);
+9 -7
View File
@@ -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::<Packet>::new()));
//let todo_futures = Arc::new(Mutex::new(Vec::<Pin<Box<dyn Future<Output = usize> + Send + Sync + 'static>>>::new()));
+221
View File
@@ -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<Xhci>,
// 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<Xhci>) -> 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<Xhci>,
request_queue: crossbeam_channel::Receiver<DeviceEnumerationRequest>,
}
impl DeviceEnumerator {
pub fn new(hci: Arc<Xhci>) -> 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);
}
}
}
}
}
}
+130 -21
View File
@@ -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<Xhci>,
irq_file: Option<File>,
receiver: Receiver<NewPendingTrb>,
irq_receiver: Receiver<NewPendingTrb>,
device_enumerator_sender: Sender<DeviceEnumerationRequest>,
states: Vec<State>,
// 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<Xhci>, receiver: Receiver<NewPendingTrb>, irq_file: Option<File>) -> Self {
pub fn new(hci: Arc<Xhci>, irq_file: Option<File>) -> 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<Self::Output> {
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<Output = NextEventTrb> + 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)
}
+329 -145
View File
@@ -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<T>,
) -> Result<()> {
if self.interrupt_is_pending(0) {
warn!("EHB is already set!");
self.force_clear_interrupt(0);
}
let len = mem::size_of::<T>();
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<usize, scheme::Handle>,
next_handle: AtomicUsize,
port_states: CHashMap<usize, PortState>,
drivers: CHashMap<usize, process::Child>,
drivers: CHashMap<usize, Mutex<process::Child>>,
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<NewPendingTrb>,
device_enumerator: Mutex<Option<thread::JoinHandle<()>>>,
device_enumerator_sender: Sender<DeviceEnumerationRequest>,
device_enumerator_receiver: Receiver<DeviceEnumerationRequest>,
}
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<u8> {
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::<Vec<_>>()
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::<InputContext>()? };
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::<BTreeMap<_, _>>(),
};
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::<InputContext>()? };
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::<BTreeMap<_, _>>(),
};
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<InputContext>,
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::<Vec<_>>(),
)
.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::<Vec<_>>(),
)
.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<Xhci>, irq_file: Option<File>) {
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<Xhci>) {
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<DriverConfig>,
}
use crate::xhci::device_enumerator::{DeviceEnumerationRequest, DeviceEnumerator};
use crate::xhci::port::PortFlags;
use lazy_static::lazy_static;
lazy_static! {
+1
View File
@@ -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;
+19 -16
View File
@@ -555,20 +555,18 @@ impl Xhci {
/// # Locking
/// This function will lock `Xhci::cmd` and `Xhci::dbs`.
pub async fn execute_command<F: FnOnce(&mut Trb, bool)>(&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)
}
+21 -4
View File
@@ -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<u8> {
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,