diff --git a/local/recipes/drivers/redox-driver-sys/source/src/quirks/mod.rs b/local/recipes/drivers/redox-driver-sys/source/src/quirks/mod.rs index 9aa09dc0d2..c39e4c7b17 100644 --- a/local/recipes/drivers/redox-driver-sys/source/src/quirks/mod.rs +++ b/local/recipes/drivers/redox-driver-sys/source/src/quirks/mod.rs @@ -31,6 +31,7 @@ pub mod dmi; pub mod pci_table; pub mod toml_loader; pub mod usb_table; +pub mod xhci_table; use crate::pci::PciDeviceInfo; @@ -546,27 +547,141 @@ pub fn lookup_pci_quirks_full(info: &PciDeviceInfo) -> PciQuirkLookup { } bitflags::bitflags! { - /// Flags for xHCI controller-level quirks. + /// xHCI controller quirks, matching Linux 7.1 `xhci.h:1587-1649`. + /// + /// Bit positions are identical to the Linux `XHCI_QUIRK_*` defines so + /// that consumers can translate 1:1 without remapping. See + /// `local/reference/linux-7.1/drivers/usb/host/xhci.h` and + /// `xhci-pci.c` `xhci_pci_quirks()` for the canonical reference. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct XhciControllerQuirkFlags: u64 { - /// MSI delivery on this controller is unreliable. - const BROKEN_MSI = 1 << 0; - const ZERO_64B_REGS = 1 << 1; - const BROKEN_D3COLD_S2I = 1 << 2; - const SSIC_PORT_UNUSED = 1 << 3; - const MISSING_CAS = 1 << 4; - const BROKEN_PORT_PED = 1 << 5; - const HW_LPM_DISABLE = 1 << 6; + const LINK_TRB_QUIRK = 1u64 << 0; + /// Deprecated — kept for binary compat with the Linux header. + const RESET_EP_QUIRK = 1u64 << 1; + const NEC_HOST = 1u64 << 2; + const AMD_PLL_FIX = 1u64 << 3; + const SPURIOUS_SUCCESS = 1u64 << 4; + const EP_LIMIT_QUIRK = 1u64 << 5; + const BROKEN_MSI = 1u64 << 6; + const RESET_ON_RESUME = 1u64 << 7; + const SW_BW_CHECKING = 1u64 << 8; + const AMD_0x96_HOST = 1u64 << 9; + /// Deprecated. + const TRUST_TX_LENGTH = 1u64 << 10; + const LPM_SUPPORT = 1u64 << 11; + const INTEL_HOST = 1u64 << 12; + const SPURIOUS_REBOOT = 1u64 << 13; + const COMP_MODE_QUIRK = 1u64 << 14; + const AVOID_BEI = 1u64 << 15; + /// Deprecated. + const PLAT = 1u64 << 16; + const SLOW_SUSPEND = 1u64 << 17; + const SPURIOUS_WAKEUP = 1u64 << 18; + const BROKEN_STREAMS = 1u64 << 19; + const PME_STUCK_QUIRK = 1u64 << 20; + const MTK_HOST = 1u64 << 21; + const SSIC_PORT_UNUSED = 1u64 << 22; + const NO_64BIT_SUPPORT = 1u64 << 23; + const MISSING_CAS = 1u64 << 24; + const BROKEN_PORT_PED = 1u64 << 25; + const LIMIT_ENDPOINT_INTERVAL_7 = 1u64 << 26; + const U2_DISABLE_WAKE = 1u64 << 27; + const ASMEDIA_MODIFY_FLOWCONTROL = 1u64 << 28; + const HW_LPM_DISABLE = 1u64 << 29; + const SUSPEND_DELAY = 1u64 << 30; + const INTEL_USB_ROLE_SW = 1u64 << 31; + const ZERO_64B_REGS = 1u64 << 32; + const DEFAULT_PM_RUNTIME_ALLOW = 1u64 << 33; + const RESET_PLL_ON_DISCONNECT = 1u64 << 34; + const SNPS_BROKEN_SUSPEND = 1u64 << 35; + const SKIP_PHY_INIT = 1u64 << 37; + const DISABLE_SPARSE = 1u64 << 38; + const SG_TRB_CACHE_SIZE_QUIRK = 1u64 << 39; + const NO_SOFT_RETRY = 1u64 << 40; + const BROKEN_D3COLD_S2I = 1u64 << 41; + const EP_CTX_BROKEN_DCS = 1u64 << 42; + const SUSPEND_RESUME_CLKS = 1u64 << 43; + const RESET_TO_DEFAULT = 1u64 << 44; + const TRB_OVERFETCH = 1u64 << 45; + const ZHAOXIN_HOST = 1u64 << 46; + const WRITE_64_HI_LO = 1u64 << 47; + const CDNS_SCTX_QUIRK = 1u64 << 48; + const ETRON_HOST = 1u64 << 49; + const LIMIT_ENDPOINT_INTERVAL_9 = 1u64 << 50; } } -/// Full xHCI controller quirk lookup combining compiled-in PCI/DMI tables. +/// Compiled-in xHCI controller quirk entry. +/// +/// Mirrors the per-controller matching logic in +/// Linux 7.1 `drivers/usb/host/xhci-pci.c:xhci_pci_quirks()`. All matching +/// entries' flags accumulate via OR, matching Linux's `xhci->quirks |= ...` +/// accumulation pattern. +#[derive(Clone, Copy, Debug)] +pub struct XhciQuirkEntry { + pub vendor: u16, + pub device: u16, + pub revision_lo: u8, + pub revision_hi: u8, + pub hci_version_lo: u16, + pub hci_version_hi: u16, + pub flags: XhciControllerQuirkFlags, +} + +impl XhciQuirkEntry { + pub const WILDCARD: Self = Self { + vendor: PCI_QUIRK_ANY_ID, + device: PCI_QUIRK_ANY_ID, + revision_lo: 0x00, + revision_hi: 0xFF, + hci_version_lo: 0x0000, + hci_version_hi: 0xFFFF, + flags: XhciControllerQuirkFlags::empty(), + }; + + pub fn matches(&self, vendor: u16, device: u16, revision: u8, hci_version: u16) -> bool { + if self.vendor != PCI_QUIRK_ANY_ID && self.vendor != vendor { + return false; + } + if self.device != PCI_QUIRK_ANY_ID && self.device != device { + return false; + } + if revision < self.revision_lo || revision > self.revision_hi { + return false; + } + if hci_version < self.hci_version_lo || hci_version > self.hci_version_hi { + return false; + } + true + } +} + +impl Default for XhciQuirkEntry { + fn default() -> Self { + Self::WILDCARD + } +} + +/// Look up accumulated xHCI controller quirks for the given PCI device. +/// +/// Mirrors `lookup_pci_quirks` but for xHCI controllers. Currently performs +/// Layer 1 (compiled-in [`xhci_table::XHCI_QUIRK_TABLE`] lookup). Layers 2 +/// (TOML `/etc/quirks.d/`) and 3 (DMI) for xHCI will be added alongside the +/// equivalent loaders in `toml_loader` and `dmi`. pub fn lookup_xhci_controller_quirks_full( - _vendor: u16, - _device: u16, + vendor: u16, + device: u16, + revision: u8, + hci_version: u16, _dmi_info: Option<&crate::quirks::dmi::DmiInfo>, ) -> XhciControllerQuirkFlags { - XhciControllerQuirkFlags::empty() + let mut flags = XhciControllerQuirkFlags::empty(); + for entry in xhci_table::XHCI_QUIRK_TABLE { + if entry.matches(vendor, device, revision, hci_version) { + flags |= entry.flags; + } + } + flags } bitflags::bitflags! { diff --git a/local/recipes/drivers/redox-driver-sys/source/src/quirks/xhci_table.rs b/local/recipes/drivers/redox-driver-sys/source/src/quirks/xhci_table.rs new file mode 100644 index 0000000000..859e8327ce --- /dev/null +++ b/local/recipes/drivers/redox-driver-sys/source/src/quirks/xhci_table.rs @@ -0,0 +1,602 @@ +//! Canonical xHCI controller quirk table — Linux 7.1 port. +//! +//! Source: `local/reference/linux-7.1/drivers/usb/host/xhci-pci.c`, +//! function `xhci_pci_quirks()` (lines 251–517). Each entry here corresponds +//! to a single `if (pdev->vendor == X && pdev->device == Y) xhci->quirks |= Z` +//! block in that function. Flags accumulate via OR, matching Linux semantics. +//! +//! Bugs fixed vs the prior self-contained table in +//! `local/sources/base/drivers/usb/xhcid/src/xhci/quirks.rs`: +//! - Intel 0x9c31 was duplicated; second copy belonged to WildcatPoint (0x9cb1). +//! - Panther Point device ID corrected to 0x1e31 (was 0x9c31). +//! - VIA VL805 (0x3483) flags corrected to LPM_SUPPORT + TRB_OVERFETCH +//! (was RESET_ON_RESUME). +//! - Phytium (0xdc27) flags corrected to RESET_ON_RESUME (was +//! LIMIT_ENDPOINT_INTERVAL_9). +//! - ASMedia 0x1142 (ASM1042A) flags corrected to NO_64BIT_SUPPORT + +//! ASMEDIA_MODIFY_FLOWCONTROL (was BROKEN_MSI). +//! - Intel 0x9a13 (Tiger Lake non-PCH) moved to DEFAULT_PM_RUNTIME_ALLOW +//! list (was incorrectly on RESET_TO_DEFAULT list — that is Tiger Lake +//! *PCH* 0xa0ed). + +use super::{XhciQuirkEntry as Entry, XhciControllerQuirkFlags as F}; + +const INTEL_BASELINE: F = F::from_bits_truncate( + F::LPM_SUPPORT.bits() | F::INTEL_HOST.bits() | F::AVOID_BEI.bits(), +); + +const ETRON_ALL: F = F::from_bits_truncate( + F::ETRON_HOST.bits() + | F::RESET_ON_RESUME.bits() + | F::BROKEN_STREAMS.bits() + | F::NO_SOFT_RETRY.bits(), +); + +const ZHAOXIN_BASELINE: F = F::from_bits_truncate( + F::ZHAOXIN_HOST.bits() | F::LPM_SUPPORT.bits(), +); + +pub const PCI_VENDOR_ID_FRESCO_LOGIC: u16 = 0x1b73; +pub const PCI_VENDOR_ID_NEC: u16 = 0x1033; +pub const PCI_VENDOR_ID_AMD: u16 = 0x1022; +pub const PCI_VENDOR_ID_ATI: u16 = 0x1002; +pub const PCI_VENDOR_ID_INTEL: u16 = 0x8086; +pub const PCI_VENDOR_ID_ETRON: u16 = 0x1b6f; +pub const PCI_VENDOR_ID_RENESAS: u16 = 0x1912; +pub const PCI_VENDOR_ID_VIA: u16 = 0x1106; +pub const PCI_VENDOR_ID_PHYTIUM: u16 = 0x1db7; +pub const PCI_VENDOR_ID_ASMEDIA: u16 = 0x1b21; +pub const PCI_VENDOR_ID_TI: u16 = 0x104c; +pub const PCI_VENDOR_ID_BROADCOM: u16 = 0x14e4; +pub const PCI_VENDOR_ID_CAVIUM: u16 = 0x177d; +pub const PCI_VENDOR_ID_ZHAOXIN: u16 = 0x1d17; +pub const PCI_VENDOR_ID_CDNS: u16 = 0x17cd; + +pub const XHCI_QUIRK_TABLE: &[Entry] = &[ + // === Fresco Logic ===================================================== + // PDK rev 0x0: deprecated RESET_EP_QUIRK. + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1000, + revision_lo: 0x0, + revision_hi: 0x0, + flags: F::RESET_EP_QUIRK, + ..Entry::WILDCARD + }, + // PDK rev 0x4: SLOW_SUSPEND. + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1000, + revision_lo: 0x4, + revision_hi: 0x4, + flags: F::SLOW_SUSPEND, + ..Entry::WILDCARD + }, + // PDK any revision: BROKEN_STREAMS. + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1000, + flags: F::BROKEN_STREAMS, + ..Entry::WILDCARD + }, + // PDK + FL1400: BROKEN_MSI (confirmed for all revisions of both). + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1000, + flags: F::BROKEN_MSI, + ..Entry::WILDCARD + }, + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1400, + flags: F::BROKEN_MSI, + ..Entry::WILDCARD + }, + // FL1009: BROKEN_STREAMS. + Entry { + vendor: PCI_VENDOR_ID_FRESCO_LOGIC, + device: 0x1009, + flags: F::BROKEN_STREAMS, + ..Entry::WILDCARD + }, + + // === NEC ============================================================== + Entry { + vendor: PCI_VENDOR_ID_NEC, + flags: F::NEC_HOST, + ..Entry::WILDCARD + }, + + // === AMD — LIMIT_ENDPOINT_INTERVAL_9 on 8 controllers ================= + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x13ed, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x13ee, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x148c, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15d4, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15d5, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e0, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e1, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e5, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + + // AMD 0x96 host controllers (hci_version == 0x96). + Entry { + vendor: PCI_VENDOR_ID_AMD, + hci_version_lo: 0x0096, + hci_version_hi: 0x0096, + flags: F::AMD_0x96_HOST, + ..Entry::WILDCARD + }, + + // AMD SUSPEND_DELAY (also requires platform PLL check in Linux; we + // apply the flag unconditionally — `usb_amd_quirk_pll_check()` is a + // host-level helper that we cannot easily port. The flag is a hint + // for the suspend path, which xhcid does not yet implement). + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x145c, flags: F::SUSPEND_DELAY, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e0, flags: F::SUSPEND_DELAY, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e1, flags: F::SUSPEND_DELAY, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43bb, flags: F::SUSPEND_DELAY, ..Entry::WILDCARD }, + + // AMD SNPS_BROKEN_SUSPEND (Raven 15E0/15E1). + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e0, flags: F::SNPS_BROKEN_SUSPEND, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x15e1, flags: F::SNPS_BROKEN_SUSPEND, ..Entry::WILDCARD }, + + // AMD Raven2 (0x15e5): DISABLE_SPARSE + RESET_ON_RESUME. + Entry { + vendor: PCI_VENDOR_ID_AMD, device: 0x15e5, + flags: F::from_bits_truncate(F::DISABLE_SPARSE.bits() | F::RESET_ON_RESUME.bits()), + ..Entry::WILDCARD + }, + + // AMD 0x43f7: DEFAULT_PM_RUNTIME_ALLOW. + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43f7, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + + // AMD Promontory (43b9/43ba/43bb/43bc): U2_DISABLE_WAKE. + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43b9, flags: F::U2_DISABLE_WAKE, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43ba, flags: F::U2_DISABLE_WAKE, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43bb, flags: F::U2_DISABLE_WAKE, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43bc, flags: F::U2_DISABLE_WAKE, ..Entry::WILDCARD }, + + // AMD Promontory _2 (43bb) and _4 (43b9): NO_SOFT_RETRY. + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43b9, flags: F::NO_SOFT_RETRY, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x43bb, flags: F::NO_SOFT_RETRY, ..Entry::WILDCARD }, + + // AMD Renoir (0x1639): BROKEN_D3COLD_S2I. + Entry { vendor: PCI_VENDOR_ID_AMD, device: 0x1639, flags: F::BROKEN_D3COLD_S2I, ..Entry::WILDCARD }, + + // === ATI — Navi10 internal xHCI ======================================= + Entry { vendor: PCI_VENDOR_ID_ATI, device: 0x7316, flags: F::LIMIT_ENDPOINT_INTERVAL_9, ..Entry::WILDCARD }, + + // === Intel — vendor baseline ========================================== + Entry { + vendor: PCI_VENDOR_ID_INTEL, + flags: INTEL_BASELINE, + ..Entry::WILDCARD + }, + + // Intel Panther Point (0x1e31). + Entry { + vendor: PCI_VENDOR_ID_INTEL, device: 0x1e31, + flags: F::from_bits_truncate( + F::EP_LIMIT_QUIRK.bits() | F::SW_BW_CHECKING.bits() | F::SPURIOUS_REBOOT.bits(), + ), + ..Entry::WILDCARD + }, + + // Intel LynxPoint-LP (0x9c31) and WildcatPoint-LP (0x9cb1). + Entry { + vendor: PCI_VENDOR_ID_INTEL, device: 0x9c31, + flags: F::from_bits_truncate(F::SPURIOUS_REBOOT.bits() | F::SPURIOUS_WAKEUP.bits()), + ..Entry::WILDCARD + }, + Entry { + vendor: PCI_VENDOR_ID_INTEL, device: 0x9cb1, + flags: F::from_bits_truncate(F::SPURIOUS_REBOOT.bits() | F::SPURIOUS_WAKEUP.bits()), + ..Entry::WILDCARD + }, + + // Intel PME_STUCK_QUIRK (8 controllers). + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x9d2f, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0xa12f, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x22b5, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x0aa8, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x1aa8, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x5aa8, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x19d0, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0xa3af, flags: F::PME_STUCK_QUIRK, ..Entry::WILDCARD }, + + // Intel Cherryview (0x22b5): SSIC_PORT_UNUSED. + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x22b5, flags: F::SSIC_PORT_UNUSED, ..Entry::WILDCARD }, + + // Intel INTEL_USB_ROLE_SW (3 controllers). + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x22b5, flags: F::INTEL_USB_ROLE_SW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x9d2f, flags: F::INTEL_USB_ROLE_SW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x5aa8, flags: F::INTEL_USB_ROLE_SW, ..Entry::WILDCARD }, + + // Intel MISSING_CAS (5 controllers). + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x22b5, flags: F::MISSING_CAS, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x9d2f, flags: F::MISSING_CAS, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0xa12f, flags: F::MISSING_CAS, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x5aa8, flags: F::MISSING_CAS, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x19d0, flags: F::MISSING_CAS, ..Entry::WILDCARD }, + + // Intel RESET_TO_DEFAULT (PCH variants only). + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0xa0ed, flags: F::RESET_TO_DEFAULT, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x51ed, flags: F::RESET_TO_DEFAULT, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x54ed, flags: F::RESET_TO_DEFAULT, ..Entry::WILDCARD }, + + // Intel DEFAULT_PM_RUNTIME_ALLOW (Thunderbolt + Tiger Lake non-PCH + Maple Ridge). + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15b5, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15b6, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15c1, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15db, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15d4, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15e9, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15ec, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x15f0, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x8a13, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x9a13, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_INTEL, device: 0x1138, flags: F::DEFAULT_PM_RUNTIME_ALLOW, ..Entry::WILDCARD }, + + // === Etron ============================================================ + Entry { vendor: PCI_VENDOR_ID_ETRON, device: 0x7023, flags: ETRON_ALL, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_ETRON, device: 0x7052, flags: ETRON_ALL, ..Entry::WILDCARD }, + + // === Renesas ========================================================== + Entry { vendor: PCI_VENDOR_ID_RENESAS, device: 0x0014, flags: F::ZERO_64B_REGS, ..Entry::WILDCARD }, + Entry { + vendor: PCI_VENDOR_ID_RENESAS, device: 0x0015, + flags: F::from_bits_truncate(F::RESET_ON_RESUME.bits() | F::ZERO_64B_REGS.bits()), + ..Entry::WILDCARD + }, + + // === VIA ============================================================== + // Any VIA: RESET_ON_RESUME. + Entry { vendor: PCI_VENDOR_ID_VIA, flags: F::RESET_ON_RESUME, ..Entry::WILDCARD }, + // VIA 0x3432: BROKEN_STREAMS. + Entry { vendor: PCI_VENDOR_ID_VIA, device: 0x3432, flags: F::BROKEN_STREAMS, ..Entry::WILDCARD }, + // VIA VL805 (0x3483): LPM_SUPPORT + TRB_OVERFETCH. + Entry { + vendor: PCI_VENDOR_ID_VIA, device: 0x3483, + flags: F::from_bits_truncate(F::LPM_SUPPORT.bits() | F::TRB_OVERFETCH.bits()), + ..Entry::WILDCARD + }, + + // === Phytium ========================================================== + Entry { vendor: PCI_VENDOR_ID_PHYTIUM, device: 0xdc27, flags: F::RESET_ON_RESUME, ..Entry::WILDCARD }, + + // === ASMedia ========================================================== + // ASM1042 (0x1042): SPURIOUS_SUCCESS + BROKEN_STREAMS. + Entry { + vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x1042, + flags: F::from_bits_truncate(F::SPURIOUS_SUCCESS.bits() | F::BROKEN_STREAMS.bits()), + ..Entry::WILDCARD + }, + // ASM1042A (0x1142): NO_64BIT_SUPPORT + ASMEDIA_MODIFY_FLOWCONTROL. + Entry { + vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x1142, + flags: F::from_bits_truncate( + F::NO_64BIT_SUPPORT.bits() | F::ASMEDIA_MODIFY_FLOWCONTROL.bits(), + ), + ..Entry::WILDCARD + }, + // ASM1142/ASM2142/ASM3242 (0x1242/0x2142/0x3242): NO_64BIT_SUPPORT. + Entry { vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x1242, flags: F::NO_64BIT_SUPPORT, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x2142, flags: F::NO_64BIT_SUPPORT, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x3242, flags: F::NO_64BIT_SUPPORT, ..Entry::WILDCARD }, + // ASM3042 (0x3042): RESET_ON_RESUME. + Entry { vendor: PCI_VENDOR_ID_ASMEDIA, device: 0x3042, flags: F::RESET_ON_RESUME, ..Entry::WILDCARD }, + + // === TI =============================================================== + Entry { vendor: PCI_VENDOR_ID_TI, device: 0x8241, flags: F::LIMIT_ENDPOINT_INTERVAL_7, ..Entry::WILDCARD }, + + // === Broadcom / Cavium ================================================ + Entry { vendor: PCI_VENDOR_ID_BROADCOM, device: 0x9026, flags: F::RESET_PLL_ON_DISCONNECT, ..Entry::WILDCARD }, + Entry { vendor: PCI_VENDOR_ID_CAVIUM, device: 0x9026, flags: F::RESET_PLL_ON_DISCONNECT, ..Entry::WILDCARD }, + + // === Zhaoxin ========================================================== + Entry { vendor: PCI_VENDOR_ID_ZHAOXIN, flags: ZHAOXIN_BASELINE, ..Entry::WILDCARD }, + Entry { + vendor: PCI_VENDOR_ID_ZHAOXIN, device: 0x9202, + flags: F::from_bits_truncate(F::RESET_ON_RESUME.bits() | F::TRB_OVERFETCH.bits()), + ..Entry::WILDCARD + }, + Entry { vendor: PCI_VENDOR_ID_ZHAOXIN, device: 0x9203, flags: F::TRB_OVERFETCH, ..Entry::WILDCARD }, + + // === Cadence ========================================================== + Entry { vendor: PCI_VENDOR_ID_CDNS, device: 0x0200, flags: F::CDNS_SCTX_QUIRK, ..Entry::WILDCARD }, + + // === Spec rule: xHCI 1.2+ gets DEFAULT_PM_RUNTIME_ALLOW =============== + Entry { + hci_version_lo: 0x0120, + hci_version_hi: 0xFFFF, + flags: F::DEFAULT_PM_RUNTIME_ALLOW, + ..Entry::WILDCARD + }, +]; + +#[cfg(test)] +mod tests { + use super::*; + + fn lookup(vendor: u16, device: u16, revision: u8, hci_version: u16) -> F { + let mut flags = F::empty(); + for entry in XHCI_QUIRK_TABLE { + if entry.matches(vendor, device, revision, hci_version) { + flags |= entry.flags; + } + } + flags + } + + #[test] + fn fresco_logic_pdk_rev0_has_reset_ep_quirk() { + let q = lookup(PCI_VENDOR_ID_FRESCO_LOGIC, 0x1000, 0x0, 0x100); + assert!(q.contains(F::RESET_EP_QUIRK)); + assert!(q.contains(F::BROKEN_STREAMS)); + assert!(q.contains(F::BROKEN_MSI)); + assert!(!q.contains(F::SLOW_SUSPEND)); + } + + #[test] + fn fresco_logic_pdk_rev4_has_slow_suspend() { + let q = lookup(PCI_VENDOR_ID_FRESCO_LOGIC, 0x1000, 0x4, 0x100); + assert!(q.contains(F::SLOW_SUSPEND)); + assert!(q.contains(F::BROKEN_STREAMS)); + assert!(q.contains(F::BROKEN_MSI)); + assert!(!q.contains(F::RESET_EP_QUIRK)); + } + + #[test] + fn fresco_logic_fl1400_has_broken_msi_only() { + let q = lookup(PCI_VENDOR_ID_FRESCO_LOGIC, 0x1400, 0xFF, 0x100); + assert!(q.contains(F::BROKEN_MSI)); + assert!(!q.contains(F::BROKEN_STREAMS)); + } + + #[test] + fn fresco_logic_fl1009_has_broken_streams() { + let q = lookup(PCI_VENDOR_ID_FRESCO_LOGIC, 0x1009, 0x00, 0x100); + assert!(q.contains(F::BROKEN_STREAMS)); + assert!(!q.contains(F::BROKEN_MSI)); + } + + #[test] + fn nec_any_device_has_nec_host() { + let q = lookup(PCI_VENDOR_ID_NEC, 0x9999, 0x00, 0x100); + assert!(q.contains(F::NEC_HOST)); + } + + #[test] + fn amd_0x96_host_matches_by_hci_version() { + let q = lookup(PCI_VENDOR_ID_AMD, 0x9999, 0x00, 0x0096); + assert!(q.contains(F::AMD_0x96_HOST)); + let q2 = lookup(PCI_VENDOR_ID_AMD, 0x9999, 0x00, 0x0100); + assert!(!q2.contains(F::AMD_0x96_HOST)); + } + + #[test] + fn amd_starship_has_limit_endpoint_interval_9() { + let q = lookup(PCI_VENDOR_ID_AMD, 0x148c, 0x00, 0x100); + assert!(q.contains(F::LIMIT_ENDPOINT_INTERVAL_9)); + } + + #[test] + fn amd_renoir_has_broken_d3cold_s2i() { + let q = lookup(PCI_VENDOR_ID_AMD, 0x1639, 0x00, 0x100); + assert!(q.contains(F::BROKEN_D3COLD_S2I)); + } + + #[test] + fn amd_promontory_all_have_u2_disable_wake() { + for dev in [0x43b9u16, 0x43ba, 0x43bb, 0x43bc] { + let q = lookup(PCI_VENDOR_ID_AMD, dev, 0x00, 0x100); + assert!(q.contains(F::U2_DISABLE_WAKE), "Promontory device 0x{:04x} missing U2_DISABLE_WAKE", dev); + } + } + + #[test] + fn amd_promontory_2_and_4_have_no_soft_retry() { + for dev in [0x43b9u16, 0x43bb] { + let q = lookup(PCI_VENDOR_ID_AMD, dev, 0x00, 0x100); + assert!(q.contains(F::NO_SOFT_RETRY), "Promontory device 0x{:04x} missing NO_SOFT_RETRY", dev); + } + } + + #[test] + fn ati_navi10_has_limit_endpoint_interval_9() { + let q = lookup(PCI_VENDOR_ID_ATI, 0x7316, 0x00, 0x100); + assert!(q.contains(F::LIMIT_ENDPOINT_INTERVAL_9)); + } + + #[test] + fn intel_baseline_any_device() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0xFFFF, 0x00, 0x100); + assert!(q.contains(F::LPM_SUPPORT)); + assert!(q.contains(F::INTEL_HOST)); + assert!(q.contains(F::AVOID_BEI)); + } + + #[test] + fn intel_panther_point_has_ep_limit_quirk() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x1e31, 0x00, 0x100); + assert!(q.contains(F::EP_LIMIT_QUIRK)); + assert!(q.contains(F::SW_BW_CHECKING)); + assert!(q.contains(F::SPURIOUS_REBOOT)); + assert!(q.contains(F::LPM_SUPPORT)); + } + + #[test] + fn intel_lynx_point_lp_9c31_no_duplicate_match_bug() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x9c31, 0x00, 0x100); + assert!(q.contains(F::SPURIOUS_REBOOT)); + assert!(q.contains(F::SPURIOUS_WAKEUP)); + } + + #[test] + fn intel_wildcat_point_lp_9cb1_fixed() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x9cb1, 0x00, 0x100); + assert!(q.contains(F::SPURIOUS_REBOOT)); + assert!(q.contains(F::SPURIOUS_WAKEUP)); + } + + #[test] + fn intel_cherryview_22b5_has_all_expected_flags() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x22b5, 0x00, 0x100); + assert!(q.contains(F::PME_STUCK_QUIRK)); + assert!(q.contains(F::SSIC_PORT_UNUSED)); + assert!(q.contains(F::INTEL_USB_ROLE_SW)); + assert!(q.contains(F::MISSING_CAS)); + } + + #[test] + fn intel_tiger_lake_pch_has_reset_to_default() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0xa0ed, 0x00, 0x100); + assert!(q.contains(F::RESET_TO_DEFAULT)); + } + + #[test] + fn intel_tiger_lake_non_pch_has_pm_runtime_allow_not_reset() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x9a13, 0x00, 0x100); + assert!(q.contains(F::DEFAULT_PM_RUNTIME_ALLOW)); + assert!(!q.contains(F::RESET_TO_DEFAULT), "0x9a13 is Tiger Lake non-PCH, not RESET_TO_DEFAULT"); + } + + #[test] + fn intel_alder_lake_pch_51ed_has_reset_to_default() { + let q = lookup(PCI_VENDOR_ID_INTEL, 0x51ed, 0x00, 0x100); + assert!(q.contains(F::RESET_TO_DEFAULT)); + } + + #[test] + fn etron_ej168_has_full_flag_set() { + let q = lookup(PCI_VENDOR_ID_ETRON, 0x7023, 0x00, 0x100); + assert!(q.contains(F::ETRON_HOST)); + assert!(q.contains(F::RESET_ON_RESUME)); + assert!(q.contains(F::BROKEN_STREAMS)); + assert!(q.contains(F::NO_SOFT_RETRY)); + } + + #[test] + fn renesas_0014_has_zero_64b_only() { + let q = lookup(PCI_VENDOR_ID_RENESAS, 0x0014, 0x00, 0x100); + assert!(q.contains(F::ZERO_64B_REGS)); + assert!(!q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn renesas_0015_has_both() { + let q = lookup(PCI_VENDOR_ID_RENESAS, 0x0015, 0x00, 0x100); + assert!(q.contains(F::ZERO_64B_REGS)); + assert!(q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn via_vl805_fixed_flags() { + let q = lookup(PCI_VENDOR_ID_VIA, 0x3483, 0x00, 0x100); + assert!(q.contains(F::LPM_SUPPORT)); + assert!(q.contains(F::TRB_OVERFETCH)); + // VL805 also gets RESET_ON_RESUME from the vendor-wide VIA entry. + assert!(q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn via_3432_has_broken_streams() { + let q = lookup(PCI_VENDOR_ID_VIA, 0x3432, 0x00, 0x100); + assert!(q.contains(F::BROKEN_STREAMS)); + assert!(q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn phytium_fixed_to_reset_on_resume() { + let q = lookup(PCI_VENDOR_ID_PHYTIUM, 0xdc27, 0x00, 0x100); + assert!(q.contains(F::RESET_ON_RESUME)); + assert!(!q.contains(F::LIMIT_ENDPOINT_INTERVAL_9)); + } + + #[test] + fn asmedia_1042_has_spurious_success_and_broken_streams() { + let q = lookup(PCI_VENDOR_ID_ASMEDIA, 0x1042, 0x00, 0x100); + assert!(q.contains(F::SPURIOUS_SUCCESS)); + assert!(q.contains(F::BROKEN_STREAMS)); + } + + #[test] + fn asmedia_1042a_fixed_flags() { + let q = lookup(PCI_VENDOR_ID_ASMEDIA, 0x1142, 0x00, 0x100); + assert!(q.contains(F::NO_64BIT_SUPPORT)); + assert!(q.contains(F::ASMEDIA_MODIFY_FLOWCONTROL)); + assert!(!q.contains(F::BROKEN_MSI)); + } + + #[test] + fn asmedia_1242_2142_3242_have_no_64bit_support() { + for dev in [0x1242u16, 0x2142, 0x3242] { + let q = lookup(PCI_VENDOR_ID_ASMEDIA, dev, 0x00, 0x100); + assert!(q.contains(F::NO_64BIT_SUPPORT), "ASMedia device 0x{:04x} missing NO_64BIT_SUPPORT", dev); + } + } + + #[test] + fn asmedia_3042_has_reset_on_resume() { + let q = lookup(PCI_VENDOR_ID_ASMEDIA, 0x3042, 0x00, 0x100); + assert!(q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn ti_8241_has_limit_endpoint_interval_7() { + let q = lookup(PCI_VENDOR_ID_TI, 0x8241, 0x00, 0x100); + assert!(q.contains(F::LIMIT_ENDPOINT_INTERVAL_7)); + } + + #[test] + fn broadcom_9026_has_reset_pll_on_disconnect() { + let q = lookup(PCI_VENDOR_ID_BROADCOM, 0x9026, 0x00, 0x100); + assert!(q.contains(F::RESET_PLL_ON_DISCONNECT)); + } + + #[test] + fn cavium_9026_has_reset_pll_on_disconnect() { + let q = lookup(PCI_VENDOR_ID_CAVIUM, 0x9026, 0x00, 0x100); + assert!(q.contains(F::RESET_PLL_ON_DISCONNECT)); + } + + #[test] + fn zhaoxin_baseline_any_device() { + let q = lookup(PCI_VENDOR_ID_ZHAOXIN, 0xFFFF, 0x00, 0x100); + assert!(q.contains(F::ZHAOXIN_HOST)); + assert!(q.contains(F::LPM_SUPPORT)); + } + + #[test] + fn zhaoxin_9202_has_reset_on_resume_and_trb_overfetch() { + let q = lookup(PCI_VENDOR_ID_ZHAOXIN, 0x9202, 0x00, 0x100); + assert!(q.contains(F::RESET_ON_RESUME)); + assert!(q.contains(F::TRB_OVERFETCH)); + } + + #[test] + fn zhaoxin_9203_has_trb_overfetch_only() { + let q = lookup(PCI_VENDOR_ID_ZHAOXIN, 0x9203, 0x00, 0x100); + assert!(q.contains(F::TRB_OVERFETCH)); + assert!(!q.contains(F::RESET_ON_RESUME)); + } + + #[test] + fn cdns_usbssp_has_cdns_sctx_quirk() { + let q = lookup(PCI_VENDOR_ID_CDNS, 0x0200, 0x00, 0x100); + assert!(q.contains(F::CDNS_SCTX_QUIRK)); + } + + #[test] + fn spec_rule_xhci_1_2_gets_default_pm_runtime_allow() { + let q = lookup(0x1234, 0x5678, 0x00, 0x0120); + assert!(q.contains(F::DEFAULT_PM_RUNTIME_ALLOW)); + let q2 = lookup(0x1234, 0x5678, 0x00, 0x0110); + assert!(!q2.contains(F::DEFAULT_PM_RUNTIME_ALLOW)); + } + + #[test] + fn unknown_vendor_no_quirks_unless_spec_rule_applies() { + let q = lookup(0x1234, 0x5678, 0x00, 0x0100); + assert_eq!(q, F::empty()); + } +} diff --git a/local/sources/base b/local/sources/base index 4fdb81fa30..9fc1947d53 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 4fdb81fa30b7648ed832b43021ece1e55010d694 +Subproject commit 9fc1947d539fa6b770a6e377dca43b187e67cdd6