diff --git a/drivers/usb/xhcid/src/main.rs b/drivers/usb/xhcid/src/main.rs index 6898057fa5..1e2693ddbd 100644 --- a/drivers/usb/xhcid/src/main.rs +++ b/drivers/usb/xhcid/src/main.rs @@ -142,7 +142,7 @@ fn daemon_with_context_size( let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle); + let (irq_file, mut interrupt_method) = get_int_method(&mut pcid_handle); log::info!("XHCI {}", pci_config.func.display()); @@ -158,6 +158,22 @@ fn daemon_with_context_size( vendor, device, hci_version, quirks.bits() ); + // Linux 7.1 xhci-pci.c: if BROKEN_MSI quirk is set, fall back from + // MSI/MSI-X to legacy INTx or Polling to avoid interrupt storms + // and spurious reboots on buggy controller implementations. + let interrupt_method = if quirks.contains(xhci::quirks::XhciQuirks::BROKEN_MSI) { + log::warn!("xhcid: BROKEN_MSI quirk active — falling back from MSI to legacy INTx/polling"); + if let Some(irq) = pci_config.func.legacy_interrupt_line { + log::info!("xhcid: using legacy IRQ {}", irq); + InterruptMethod::Intx + } else { + log::warn!("xhcid: no legacy IRQ available — using polling mode"); + InterruptMethod::Polling + } + } else { + interrupt_method + }; + let scheme_name = scheme_path(&name); let socket = Socket::create().expect("xhcid: failed to create usb scheme"); let handler = Blocking::new(&socket, 16); diff --git a/drivers/usb/xhcid/src/xhci/mod.rs b/drivers/usb/xhcid/src/xhci/mod.rs index 6a9ac6e543..61df7452c0 100644 --- a/drivers/usb/xhcid/src/xhci/mod.rs +++ b/drivers/usb/xhcid/src/xhci/mod.rs @@ -771,6 +771,19 @@ impl Xhci { .ok_or_else(|| Error::new(EINVAL))?; log::info!("xhcid: resume port {} to U0", port_id); port.resume(); + drop(ports); + + // Linux 7.1 xhci-pci.c: RESET_ON_RESUME and RESET_TO_DEFAULT + // (which implies RESET_ON_RESUME for Tiger/Alder Lake). + // Some controllers (Etron EJ168, Fresco Logic FL1009, Intel + // Tiger Lake PCH, Alder Lake PCH) need an extra port reset + // after wake from U3 to re-establish link training. + if self.quirks.contains(crate::xhci::quirks::XhciQuirks::RESET_ON_RESUME) + || self.quirks.contains(crate::xhci::quirks::XhciQuirks::RESET_TO_DEFAULT) + { + log::info!("xhcid: RESET quirk active — extra port reset after resume on port {}", port_id); + self.reset_port(port_id)?; + } Ok(()) }