xhcid: improvements based on real hardware testing

This commit is contained in:
Jeremy Soller
2025-09-11 21:06:21 -06:00
parent 69a80a6a13
commit 12e601b336
2 changed files with 21 additions and 16 deletions
+19 -16
View File
@@ -465,12 +465,12 @@ impl Xhci {
pub fn init(&mut self, max_slots: u8) -> Result<()> { pub fn init(&mut self, max_slots: u8) -> Result<()> {
// Set run/stop to 0 // Set run/stop to 0
debug!("Stopping xHC."); debug!("Stopping xHC.");
self.op.get_mut().unwrap().usb_cmd.writef(1, false); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false);
// Warm reset // Warm reset
debug!("Reset xHC"); debug!("Reset xHC");
self.op.get_mut().unwrap().usb_cmd.writef(1 << 1, true); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_HCRST, true);
while self.op.get_mut().unwrap().usb_cmd.readf(1 << 1) { while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) {
thread::yield_now(); thread::yield_now();
} }
@@ -531,18 +531,18 @@ impl Xhci {
debug!("Enabling Primary Interrupter."); debug!("Enabling Primary Interrupter.");
int.iman.writef(1 << 1 | 1, true); int.iman.writef(1 << 1 | 1, true);
} }
self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_INTE, true);
// Setup the scratchpad buffers that are required for the xHC to function. // Setup the scratchpad buffers that are required for the xHC to function.
self.setup_scratchpads()?; self.setup_scratchpads()?;
// Set run/stop to 1 // Set run/stop to 1
debug!("Starting xHC."); debug!("Starting xHC.");
self.op.get_mut().unwrap().usb_cmd.writef(1, true); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true);
// Wait until controller is running // 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(1) { while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) {
trace!("Waiting for XHCI to report running status."); trace!("Waiting for XHCI to report running status.");
} }
@@ -796,7 +796,7 @@ impl Xhci {
info!("Attempting to address the device"); info!("Attempting to address the device");
let mut ring = match self let mut ring = match self
.address_device(&mut input, port_id, slot_ty, slot, protocol_speed) .address_device(&mut input, port_id, slot_ty, slot, protocol_speed, speed)
.await .await
{ {
Ok(device_ring) => device_ring, Ok(device_ring) => device_ring,
@@ -1012,6 +1012,7 @@ impl Xhci {
slot_ty: u8, slot_ty: u8,
slot: u8, slot: u8,
protocol_speed: &ProtocolSpeed, protocol_speed: &ProtocolSpeed,
speed: u8,
) -> Result<Ring> { ) -> Result<Ring> {
// Collect MTT, parent port number, parent slot ID // Collect MTT, parent port number, parent slot ID
let mut mtt = false; let mut mtt = false;
@@ -1057,6 +1058,7 @@ impl Xhci {
assert_eq!(route_string & 0x000F_FFFF, route_string); assert_eq!(route_string & 0x000F_FFFF, route_string);
slot_ctx.a.write( slot_ctx.a.write(
route_string route_string
| (u32::from(speed) << 20)
| (u32::from(mtt) << 25) | (u32::from(mtt) << 25)
| (u32::from(hub) << 26) | (u32::from(hub) << 26)
| (u32::from(context_entries) << 27), | (u32::from(context_entries) << 27),
@@ -1087,16 +1089,12 @@ impl Xhci {
let max_error_count = 3u8; // recommended value according to the XHCI spec let max_error_count = 3u8; // recommended value according to the XHCI spec
let ep_ty = 4u8; // control endpoint, bidirectional let ep_ty = 4u8; // control endpoint, bidirectional
let max_packet_size: u32 = if protocol_speed.is_lowspeed() { let max_packet_size: u32 = if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() {
8 // only valid value 8
} else if protocol_speed.is_fullspeed() {
64 // valid values are 8, 16, 32, 64
} else if protocol_speed.is_highspeed() { } else if protocol_speed.is_highspeed() {
64 // only valid value 64
} else if protocol_speed.is_superspeed_gen_x() {
512 // only valid value
} else { } else {
unreachable!() 512
}; };
let host_initiate_disable = false; // only applies to streams let host_initiate_disable = false; // only applies to streams
let max_burst_size = 0u8; // TODO let max_burst_size = 0u8; // TODO
@@ -1110,9 +1108,14 @@ impl Xhci {
| (u32::from(max_packet_size) << 16), | (u32::from(max_packet_size) << 16),
); );
let dequeue_cycle_state = true;
let tr = ring.register(); let tr = ring.register();
endp_ctx.trh.write((tr >> 32) as u32); endp_ctx.trh.write((tr >> 32) as u32);
endp_ctx.trl.write(tr as u32); endp_ctx.trl.write((tr as u32) | u32::from(dequeue_cycle_state));
// The default control pipe can always use 8 bytes
let avg_trb_len = 8u8;
endp_ctx.c.write(u32::from(avg_trb_len));
} }
let input_context_physical = input_context.physical(); let input_context_physical = input_context.physical();
+2
View File
@@ -80,6 +80,8 @@ pub struct OperationalRegs {
pub const USB_CMD_RS: u32 = 1 << 0; pub const USB_CMD_RS: u32 = 1 << 0;
/// Host controller reset /// Host controller reset
pub const USB_CMD_HCRST: u32 = 1 << 1; pub const USB_CMD_HCRST: u32 = 1 << 1;
// Interrupter enable
pub const USB_CMD_INTE: u32 = 1 << 2;
/// Host controller halted /// Host controller halted
pub const USB_STS_HCH: u32 = 1 << 0; pub const USB_STS_HCH: u32 = 1 << 0;