quirks: implement R6 — xHCI controller flag expansion
Phase R6 (2026-06-07) extends the xHCI controller quirk layer with five
new XHCI_* bit positions from Linux 7.1's drivers/usb/host/xhci.h, three
new PCI table entries from xhci-pci.c, and an xhcid-side observability
hook for the unenforced flags. Bit positions match Linux exactly per
the existing docstring convention on XhciControllerQuirkFlags.
Five new xHCI flags (24 total, no collisions):
- XHCI_SSIC_PORT_UNUSED (bit 22) — Intel Cherryview 0x22b5
- XHCI_MISSING_CAS (bit 24) — Intel CV/SP/APL/DV
- XHCI_BROKEN_PORT_PED (bit 25) — platform-only in Linux
- XHCI_HW_LPM_DISABLE (bit 29) — platform-only in Linux
- XHCI_BROKEN_D3COLD_S2I (bit 41) — AMD Renoir 0x1639
XHCI_EP_CTX_BROKEN_DCS (bit 42) was the fifth entry on the plan's list
but is a Linux reserved-but-unused bit: only the BIT_ULL(42) definition
exists, with no consumer code anywhere and no PCI/vendor association.
Adding it would have been a stub. XHCI_SSIC_PORT_UNUSED is added in its
place — it has both a PCI association and a consumer site.
PCI table entries (3 new, 89 total):
- Intel Cherryview 0x22b5 → SSIC_PORT_UNUSED + MISSING_CAS
- AMD Renoir 0x1639 → BROKEN_D3COLD_S2I
BROKEN_PORT_PED and HW_LPM_DISABLE have no PCI entries — Linux sets
these only from xhci-plat.c / xhci-mtk.c / xhci-histb.c (non-PCI host
adapters). They are defined for forward-compatibility with future
platform xHCI support.
xhcid consumer wiring (in local/sources/base submodule):
- log_unenforced_xhci_quirks() called from Xhci::init() emits a
warn! line for each set-but-unenforced R6 flag, citing the Linux
consumer site and the missing Red Bear code path. Observability,
not fake enforcement.
- Real enforcement for consumer sites that require suspend, LPM,
port-disable, or CAS code paths in xhcid is deferred to Phase R8
(PM infrastructure) and follow-up work.
Tests: 8 new (75 → 83 total passing).
Clippy: 26 warnings, all pre-existing R0–R5 baseline. No new warnings.
TOML validator: 244 entries, 0 undefined (no TOML changes for R6 —
xHCI controller flags are compiled-in only).
Source of truth: Linux 7.1 drivers/usb/host/{xhci.h, xhci-pci.c,
xhci.c, xhci-hub.c, xhci-plat.c, xhci-mtk.c, xhci-histb.c}.
This commit is contained in:
@@ -2108,18 +2108,99 @@ as the R5b backlog:
|
|||||||
`quirk_radeon_pm`, `quirk_remove_d3hot_delay` — deferred to Phase R8
|
`quirk_radeon_pm`, `quirk_remove_d3hot_delay` — deferred to Phase R8
|
||||||
when PM infrastructure lands.
|
when PM infrastructure lands.
|
||||||
|
|
||||||
### Phase R6: xHCI Controller Flag Expansion (1–2 days)
|
### Phase R6: xHCI Controller Flag Expansion (delivered 2026-06-07)
|
||||||
|
|
||||||
Expand `XhciControllerQuirkFlags` from 19 to cover the 29 missing Linux flags.
|
Expand `XhciControllerQuirkFlags` from 19 to cover the 29 missing Linux flags.
|
||||||
Only add flags that xhcid's driver code actually consumes — not all 29 at once.
|
Only add flags that xhcid's driver code actually consumes — not all 29 at once.
|
||||||
|
|
||||||
Priority flags based on hardware likely to be encountered:
|
#### Priority flags (plan target)
|
||||||
|
|
||||||
|
The plan's five priority flags were:
|
||||||
1. `XHCI_BROKEN_PORT_PED` — broken port detect (common on older Intel)
|
1. `XHCI_BROKEN_PORT_PED` — broken port detect (common on older Intel)
|
||||||
2. `XHCI_HW_LPM_DISABLE` — hardware LPM broken
|
2. `XHCI_HW_LPM_DISABLE` — hardware LPM broken
|
||||||
3. `XHCI_MISSING_CAS` — missing CAS workaround
|
3. `XHCI_MISSING_CAS` — missing CAS workaround
|
||||||
4. `XHCI_BROKEN_D3COLD_S2I` — D3cold broken on some AMD
|
4. `XHCI_BROKEN_D3COLD_S2I` — D3cold broken on some AMD
|
||||||
5. `XHCI_EP_CTX_BROKEN_DCS` — endpoint context DCS bit broken
|
5. `XHCI_EP_CTX_BROKEN_DCS` — endpoint context DCS bit broken
|
||||||
|
|
||||||
|
#### Phase R6 audit: PCI vs platform, plus a Linux-reserved bit
|
||||||
|
|
||||||
|
The five priority flags were audited against Linux 7.1's `xhci-pci.c`,
|
||||||
|
`xhci-plat.c`, `xhci-mtk.c`, `xhci-histb.c`, `xhci.c`, and `xhci-hub.c` to
|
||||||
|
determine which had a real PCI association versus which were
|
||||||
|
platform-device-only, and which had any consumer code at all. The audit
|
||||||
|
produced the following mapping:
|
||||||
|
|
||||||
|
| Linux flag | Bit | PCI-associable? | Consumer code? | Red Bear status |
|
||||||
|
|--------------------------|-----|-----------------|----------------|------------------|
|
||||||
|
| `XHCI_SSIC_PORT_UNUSED` | 22 | Yes (Intel Cherryview 0x22b5) | Yes (`xhci-pci.c:823-825`, suspend path) | **Real** — flag set via PCI table |
|
||||||
|
| `XHCI_MISSING_CAS` | 24 | Yes (Intel CV/SP/APL/DV) | Yes (CAS bit in endpoint context) | **Real** — flag set via PCI table |
|
||||||
|
| `XHCI_BROKEN_PORT_PED` | 25 | **No** (xhci-plat.c:266, xhci-histb.c, xhci-mtk.c — platform only) | Yes (`xhci-hub.c:563`) | **Forward-compat** — defined, no PCI entry |
|
||||||
|
| `XHCI_HW_LPM_DISABLE` | 29 | **No** (xhci-plat.c:260, xhci-histb.c:265, xhci-mtk.c:465 — platform only) | Yes (`xhci.c:4665`) | **Forward-compat** — defined, no PCI entry |
|
||||||
|
| `XHCI_BROKEN_D3COLD_S2I` | 41 | Yes (AMD Renoir 0x1639) | Yes (`xhci-pci.c:815-817`, suspend path) | **Real** — flag set via PCI table |
|
||||||
|
|
||||||
|
`XHCI_EP_CTX_BROKEN_DCS` (bit 42) was the fifth entry on the plan's list
|
||||||
|
but **is a Linux reserved-but-unused bit**: only the `BIT_ULL(42)`
|
||||||
|
definition exists in `xhci.h:1639`, with no consumer code anywhere in the
|
||||||
|
kernel (`xhci.c`, `xhci-pci.c`, `xhci-hub.c`, `xhci-plat.c`,
|
||||||
|
`xhci-mtk.c`, `xhci-histb.c` all reference it zero times) and no
|
||||||
|
PCI/vendor association. Adding it would have been a stub (no real
|
||||||
|
enforcement possible). It is therefore **NOT** added in Phase R6.
|
||||||
|
`XHCI_SSIC_PORT_UNUSED` (bit 22) is added in its place — it has both a
|
||||||
|
PCI association and a consumer site, making it the only other valid
|
||||||
|
replacement that pairs a flag with real enforcement.
|
||||||
|
|
||||||
|
#### Implementation summary
|
||||||
|
|
||||||
|
| Layer | What changed |
|
||||||
|
|-------|---------------|
|
||||||
|
| `XhciControllerQuirkFlags` (`mod.rs`) | 5 new bits: `SSIC_PORT_UNUSED` (22), `MISSING_CAS` (24), `BROKEN_PORT_PED` (25), `HW_LPM_DISABLE` (29), `BROKEN_D3COLD_S2I` (41). Bit positions match Linux `xhci.h` exactly per the existing docstring convention. |
|
||||||
|
| `xhci_controller_table.rs` | 3 new entries: Cherryview (0x22b5) × 2 (`SSIC_PORT_UNUSED`, `MISSING_CAS`) + AMD Renoir (0x1639) × 1 (`BROKEN_D3COLD_S2I`). No entry for `BROKEN_PORT_PED` / `HW_LPM_DISABLE` — Linux sets these only from `xhci-plat.c` / `xhci-mtk.c` / `xhci-histb.c`, never from `xhci-pci.c`. |
|
||||||
|
| `xhcid/src/xhci/mod.rs` | New `log_unenforced_xhci_quirks()` method called from `init()`. Emits a `warn!` line for each set-but-unenforced R6 flag, citing the Linux consumer site and the missing xhcid code path. **Observability, not fake enforcement.** |
|
||||||
|
| `XHCI_CONTROLLER_QUIRK_TABLE` size | 86 pre-R6 + 3 R6 = 89 entries. |
|
||||||
|
| Distinct xHCI flag bits defined | 19 pre-R6 + 5 R6 = 24 bits, no collisions. |
|
||||||
|
|
||||||
|
#### xhcid consumer wiring — real vs deferred
|
||||||
|
|
||||||
|
The Phase R6 work added a real xHCI quirk consumer wiring point in
|
||||||
|
`xhcid::Xhci::init()`. The function `log_unenforced_xhci_quirks` is the
|
||||||
|
**single hook point** through which every future xHCI quirk consumer in
|
||||||
|
xhcid can be discovered and audited: when a flag is set, the driver
|
||||||
|
either enforces it inline (if the code path exists in xhcid) or logs a
|
||||||
|
warn!-line that names the Linux consumer site and the missing Red Bear
|
||||||
|
subsystem. There are zero fake enforcement branches; the warn! lines
|
||||||
|
are honest diagnostic output.
|
||||||
|
|
||||||
|
| Flag | Enforced in xhcid R6? | What would enforce it |
|
||||||
|
|------|------------------------|----------------------|
|
||||||
|
| `SSIC_PORT_UNUSED` | No (observability only) | Suspend path that calls `xhci_ssic_port_unused_quirk()` — pending Phase R8 (PM infrastructure) |
|
||||||
|
| `MISSING_CAS` | No (observability only) | Endpoint context init that suppresses the CAS bit — pending context init wiring |
|
||||||
|
| `BROKEN_PORT_PED` | No (observability only) | Port disable path that checks `xhci-hub.c:563` semantics — pending xhcid port-disable code |
|
||||||
|
| `HW_LPM_DISABLE` | No (observability only) | LPM enable path that skips hardware LPM init — pending LPM code (xhcid has no LPM at all) |
|
||||||
|
| `BROKEN_D3COLD_S2I` | No (observability only) | Suspend path that calls `pci_d3cold_disable()` on S2Idle — pending Phase R8 |
|
||||||
|
|
||||||
|
The deferred items are listed in the R8 plan below as part of the
|
||||||
|
PM/suspend work. None of them block xhcid boot or basic enumeration.
|
||||||
|
|
||||||
|
#### Tests added (Phase R6, 8 new tests, 83 total passing)
|
||||||
|
|
||||||
|
| Test | Asserts |
|
||||||
|
|------|---------|
|
||||||
|
| `phase_r6_xhci_flags_present` | All 5 new bits are queryable and carry the right bit position |
|
||||||
|
| `phase_r6_xhci_lookup_intel_cherryview` | Intel 0x22b5 returns `SSIC_PORT_UNUSED` + `MISSING_CAS` + `INTEL_HOST` + `LPM_SUPPORT` |
|
||||||
|
| `phase_r6_xhci_lookup_amd_renoir` | AMD 0x1639 returns `BROKEN_D3COLD_S2I` |
|
||||||
|
| `phase_r6_xhci_platform_only_flags_never_set_by_pci_lookup` | Scans the entire PCI table: no entry sets `BROKEN_PORT_PED` or `HW_LPM_DISABLE`. Unknown vendor returns empty. |
|
||||||
|
| `phase_r6_xhci_audit_no_bit_collisions` | The 5 new bits are pairwise disjoint and disjoint from all 19 pre-R6 bits |
|
||||||
|
| `phase_r6_xhci_audit_total_flag_count` | Exactly 24 distinct xHCI flags are defined in the bitflags type |
|
||||||
|
| `phase_r6_xhci_table_size_grew_by_three` | Exactly 3 table entries are R6-only single-flag entries (Cherryview × 2 + Renoir × 1) |
|
||||||
|
| `phase_r6_xhci_lookup_unknown_returns_empty` | Unknown PCI vendor/device returns empty flag set |
|
||||||
|
|
||||||
|
#### Clippy / test status
|
||||||
|
|
||||||
|
- `cargo test --lib`: 83 passed; 0 failed; 0 ignored (was 75 in R5).
|
||||||
|
- `cargo clippy --lib`: 26 warnings, all pre-existing from R0–R5 (same count as the R5 baseline). No new warnings introduced by R6.
|
||||||
|
- `xhcid` (the consumer of `redox-driver-sys`): `cargo check` clean, 10 pre-existing warnings in `usb/*.rs` (unrelated to R6 — never-constructed structs, unused methods).
|
||||||
|
- No TOML changes for R6 (xHCI controller flags are compiled-in only — no equivalent of `quirks.d/0X-*.toml` for xHCI).
|
||||||
|
|
||||||
### Phase R7: GPU Device Table Expansion (2–3 days)
|
### Phase R7: GPU Device Table Expansion (2–3 days)
|
||||||
|
|
||||||
Mine Linux's GPU driver device ID tables for comprehensive coverage:
|
Mine Linux's GPU driver device ID tables for comprehensive coverage:
|
||||||
|
|||||||
@@ -543,8 +543,38 @@ bitflags::bitflags! {
|
|||||||
/// Mirrors Linux's `XHCI_*` quirk defines from `drivers/usb/host/xhci.h`.
|
/// Mirrors Linux's `XHCI_*` quirk defines from `drivers/usb/host/xhci.h`.
|
||||||
/// Bit positions match the Linux numerical values exactly for clean
|
/// Bit positions match the Linux numerical values exactly for clean
|
||||||
/// cross-reference with upstream documentation and debugging.
|
/// cross-reference with upstream documentation and debugging.
|
||||||
|
///
|
||||||
|
/// ## Phase R6 expansion (2026-06-07)
|
||||||
|
///
|
||||||
|
/// The plan's five priority flags were audited against Linux 7.1 to
|
||||||
|
/// determine which had a real PCI association versus which were
|
||||||
|
/// platform-device-only. The expansion below reflects that audit:
|
||||||
|
///
|
||||||
|
/// | Linux flag | Bit | PCI-associable? | Red Bear status |
|
||||||
|
/// |-------------------------|-----|-----------------|------------------|
|
||||||
|
/// | `XHCI_MISSING_CAS` | 24 | Yes (Intel CV/SP/APL/DV) | Real — has consumer; flag set via PCI table |
|
||||||
|
/// | `XHCI_BROKEN_PORT_PED` | 25 | **No** (xhci-plat.c/xhci-histb.c/xhci-mtk.c) | Future — defined, no PCI entry; consumer in xhci-hub.c |
|
||||||
|
/// | `XHCI_SSIC_PORT_UNUSED` | 22 | Yes (Intel Cherryview 0x22b5) | Real — has consumer; flag set via PCI table |
|
||||||
|
/// | `XHCI_HW_LPM_DISABLE` | 29 | **No** (xhci-plat.c/xhci-histb.c/xhci-mtk.c) | Future — defined, no PCI entry; consumer in xhci.c |
|
||||||
|
/// | `XHCI_BROKEN_D3COLD_S2I`| 41 | Yes (AMD Renoir 0x1639) | Real — has consumer; flag set via PCI table |
|
||||||
|
///
|
||||||
|
/// `XHCI_EP_CTX_BROKEN_DCS` (bit 42) was the fifth entry on the plan's
|
||||||
|
/// list but **is a Linux reserved-but-unused bit**: only the `BIT_ULL(42)`
|
||||||
|
/// definition exists, with no consumer code anywhere in the kernel and
|
||||||
|
/// no PCI/vendor association. Adding it would have been a stub
|
||||||
|
/// (no real enforcement possible). It is therefore NOT added in
|
||||||
|
/// Phase R6. `XHCI_SSIC_PORT_UNUSED` (bit 22) is added in its place —
|
||||||
|
/// it has both a PCI association and a consumer site.
|
||||||
|
///
|
||||||
|
/// `XHCI_BROKEN_PORT_PED` and `XHCI_HW_LPM_DISABLE` are PLATFORM-only in
|
||||||
|
/// Linux (set by xhci-plat.c, xhci-histb.c, xhci-mtk.c — non-PCI host
|
||||||
|
/// adapters). Red Bear's xhcid only supports PCI xHCI, so no PCI table
|
||||||
|
/// entries can ever set these bits; they are defined now for
|
||||||
|
/// forward-compatibility with future platform xHCI work and to make the
|
||||||
|
/// bitmask model exhaustive against the Linux header.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct XhciControllerQuirkFlags: u64 {
|
pub struct XhciControllerQuirkFlags: u64 {
|
||||||
|
// R0–R5 — pre-existing bits.
|
||||||
const RESET_EP_QUIRK = 1 << 1; // XHCI_RESET_EP_QUIRK
|
const RESET_EP_QUIRK = 1 << 1; // XHCI_RESET_EP_QUIRK
|
||||||
const AMD_PLL_FIX = 1 << 3; // XHCI_AMD_PLL_FIX
|
const AMD_PLL_FIX = 1 << 3; // XHCI_AMD_PLL_FIX
|
||||||
const SPURIOUS_SUCCESS = 1 << 4; // XHCI_SPURIOUS_SUCCESS
|
const SPURIOUS_SUCCESS = 1 << 4; // XHCI_SPURIOUS_SUCCESS
|
||||||
@@ -564,6 +594,18 @@ bitflags::bitflags! {
|
|||||||
const NO_SOFT_RETRY = 1 << 40; // XHCI_NO_SOFT_RETRY
|
const NO_SOFT_RETRY = 1 << 40; // XHCI_NO_SOFT_RETRY
|
||||||
const TRB_OVERFETCH = 1 << 45; // XHCI_TRB_OVERFETCH
|
const TRB_OVERFETCH = 1 << 45; // XHCI_TRB_OVERFETCH
|
||||||
const LIMIT_EP_INTERVAL_9 = 1 << 50; // XHCI_LIMIT_ENDPOINT_INTERVAL_9
|
const LIMIT_EP_INTERVAL_9 = 1 << 50; // XHCI_LIMIT_ENDPOINT_INTERVAL_9
|
||||||
|
|
||||||
|
// R6 — five new bits. Bit positions match Linux `xhci.h` exactly.
|
||||||
|
//
|
||||||
|
// Source: `linux-7.1/drivers/usb/host/xhci.h:1618,1620,1622,1626,1638`.
|
||||||
|
// Cross-reference: xhci-pci.c (PCI associations), xhci.c /
|
||||||
|
// xhci-hub.c (consumer sites), xhci-plat.c / xhci-mtk.c /
|
||||||
|
// xhci-histb.c (platform-only associations).
|
||||||
|
const SSIC_PORT_UNUSED = 1 << 22; // XHCI_SSIC_PORT_UNUSED (Intel Cherryview 0x22b5, xhci-pci.c:383-384, xhci-pci.c:823-825 consumer)
|
||||||
|
const MISSING_CAS = 1 << 24; // XHCI_MISSING_CAS (Intel CV/SP-LP/SP-H/APL/DV, xhci-pci.c:390-396)
|
||||||
|
const BROKEN_PORT_PED = 1 << 25; // XHCI_BROKEN_PORT_PED (platform-only: xhci-plat.c:266; consumer in xhci-hub.c:563)
|
||||||
|
const HW_LPM_DISABLE = 1 << 29; // XHCI_HW_LPM_DISABLE (platform-only: xhci-plat.c:260, xhci-mtk.c:465, xhci-histb.c:265; consumer in xhci.c:4665)
|
||||||
|
const BROKEN_D3COLD_S2I = 1 << 41; // XHCI_BROKEN_D3COLD_S2I (AMD Renoir 0x1639, xhci-pci.c:341-343; consumer in xhci-pci.c:815-817 suspend path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1473,4 +1515,203 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert_eq!(all.count_ones(), 10);
|
assert_eq!(all.count_ones(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Phase R6 tests (2026-06-07) ----
|
||||||
|
//
|
||||||
|
// The five new xHCI controller flags, with their PCI / platform
|
||||||
|
// associations, are exercised below. Lookup tests use the compiled-in
|
||||||
|
// table directly (PCI vendor/device keys), not TOML.
|
||||||
|
|
||||||
|
/// Phase R6 — every new xHCI flag is queryable and carries the bit
|
||||||
|
/// position documented in the bitflags block.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_flags_present() {
|
||||||
|
assert!(XhciControllerQuirkFlags::SSIC_PORT_UNUSED.bits() == (1u64 << 22));
|
||||||
|
assert!(XhciControllerQuirkFlags::MISSING_CAS.bits() == (1u64 << 24));
|
||||||
|
assert!(XhciControllerQuirkFlags::BROKEN_PORT_PED.bits() == (1u64 << 25));
|
||||||
|
assert!(XhciControllerQuirkFlags::HW_LPM_DISABLE.bits() == (1u64 << 29));
|
||||||
|
assert!(XhciControllerQuirkFlags::BROKEN_D3COLD_S2I.bits() == (1u64 << 41));
|
||||||
|
|
||||||
|
let all = XhciControllerQuirkFlags::SSIC_PORT_UNUSED
|
||||||
|
| XhciControllerQuirkFlags::MISSING_CAS
|
||||||
|
| XhciControllerQuirkFlags::BROKEN_PORT_PED
|
||||||
|
| XhciControllerQuirkFlags::HW_LPM_DISABLE
|
||||||
|
| XhciControllerQuirkFlags::BROKEN_D3COLD_S2I;
|
||||||
|
assert_eq!(all.bits().count_ones(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — Intel Cherryview (0x22b5) returns SSIC_PORT_UNUSED and
|
||||||
|
/// MISSING_CAS from the compiled-in table.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_lookup_intel_cherryview() {
|
||||||
|
let flags = lookup_xhci_controller_quirks(0x8086, 0x22b5);
|
||||||
|
assert!(flags.contains(XhciControllerQuirkFlags::SSIC_PORT_UNUSED));
|
||||||
|
assert!(flags.contains(XhciControllerQuirkFlags::MISSING_CAS));
|
||||||
|
// Cherryview is also an Intel host controller — base flags
|
||||||
|
// should still apply (carried by the pre-existing INTEL_BASE row).
|
||||||
|
assert!(flags.contains(XhciControllerQuirkFlags::INTEL_HOST));
|
||||||
|
assert!(flags.contains(XhciControllerQuirkFlags::LPM_SUPPORT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — AMD Renoir (0x1639) returns BROKEN_D3COLD_S2I.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_lookup_amd_renoir() {
|
||||||
|
let flags = lookup_xhci_controller_quirks(0x1022, 0x1639);
|
||||||
|
assert!(flags.contains(XhciControllerQuirkFlags::BROKEN_D3COLD_S2I));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — platform-only flags BROKEN_PORT_PED and HW_LPM_DISABLE
|
||||||
|
/// are defined but never set by the PCI lookup, because no PCI
|
||||||
|
/// vendor/device combination in xhci-pci.c associates with them.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_platform_only_flags_never_set_by_pci_lookup() {
|
||||||
|
// Scan the entire PCI table for entries that set these flags.
|
||||||
|
for entry in xhci_controller_table::XHCI_CONTROLLER_QUIRK_TABLE {
|
||||||
|
assert!(
|
||||||
|
!entry.flags.contains(XhciControllerQuirkFlags::BROKEN_PORT_PED),
|
||||||
|
"PCI entry {:04X}:{:04X} unexpectedly sets BROKEN_PORT_PED — \
|
||||||
|
this is a platform-only flag in Linux",
|
||||||
|
entry.vendor, entry.device
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!entry.flags.contains(XhciControllerQuirkFlags::HW_LPM_DISABLE),
|
||||||
|
"PCI entry {:04X}:{:04X} unexpectedly sets HW_LPM_DISABLE — \
|
||||||
|
this is a platform-only flag in Linux",
|
||||||
|
entry.vendor, entry.device
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Verify on a sample lookup that an unknown vendor returns empty
|
||||||
|
// and that the platform-only bits are not accidentally returned.
|
||||||
|
let flags = lookup_xhci_controller_quirks(0xDEAD, 0xBEEF);
|
||||||
|
assert!(!flags.contains(XhciControllerQuirkFlags::BROKEN_PORT_PED));
|
||||||
|
assert!(!flags.contains(XhciControllerQuirkFlags::HW_LPM_DISABLE));
|
||||||
|
assert!(flags.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — no bit collisions among the five new xHCI flags, nor
|
||||||
|
/// with any pre-existing bit in the same `XhciControllerQuirkFlags`
|
||||||
|
/// type.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_audit_no_bit_collisions() {
|
||||||
|
let new_bits = [
|
||||||
|
(1u64 << 22, "SSIC_PORT_UNUSED"),
|
||||||
|
(1u64 << 24, "MISSING_CAS"),
|
||||||
|
(1u64 << 25, "BROKEN_PORT_PED"),
|
||||||
|
(1u64 << 29, "HW_LPM_DISABLE"),
|
||||||
|
(1u64 << 41, "BROKEN_D3COLD_S2I"),
|
||||||
|
];
|
||||||
|
// Pre-R6 bits (the 19 flags already defined). Listed as their
|
||||||
|
// bit positions, not names, to keep the test resilient to the
|
||||||
|
// pre-existing bitflag name list.
|
||||||
|
let pre_r6_bits: [u64; 19] = [
|
||||||
|
1u64 << 1, // RESET_EP_QUIRK
|
||||||
|
1u64 << 3, // AMD_PLL_FIX
|
||||||
|
1u64 << 4, // SPURIOUS_SUCCESS
|
||||||
|
1u64 << 6, // BROKEN_MSI
|
||||||
|
1u64 << 7, // RESET_ON_RESUME
|
||||||
|
1u64 << 11, // LPM_SUPPORT
|
||||||
|
1u64 << 12, // INTEL_HOST
|
||||||
|
1u64 << 13, // SPURIOUS_REBOOT
|
||||||
|
1u64 << 15, // AVOID_BEI
|
||||||
|
1u64 << 17, // SLOW_SUSPEND
|
||||||
|
1u64 << 19, // BROKEN_STREAMS
|
||||||
|
1u64 << 20, // PME_STUCK
|
||||||
|
1u64 << 23, // NO_64BIT_SUPPORT
|
||||||
|
1u64 << 30, // SUSPEND_DELAY
|
||||||
|
1u64 << 32, // ZERO_64B_REGS
|
||||||
|
1u64 << 38, // DISABLE_SPARSE
|
||||||
|
1u64 << 40, // NO_SOFT_RETRY
|
||||||
|
1u64 << 45, // TRB_OVERFETCH
|
||||||
|
1u64 << 50, // LIMIT_EP_INTERVAL_9
|
||||||
|
];
|
||||||
|
let pre_r6_mask: u64 = pre_r6_bits.iter().sum();
|
||||||
|
let mut r6_mask: u64 = 0;
|
||||||
|
for (bit, name) in &new_bits {
|
||||||
|
assert_eq!(*bit & pre_r6_mask, 0, "Phase R6 bit {name} collides with pre-R6");
|
||||||
|
assert_eq!(*bit & r6_mask, 0, "Phase R6 bit {name} duplicates a sibling");
|
||||||
|
r6_mask |= *bit;
|
||||||
|
}
|
||||||
|
assert_eq!(r6_mask.count_ones(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — audit: 24 distinct xHCI flags are now defined in
|
||||||
|
/// `XhciControllerQuirkFlags` (19 pre-R6 + 5 new).
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_audit_total_flag_count() {
|
||||||
|
// Iterate the named bits of the bitflags! macro by collecting
|
||||||
|
// every individual named flag and verifying the union is 24 bits.
|
||||||
|
let all_named_bits: [XhciControllerQuirkFlags; 24] = [
|
||||||
|
XhciControllerQuirkFlags::RESET_EP_QUIRK, // 1
|
||||||
|
XhciControllerQuirkFlags::AMD_PLL_FIX, // 3
|
||||||
|
XhciControllerQuirkFlags::SPURIOUS_SUCCESS, // 4
|
||||||
|
XhciControllerQuirkFlags::BROKEN_MSI, // 6
|
||||||
|
XhciControllerQuirkFlags::RESET_ON_RESUME, // 7
|
||||||
|
XhciControllerQuirkFlags::LPM_SUPPORT, // 11
|
||||||
|
XhciControllerQuirkFlags::INTEL_HOST, // 12
|
||||||
|
XhciControllerQuirkFlags::SPURIOUS_REBOOT, // 13
|
||||||
|
XhciControllerQuirkFlags::AVOID_BEI, // 15
|
||||||
|
XhciControllerQuirkFlags::SLOW_SUSPEND, // 17
|
||||||
|
XhciControllerQuirkFlags::BROKEN_STREAMS, // 19
|
||||||
|
XhciControllerQuirkFlags::PME_STUCK, // 20
|
||||||
|
XhciControllerQuirkFlags::NO_64BIT_SUPPORT, // 23
|
||||||
|
XhciControllerQuirkFlags::SSIC_PORT_UNUSED, // 22 (R6)
|
||||||
|
XhciControllerQuirkFlags::MISSING_CAS, // 24 (R6)
|
||||||
|
XhciControllerQuirkFlags::BROKEN_PORT_PED, // 25 (R6)
|
||||||
|
XhciControllerQuirkFlags::HW_LPM_DISABLE, // 29 (R6)
|
||||||
|
XhciControllerQuirkFlags::SUSPEND_DELAY, // 30
|
||||||
|
XhciControllerQuirkFlags::ZERO_64B_REGS, // 32
|
||||||
|
XhciControllerQuirkFlags::DISABLE_SPARSE, // 38
|
||||||
|
XhciControllerQuirkFlags::NO_SOFT_RETRY, // 40
|
||||||
|
XhciControllerQuirkFlags::BROKEN_D3COLD_S2I, // 41 (R6)
|
||||||
|
XhciControllerQuirkFlags::TRB_OVERFETCH, // 45
|
||||||
|
XhciControllerQuirkFlags::LIMIT_EP_INTERVAL_9, // 50
|
||||||
|
];
|
||||||
|
let union: u64 = all_named_bits.iter().map(|f| f.bits()).sum();
|
||||||
|
assert_eq!(union.count_ones(), 24, "expected 24 distinct xHCI flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — table size grew by exactly 3 entries (Cherryview × 2
|
||||||
|
/// flags + AMD Renoir × 1 flag) relative to the pre-R6 baseline.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_table_size_grew_by_three() {
|
||||||
|
// Mask of every pre-R6 bit position in `XhciControllerQuirkFlags`.
|
||||||
|
// Any table entry whose flag set intersects this mask is a pre-R6
|
||||||
|
// (or composite) entry; an R6-only entry has none of these bits set.
|
||||||
|
const PRE_R6_MASK: u64 = (1u64 << 1)
|
||||||
|
| (1u64 << 3)
|
||||||
|
| (1u64 << 4)
|
||||||
|
| (1u64 << 6)
|
||||||
|
| (1u64 << 7)
|
||||||
|
| (1u64 << 11)
|
||||||
|
| (1u64 << 12)
|
||||||
|
| (1u64 << 13)
|
||||||
|
| (1u64 << 15)
|
||||||
|
| (1u64 << 17)
|
||||||
|
| (1u64 << 19)
|
||||||
|
| (1u64 << 20)
|
||||||
|
| (1u64 << 23)
|
||||||
|
| (1u64 << 30)
|
||||||
|
| (1u64 << 32)
|
||||||
|
| (1u64 << 38)
|
||||||
|
| (1u64 << 40)
|
||||||
|
| (1u64 << 45)
|
||||||
|
| (1u64 << 50);
|
||||||
|
|
||||||
|
let r6_only_entries = xhci_controller_table::XHCI_CONTROLLER_QUIRK_TABLE
|
||||||
|
.iter()
|
||||||
|
.filter(|e| e.flags.bits() != 0 && e.flags.bits() & PRE_R6_MASK == 0)
|
||||||
|
.count();
|
||||||
|
assert_eq!(
|
||||||
|
r6_only_entries, 3,
|
||||||
|
"expected 3 R6-only single-flag entries (Cherryview × 2 + Renoir × 1)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase R6 — `lookup_xhci_controller_quirks` for an unknown PCI
|
||||||
|
/// vendor/device returns an empty flag set, not a partial match.
|
||||||
|
#[test]
|
||||||
|
fn phase_r6_xhci_lookup_unknown_returns_empty() {
|
||||||
|
let flags = lookup_xhci_controller_quirks(0x1234, 0x5678);
|
||||||
|
assert!(flags.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -446,4 +446,33 @@ pub const XHCI_CONTROLLER_QUIRK_TABLE: &[XhciControllerQuirk] = &[
|
|||||||
device: 0x3483,
|
device: 0x3483,
|
||||||
flags: XhciControllerQuirkFlags::TRB_OVERFETCH,
|
flags: XhciControllerQuirkFlags::TRB_OVERFETCH,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ---- Phase R6 entries (2026-06-07) ----
|
||||||
|
//
|
||||||
|
// Three of the five Phase R6 priority flags have PCI vendor/device
|
||||||
|
// associations in Linux's xhci-pci.c. The other two
|
||||||
|
// (XHCI_BROKEN_PORT_PED bit 25, XHCI_HW_LPM_DISABLE bit 29) are
|
||||||
|
// platform-device-only in Linux and therefore have no PCI table
|
||||||
|
// entry — see the doc comment on `XhciControllerQuirkFlags`.
|
||||||
|
|
||||||
|
// Intel Cherryview xHCI (0x22b5): xhci-pci.c:383-384 (SSIC) and
|
||||||
|
// xhci-pci.c:390-396 (MISSING_CAS). Device 0x22b5 already has an
|
||||||
|
// INTEL_BASE entry above; the entries below carry the extra flags.
|
||||||
|
XhciControllerQuirk {
|
||||||
|
vendor: 0x8086,
|
||||||
|
device: 0x22b5,
|
||||||
|
flags: XhciControllerQuirkFlags::SSIC_PORT_UNUSED,
|
||||||
|
},
|
||||||
|
XhciControllerQuirk {
|
||||||
|
vendor: 0x8086,
|
||||||
|
device: 0x22b5,
|
||||||
|
flags: XhciControllerQuirkFlags::MISSING_CAS,
|
||||||
|
},
|
||||||
|
|
||||||
|
// AMD Renoir xHCI (0x1639): xhci-pci.c:341-343.
|
||||||
|
XhciControllerQuirk {
|
||||||
|
vendor: 0x1022,
|
||||||
|
device: 0x1639,
|
||||||
|
flags: XhciControllerQuirkFlags::BROKEN_D3COLD_S2I,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
+1
-1
Submodule local/sources/base updated: c54b5182cd...3b0d02d81c
Reference in New Issue
Block a user