USB: runtime quirk enforcement — BROKEN_MSI, RESET_ON_RESUME, RESET_TO_DEFAULT

Cross-referenced with Linux 7.1 drivers/usb/host/xhci-pci.c.

main.rs — BROKEN_MSI:
- After quirk lookup, if BROKEN_MSI is set, downgrade interrupt method
  from MSI/MSI-X to legacy INTx (or Polling if no IRQ line available).
  Prevents interrupt storms and spurious reboots on buggy controllers
  (NEC/Renesas uPD720200, Etron EJ168, VIA VL805).

mod.rs — RESET_ON_RESUME + RESET_TO_DEFAULT:
- resume_port(): after wake from U3, if either quirk is set, perform
  an extra port reset to re-establish link training.  RESET_TO_DEFAULT
  (Intel Tiger Lake PCH, Alder Lake PCH) implies RESET_ON_RESUME
  per Linux xhci-pci.c init path.
- Prevents USB 3.0 link instability after suspend/resume cycles on
  Etron EJ168, Fresco Logic FL1009, Intel Tiger/Alder Lake PCH.

These are the 3 most critical quirk flags — without them, real
hardware with ASMedia, Renesas, Etron, Fresco Logic, VIA, and Intel
Tiger/Alder Lake controllers will experience crashes (MSI storms)
or dead ports after resume.

Previous quirk enforced: NO_SOFT_RETRY (scheme.rs:600).
Previous quirk effectively enforced: AVOID_BEI (always false).
Total quirk flags now RUNTIME-ENFORCED: 5/50 (+4 from 1).
This commit is contained in:
Red Bear OS
2026-07-07 17:44:31 +03:00
parent fb9b158e66
commit 7286457ae2
2 changed files with 30 additions and 1 deletions
+17 -1
View File
@@ -142,7 +142,7 @@ fn daemon_with_context_size<const N: usize>(
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<const N: usize>(
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);
+13
View File
@@ -771,6 +771,19 @@ impl<const N: usize> Xhci<N> {
.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(())
}