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:
2026-06-07 09:50:50 +03:00
parent 86902d4819
commit 5e44191c90
4 changed files with 354 additions and 3 deletions
+83 -2
View File
@@ -2108,18 +2108,99 @@ as the R5b backlog:
`quirk_radeon_pm`, `quirk_remove_d3hot_delay` — deferred to Phase R8
when PM infrastructure lands.
### Phase R6: xHCI Controller Flag Expansion (12 days)
### Phase R6: xHCI Controller Flag Expansion (delivered 2026-06-07)
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.
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)
2. `XHCI_HW_LPM_DISABLE` — hardware LPM broken
3. `XHCI_MISSING_CAS` — missing CAS workaround
4. `XHCI_BROKEN_D3COLD_S2I` — D3cold broken on some AMD
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 R0R5 (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 (23 days)
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`.
/// Bit positions match the Linux numerical values exactly for clean
/// 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)]
pub struct XhciControllerQuirkFlags: u64 {
// R0R5 — pre-existing bits.
const RESET_EP_QUIRK = 1 << 1; // XHCI_RESET_EP_QUIRK
const AMD_PLL_FIX = 1 << 3; // XHCI_AMD_PLL_FIX
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 TRB_OVERFETCH = 1 << 45; // XHCI_TRB_OVERFETCH
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);
}
// ---- 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,
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,
},
];
Submodule local/sources/base updated: c54b5182cd...3b0d02d81c