xhcid: add more timeouts

This commit is contained in:
Jeremy Soller
2025-11-26 17:45:46 -07:00
parent 8ca163d575
commit 4d6581d454
2 changed files with 68 additions and 39 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ impl<const N: usize> DeviceEnumerator<N> {
//THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT //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.", port_id); info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id);
self.hci.reset_port(port_id); let _ = self.hci.reset_port(port_id);
let mut ports = self.hci.ports.lock().unwrap(); let mut ports = self.hci.ports.lock().unwrap();
let port = &mut ports[port_array_index]; let port = &mut ports[port_array_index];
+67 -38
View File
@@ -20,7 +20,7 @@ use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT};
use syscall::{EAGAIN, PAGE_SIZE}; use syscall::{EAGAIN, PAGE_SIZE};
use chashmap::CHashMap; use chashmap::CHashMap;
use common::{dma::Dma, io::Io}; use common::{dma::Dma, io::Io, timeout::Timeout};
use crossbeam_channel::{Receiver, Sender}; use crossbeam_channel::{Receiver, Sender};
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use serde::Deserialize; use serde::Deserialize;
@@ -374,26 +374,42 @@ impl<const N: usize> Xhci<N> {
//Reset the XHCI device //Reset the XHCI device
let (max_slots, max_ports) = { let (max_slots, max_ports) = {
debug!("Waiting for xHC becoming ready."); {
// Wait until controller is ready debug!("Waiting for xHC becoming ready.");
while op.usb_sts.readf(USB_STS_CNR) { let timeout = Timeout::from_secs(1);
trace!("Waiting for the xHC to be ready."); while op.usb_sts.readf(USB_STS_CNR) {
timeout.run().map_err(|()| {
log::error!("timeout on USB_STS_CNR");
Error::new(EIO)
})?;
}
} }
debug!("Stopping the xHC"); debug!("Stopping the xHC");
// Set run/stop to 0 // Set run/stop to 0
op.usb_cmd.writef(USB_CMD_RS, false); op.usb_cmd.writef(USB_CMD_RS, false);
debug!("Waiting for the xHC to stop."); {
// Wait until controller not running debug!("Waiting for the xHC to stop.");
while !op.usb_sts.readf(USB_STS_HCH) { let timeout = Timeout::from_secs(1);
trace!("Waiting for the xHC to stop."); while !op.usb_sts.readf(USB_STS_HCH) {
timeout.run().map_err(|()| {
log::error!("timeout on USB_STS_HCH");
Error::new(EIO)
})?;
}
} }
debug!("Resetting the xHC."); {
op.usb_cmd.writef(USB_CMD_HCRST, true); debug!("Resetting the xHC.");
while op.usb_cmd.readf(USB_CMD_HCRST) { op.usb_cmd.writef(USB_CMD_HCRST, true);
trace!("Waiting for the xHC to reset."); let timeout = Timeout::from_secs(1);
while op.usb_cmd.readf(USB_CMD_HCRST) {
timeout.run().map_err(|()| {
log::error!("timeout on USB_CMD_HCRST");
Error::new(EIO)
})?;
}
} }
debug!("Reading max slots."); debug!("Reading max slots.");
@@ -472,14 +488,20 @@ impl<const N: usize> Xhci<N> {
self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false);
// Warm reset // Warm reset
debug!("Reset xHC"); {
self.op debug!("Reset xHC");
.get_mut() let timeout = Timeout::from_secs(1);
.unwrap() self.op
.usb_cmd .get_mut()
.writef(USB_CMD_HCRST, true); .unwrap()
while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { .usb_cmd
thread::yield_now(); .writef(USB_CMD_HCRST, true);
while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) {
timeout.run().map_err(|()| {
log::error!("timeout on USB_CMD_HCRST");
Error::new(EIO)
})?;
}
} }
// Set enabled slots // Set enabled slots
@@ -552,10 +574,15 @@ impl<const N: usize> Xhci<N> {
debug!("Starting xHC."); debug!("Starting xHC.");
self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true);
// Wait until controller is running {
debug!("Waiting for start request to complete."); debug!("Waiting for start request to complete.");
while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) { let timeout = Timeout::from_secs(1);
trace!("Waiting for XHCI to report running status."); while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) {
timeout.run().map_err(|()| {
log::error!("timeout on USB_STS_HCH");
Error::new(EIO)
})?;
}
} }
// Ring command doorbell // Ring command doorbell
@@ -654,7 +681,7 @@ impl<const N: usize> Xhci<N> {
}; };
} }
} }
pub fn reset_port(&self, port_id: PortId) { pub fn reset_port(&self, port_id: PortId) -> Result<()> {
debug!("XHCI Port {} reset", port_id); debug!("XHCI Port {} reset", port_id);
//TODO handle the second unwrap //TODO handle the second unwrap
@@ -664,20 +691,22 @@ impl<const N: usize> Xhci<N> {
debug!("Port {} Link State: {}", port_id, port.state()); debug!("Port {} Link State: {}", port_id, port.state());
port.set_pr(); {
debug!( port.set_pr();
"Flags after setting port {} reset: {:?}", debug!(
port_id, "Flags after setting port {} reset: {:?}",
port.flags() port_id,
); port.flags()
while !port.flags().contains(port::PortFlags::PRC) { );
debug!("port {} reset loop ran at least once!", port_id); let timeout = Timeout::from_secs(1);
if instant.elapsed().as_secs() >= 1 { while !port.flags().contains(port::PortFlags::PRC) {
warn!("timeout"); timeout.run().map_err(|()| {
break; log::error!("timeout on port {} PRC", port_id);
Error::new(EIO)
})?;
} }
std::thread::yield_now();
} }
Ok(())
} }
pub fn setup_scratchpads(&mut self) -> Result<()> { pub fn setup_scratchpads(&mut self) -> Result<()> {