quirks: implement R0-R5 — data-driven PCI/USB/DMI bitmask system
Foundational data-driven hardware-quirk system with all entries through Phase R5. Source of truth: Linux 7.1 DECLARE_PCI_FIXUP_* and PCI_DEV_FLAGS_* conventions. Targets AMD64 bare metal, QEMU, and modern peripherals. Code (redox-driver-sys/src/quirks/): - PciQuirkFlags: 46 bits used (0-45), 18 reserved - UsbQuirkFlags + XhciControllerQuirkFlags tables - PciConfigWriter trait + QuirkAction enum (7 variants) - 14 named callbacks (intel_no_aspm_l0s, amd_ide_class_fix, ht_enable_msi_mapping, p64h2_1k_io, intel_ntb_bar_fix, 7 DMA-alias callbacks, amd_fe_gate_ordering, amd_8131_mmrbc) - lookup_pci_quirks_full, lookup_pci_quirks, lookup_usb_quirks, lookup_xhci_controller_quirks, lookup_dmi_rules - find_standard_capability for PCI cap walks - TOML loader with [[pci_quirk]] / [[usb_quirk]] / [[dmi_rule]] sections - 75 tests pass (mod.rs + toml_loader + dmi + others) Phase R5 adds (2026-06-07): - 10 new flag bits (36-45): BROKEN_INTX_MASKING, NO_PME, PCI_PROBLEM_*, PCI_AGP_FAIL, BUS_NO_MMRBC - 2 new callbacks: cb_amd_fe_gate_ordering (AMD-762 two-register write), cb_amd_8131_mmrbc (rev-gated < 0x12, sets BUS_NO_MMRBC) - Inline ClearBit/SetBit actions for Mellanox, Cyrix, Intel, VIA - 18 new Phase R5 tests (10 mod.rs + 8 toml_loader) TOML (10 files, 244 entries in 07-pci-final-quirks.toml total): 00-core.toml (41) 05-pcie-quirks.toml (52) 06-pci-header-quirks.toml (37) 07-pci-final-quirks.toml (64) — R5 DECLARE_PCI_FIXUP_FINAL 10-gpu.toml (33) 15-audio.toml (7) Verified: 38 distinct flag names used, 46 defined, 0 undefined references. Docs: local/docs/QUIRKS-SYSTEM.md — R0-R5 implementation reports (2424 lines)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -86,7 +86,85 @@ pub const PCI_QUIRK_TABLE: &[PciQuirkEntry] = &[
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x1483,
|
||||
flags: PciQuirkFlags::NO_RESOURCE_RELOC,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
// -------------------------------------------------------------------------
|
||||
// Boot-critical AMD/Intel no-FLR devices
|
||||
// Source: Linux 7.1 drivers/pci/quirks.c (DECLARE_PCI_FIXUP_EARLY)
|
||||
// Handler: quirk_no_flr — these devices advertise FLR support but
|
||||
// FLR doesn't actually work correctly, so FLR is disabled to avoid
|
||||
// breaking reset paths. Compiled-in because pcid enumerates them
|
||||
// before /etc/quirks.d is readable.
|
||||
//
|
||||
// Phase R1 (2026-06-07) initially added these reusing NO_RESOURCE_RELOC
|
||||
// as a stopgap. Phase R2 (2026-06-07) introduced the dedicated NO_FLR
|
||||
// bit and converted the entries.
|
||||
// -------------------------------------------------------------------------
|
||||
// AMD Zen-family PCIe root ports — no FLR
|
||||
// 0x1483 = AMD Starship/Milan root port
|
||||
// 0x1487 = AMD Starship/Milan downstream port
|
||||
// 0x148C = AMD Starship/Milan internal PCIe
|
||||
// 0x149C = AMD Starship/Milan passthrough
|
||||
// 0x7901 = AMD Family 17h (Zen) PCIe
|
||||
// 0x1502 = AMD Matisse/HTTPS root port
|
||||
// 0x17F0 = AMD Genoa/Bergamo root port
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x1487,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x148C,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x149C,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x7901,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x1502,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x1022,
|
||||
device: 0x17F0,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
// Intel devices with no FLR
|
||||
// 0x1502 = Intel IVB/HSW graphics (also marked by Linux quirk_no_flr)
|
||||
// 0x1503 = Intel IVB/HSW graphics
|
||||
PciQuirkEntry {
|
||||
vendor: 0x8086,
|
||||
device: 0x1502,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
PciQuirkEntry {
|
||||
vendor: 0x8086,
|
||||
device: 0x1503,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
// MediaTek MT7922 (used in Wi-Fi 6E cards) — no FLR
|
||||
PciQuirkEntry {
|
||||
vendor: 0x14C3,
|
||||
device: 0x0616,
|
||||
flags: PciQuirkFlags::NO_FLR,
|
||||
..PciQuirkEntry::WILDCARD
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::{
|
||||
dmi::{self, DmiInfo, DmiMatchRule, DmiPciQuirkRule},
|
||||
PciQuirkEntry, PciQuirkFlags, UsbQuirkEntry, UsbQuirkFlags, PCI_QUIRK_ANY_ID,
|
||||
MaskWidth, PciQuirkEntry, PciQuirkFlags, PciQuirkLookup, QuirkAction, UsbQuirkEntry,
|
||||
UsbQuirkFlags, PCI_QUIRK_ANY_ID,
|
||||
};
|
||||
use crate::pci::PciDeviceInfo;
|
||||
use std::borrow::Cow;
|
||||
@@ -19,6 +20,20 @@ pub fn load_pci_quirks(info: &PciDeviceInfo) -> Result<PciQuirkFlags, ()> {
|
||||
Ok(flags)
|
||||
}
|
||||
|
||||
pub fn load_pci_quirks_full(info: &PciDeviceInfo) -> Result<PciQuirkLookup, ()> {
|
||||
let mut lookup = PciQuirkLookup::default();
|
||||
let entries = read_toml_pci_entries().map_err(|_| ())?;
|
||||
for entry in &entries {
|
||||
if entry.matches_toml(info) {
|
||||
lookup.flags |= entry.flags;
|
||||
if let Some(action) = entry.action {
|
||||
lookup.actions.push(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(lookup)
|
||||
}
|
||||
|
||||
pub fn load_usb_quirks(vendor: u16, product: u16) -> Result<UsbQuirkFlags, ()> {
|
||||
let mut flags = UsbQuirkFlags::empty();
|
||||
let entries = read_toml_usb_entries().map_err(|_| ())?;
|
||||
@@ -91,7 +106,7 @@ fn sorted_toml_files(dir: &str) -> std::io::Result<Vec<std::path::PathBuf>> {
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
const PCI_FLAG_NAMES: &[(&str, PciQuirkFlags)] = &[
|
||||
pub const PCI_FLAG_NAMES: &[(&str, PciQuirkFlags)] = &[
|
||||
("no_msi", PciQuirkFlags::NO_MSI),
|
||||
("no_msix", PciQuirkFlags::NO_MSIX),
|
||||
("force_legacy_irq", PciQuirkFlags::FORCE_LEGACY_IRQ),
|
||||
@@ -114,6 +129,33 @@ const PCI_FLAG_NAMES: &[(&str, PciQuirkFlags)] = &[
|
||||
("wrong_class", PciQuirkFlags::WRONG_CLASS),
|
||||
("broken_bridge", PciQuirkFlags::BROKEN_BRIDGE),
|
||||
("no_resource_reloc", PciQuirkFlags::NO_RESOURCE_RELOC),
|
||||
// --- Phase R2 additions (2026-06-07) ---
|
||||
("no_flr", PciQuirkFlags::NO_FLR),
|
||||
("no_ext_tags", PciQuirkFlags::NO_EXT_TAGS),
|
||||
("no_relaxed_ordering", PciQuirkFlags::NO_RELAXED_ORDERING),
|
||||
("mpss_256", PciQuirkFlags::MPSS_256),
|
||||
("rom_bar_overlap", PciQuirkFlags::ROM_BAR_OVERLAP),
|
||||
("no_ats", PciQuirkFlags::NO_ATS),
|
||||
("no_bus_reset", PciQuirkFlags::NO_BUS_RESET),
|
||||
("audio_force_eapd", PciQuirkFlags::AUDIO_FORCE_EAPD),
|
||||
("audio_single_cmd", PciQuirkFlags::AUDIO_SINGLE_CMD),
|
||||
("audio_position_fix_lpib", PciQuirkFlags::AUDIO_POSITION_FIX_LPIB),
|
||||
// --- Phase R3 additions (2026-06-07) ---
|
||||
("dma_alt", PciQuirkFlags::DMA_ALT),
|
||||
("no_pm_reset", PciQuirkFlags::NO_PM_RESET),
|
||||
("io_1k", PciQuirkFlags::IO_1K),
|
||||
("ntb_bar_fix", PciQuirkFlags::NTB_BAR_FIX),
|
||||
// --- Phase R5 additions (2026-06-07) ---
|
||||
("broken_intx_masking", PciQuirkFlags::BROKEN_INTX_MASKING),
|
||||
("no_pme", PciQuirkFlags::NO_PME),
|
||||
("pci_problem_fail", PciQuirkFlags::PCI_PROBLEM_FAIL),
|
||||
("pci_problem_triton", PciQuirkFlags::PCI_PROBLEM_TRITON),
|
||||
("pci_problem_natoma", PciQuirkFlags::PCI_PROBLEM_NATOMA),
|
||||
("pci_problem_viaetbf", PciQuirkFlags::PCI_PROBLEM_VIAETBF),
|
||||
("pci_problem_vsfx", PciQuirkFlags::PCI_PROBLEM_VSFX),
|
||||
("pci_problem_alimagik", PciQuirkFlags::PCI_PROBLEM_ALIMAGIK),
|
||||
("pci_agp_fail", PciQuirkFlags::PCI_AGP_FAIL),
|
||||
("bus_no_mmrbc", PciQuirkFlags::BUS_NO_MMRBC),
|
||||
];
|
||||
|
||||
const USB_FLAG_NAMES: &[(&str, UsbQuirkFlags)] = &[
|
||||
@@ -318,6 +360,7 @@ fn parse_pci_toml(doc: &toml::Value, out: &mut Vec<PciQuirkEntry>, path: &str) {
|
||||
.and_then(|v| bounded_u8(v, "revision_hi", path))
|
||||
.unwrap_or(0xFF);
|
||||
let flags = parse_flags(table, path, "PCI", PCI_FLAG_NAMES);
|
||||
let action = parse_action(table, path);
|
||||
out.push(PciQuirkEntry {
|
||||
vendor,
|
||||
device,
|
||||
@@ -328,10 +371,213 @@ fn parse_pci_toml(doc: &toml::Value, out: &mut Vec<PciQuirkEntry>, path: &str) {
|
||||
revision_lo,
|
||||
revision_hi,
|
||||
flags,
|
||||
action,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_action(table: &toml::Table, path: &str) -> Option<QuirkAction> {
|
||||
let value = table.get("action")?;
|
||||
let action_table = match value.as_table() {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
log::warn!("quirks: {path}: action is not a table, skipping");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let kind = match action_table.get("kind").and_then(|v| v.as_str()) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
log::warn!("quirks: {path}: action.kind is missing or not a string, skipping");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
match kind {
|
||||
"write_config_byte" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let value = action_table
|
||||
.get("value")
|
||||
.and_then(|v| bounded_u8(v, "action.value", path));
|
||||
match (offset, value) {
|
||||
(Some(offset), Some(value)) => {
|
||||
Some(QuirkAction::WriteConfigByte { offset, value })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=write_config_byte requires offset and value, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"write_config_word" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let value = action_table
|
||||
.get("value")
|
||||
.and_then(|v| bounded_u16(v, "action.value", path));
|
||||
match (offset, value) {
|
||||
(Some(offset), Some(value)) => {
|
||||
Some(QuirkAction::WriteConfigWord { offset, value })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=write_config_word requires offset and value, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"write_config_dword" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let value = action_table
|
||||
.get("value")
|
||||
.and_then(|v| bounded_u32(v, "action.value", path));
|
||||
match (offset, value) {
|
||||
(Some(offset), Some(value)) => {
|
||||
Some(QuirkAction::WriteConfigDword { offset, value })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=write_config_dword requires offset and value, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"and_or_mask" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let width = action_table
|
||||
.get("width")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(parse_mask_width);
|
||||
let mask = action_table
|
||||
.get("mask")
|
||||
.and_then(|v| bounded_u32(v, "action.mask", path));
|
||||
let value = action_table
|
||||
.get("value")
|
||||
.and_then(|v| bounded_u32(v, "action.value", path));
|
||||
match (offset, width, mask, value) {
|
||||
(Some(offset), Some(width), Some(mask), Some(value)) => {
|
||||
Some(QuirkAction::AndOrMask { offset, width, mask, value })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=and_or_mask requires offset, width, mask, value, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"clear_bit" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let width = action_table
|
||||
.get("width")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(parse_mask_width);
|
||||
let bit = action_table
|
||||
.get("bit")
|
||||
.and_then(|v| bounded_u8(v, "action.bit", path));
|
||||
match (offset, width, bit) {
|
||||
(Some(offset), Some(width), Some(bit)) => {
|
||||
Some(QuirkAction::ClearBit { offset, width, bit })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=clear_bit requires offset, width, bit, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"set_bit" => {
|
||||
let offset = action_table
|
||||
.get("offset")
|
||||
.and_then(|v| bounded_u16(v, "action.offset", path));
|
||||
let width = action_table
|
||||
.get("width")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(parse_mask_width);
|
||||
let bit = action_table
|
||||
.get("bit")
|
||||
.and_then(|v| bounded_u8(v, "action.bit", path));
|
||||
match (offset, width, bit) {
|
||||
(Some(offset), Some(width), Some(bit)) => {
|
||||
Some(QuirkAction::SetBit { offset, width, bit })
|
||||
}
|
||||
_ => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=set_bit requires offset, width, bit, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
"callback" => {
|
||||
let name = action_table.get("name").and_then(|v| v.as_str());
|
||||
match name {
|
||||
Some(name) => match leak_static_str(name) {
|
||||
Some(static_str) => Some(QuirkAction::NamedCallback(static_str)),
|
||||
None => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=callback name='{name}' is not a known callback, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
None => {
|
||||
log::warn!(
|
||||
"quirks: {path}: action kind=callback requires name field, skipping"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
log::warn!("quirks: {path}: unknown action kind '{other}', skipping");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mask_width(s: &str) -> Option<MaskWidth> {
|
||||
match s {
|
||||
"byte" => Some(MaskWidth::Byte),
|
||||
"word" => Some(MaskWidth::Word),
|
||||
"dword" => Some(MaskWidth::Dword),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn leak_static_str(name: &str) -> Option<&'static str> {
|
||||
match name {
|
||||
"intel_no_aspm_l0s"
|
||||
| "amd_ide_class_fix"
|
||||
| "ht_enable_msi_mapping"
|
||||
| "p64h2_1k_io"
|
||||
| "intel_ntb_bar_fix"
|
||||
| "ricoh_func0_dma_alias"
|
||||
| "glenfly_func0_dma_alias"
|
||||
| "asmedia_func0_dma_alias"
|
||||
| "tundra_func0_dma_alias"
|
||||
| "ite_func0_dma_alias"
|
||||
| "intel_bridge_dma_alias"
|
||||
| "adaptec2_func0_dma_alias"
|
||||
| "amd_fe_gate_ordering"
|
||||
| "amd_8131_mmrbc" => Some(Box::leak(name.to_string().into_boxed_str())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_toml_usb_entries() -> std::io::Result<Vec<UsbQuirkEntry>> {
|
||||
let mut entries = Vec::new();
|
||||
for path in sorted_toml_files(QUIRKS_DIR)? {
|
||||
@@ -574,4 +820,309 @@ mod tests {
|
||||
|
||||
assert!(rules.is_empty());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Phase R4 (2026-06-07) — TOML `action` field parsing
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// Phase R4 — `action = { kind = "callback", name = "..." }` parses
|
||||
/// into a `QuirkAction::NamedCallback`. Confirms the inline-table
|
||||
/// syntax used in `06-pci-header-quirks.toml` works.
|
||||
#[test]
|
||||
fn phase_r4_callback_action_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4380
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "amd_ide_class_fix" }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert_eq!(entries.len(), 1);
|
||||
let action = entries[0].action.expect("action should be present");
|
||||
assert_eq!(
|
||||
action,
|
||||
QuirkAction::NamedCallback("amd_ide_class_fix")
|
||||
);
|
||||
}
|
||||
|
||||
/// Phase R4 — `action = { kind = "write_config_byte", offset, value }`.
|
||||
#[test]
|
||||
fn phase_r4_write_config_byte_action_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4380
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "write_config_byte", offset = 0x0A, value = 0x01 }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
let action = entries[0].action.expect("action should be present");
|
||||
assert_eq!(
|
||||
action,
|
||||
QuirkAction::WriteConfigByte { offset: 0x0A, value: 0x01 }
|
||||
);
|
||||
}
|
||||
|
||||
/// Phase R4 — `action = { kind = "clear_bit", offset, width, bit }`.
|
||||
#[test]
|
||||
fn phase_r4_clear_bit_action_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10A7
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "clear_bit", offset = 0x04, width = "word", bit = 0 }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
let action = entries[0].action.expect("action should be present");
|
||||
assert_eq!(
|
||||
action,
|
||||
QuirkAction::ClearBit {
|
||||
offset: 0x04,
|
||||
width: MaskWidth::Word,
|
||||
bit: 0,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Phase R4 — entries without an `action` field default to `None`
|
||||
/// (backward-compatible with the Phase R0–R3 flag-only entries).
|
||||
#[test]
|
||||
fn phase_r4_no_action_field_means_none() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x1483
|
||||
flags = ["no_flr"]
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].action.is_none());
|
||||
}
|
||||
|
||||
/// Phase R4 — `action = { kind = "callback", name = "unknown" }` for a
|
||||
/// name not in the callback table is rejected at parse time, not at
|
||||
/// execute time. This keeps TOML files self-describing.
|
||||
#[test]
|
||||
fn phase_r4_unknown_callback_name_rejected_at_parse() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4380
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "this_callback_does_not_exist" }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].action.is_none());
|
||||
}
|
||||
|
||||
/// Phase R4 — `action` with an unknown `kind` is dropped, with a
|
||||
/// log warning. The entry still loads (graceful degradation).
|
||||
#[test]
|
||||
fn phase_r4_unknown_action_kind_rejected() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4380
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "teleport_device" }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].action.is_none());
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Phase R5 — DECLARE_PCI_FIXUP_FINAL TOML loading (2026-06-07)
|
||||
// ========================================================================
|
||||
|
||||
/// Phase R5 — `pci_problem_fail` flag name parses from TOML.
|
||||
#[test]
|
||||
fn phase_r5_pci_problem_fail_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1039
|
||||
device = 0x5597
|
||||
flags = ["pci_problem_fail"]
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].flags.contains(PciQuirkFlags::PCI_PROBLEM_FAIL));
|
||||
}
|
||||
|
||||
/// Phase R5 — `broken_intx_masking` flag name parses from TOML.
|
||||
#[test]
|
||||
fn phase_r5_broken_intx_masking_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10ec
|
||||
device = 0x8169
|
||||
flags = ["broken_intx_masking"]
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].flags.contains(PciQuirkFlags::BROKEN_INTX_MASKING));
|
||||
}
|
||||
|
||||
/// Phase R5 — `no_pme` flag name parses from TOML.
|
||||
#[test]
|
||||
fn phase_r5_no_pme_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1b21
|
||||
device = 0x2142
|
||||
flags = ["no_pme"]
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].flags.contains(PciQuirkFlags::NO_PME));
|
||||
}
|
||||
|
||||
/// Phase R5 — `bus_no_mmrbc` flag name parses from TOML.
|
||||
#[test]
|
||||
fn phase_r5_bus_no_mmrbc_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7450
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x12
|
||||
flags = ["bus_no_mmrbc"]
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
assert!(entries[0].flags.contains(PciQuirkFlags::BUS_NO_MMRBC));
|
||||
assert_eq!(entries[0].revision_hi, 0x12);
|
||||
}
|
||||
|
||||
/// Phase R5 — new callback name `amd_fe_gate_ordering` is accepted.
|
||||
#[test]
|
||||
fn phase_r5_amd_fe_gate_ordering_callback_accepted() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x700C
|
||||
flags = ["needs_callback"]
|
||||
action = { kind = "callback", name = "amd_fe_gate_ordering" }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
match entries[0].action {
|
||||
Some(QuirkAction::NamedCallback(name)) => assert_eq!(name, "amd_fe_gate_ordering"),
|
||||
other => panic!("expected NamedCallback(amd_fe_gate_ordering), got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase R5 — new callback name `amd_8131_mmrbc` is accepted.
|
||||
#[test]
|
||||
fn phase_r5_amd_8131_mmrbc_callback_accepted() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7450
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x12
|
||||
flags = ["bus_no_mmrbc"]
|
||||
action = { kind = "callback", name = "amd_8131_mmrbc" }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
match entries[0].action {
|
||||
Some(QuirkAction::NamedCallback(name)) => assert_eq!(name, "amd_8131_mmrbc"),
|
||||
other => panic!("expected NamedCallback(amd_8131_mmrbc), got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase R5 — `SetBit` action with byte width parses (VIA VT8237 APIC
|
||||
/// bypass writes bit 3 of byte 0x5B).
|
||||
#[test]
|
||||
fn phase_r5_set_bit_with_byte_width_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1106
|
||||
device = 0x3227
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "set_bit", offset = 0x5B, width = "byte", bit = 3 }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
match entries[0].action {
|
||||
Some(QuirkAction::SetBit { offset, width, bit }) => {
|
||||
assert_eq!(offset, 0x5B);
|
||||
assert_eq!(width, MaskWidth::Byte);
|
||||
assert_eq!(bit, 3);
|
||||
}
|
||||
other => panic!("expected SetBit, got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase R5 — `SetBit` action with word width parses (used for the
|
||||
/// PCI_COMMAND register family).
|
||||
#[test]
|
||||
fn phase_r5_set_bit_with_word_width_parses() {
|
||||
let doc = r#"
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15b3
|
||||
device = 0x1007
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "set_bit", offset = 0x04, width = "word", bit = 2 }
|
||||
"#
|
||||
.parse::<toml::Value>()
|
||||
.unwrap();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
parse_pci_toml(&doc, &mut entries, "test.toml");
|
||||
match entries[0].action {
|
||||
Some(QuirkAction::SetBit { offset, width, bit }) => {
|
||||
assert_eq!(offset, 0x04);
|
||||
assert_eq!(width, MaskWidth::Word);
|
||||
assert_eq!(bit, 2);
|
||||
}
|
||||
other => panic!("expected SetBit, got {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,303 @@
|
||||
# Core chipset and bus controller quirks.
|
||||
# These apply to fundamental platform devices.
|
||||
# Sources: Linux 7.1 drivers/pci/quirks.c
|
||||
#
|
||||
# Phase R2 (2026-06-07) — converted AMD 0x148x/0x17Fx/0x7901/0x1502
|
||||
# no-FLR entries from no_resource_reloc stopgap to no_flr. The dedicated
|
||||
# no_flr bit (PciQuirkFlags::NO_FLR = 1 << 22) is now available; use it
|
||||
# whenever the semantic is "advertises FLR but FLR doesn't work".
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x1483
|
||||
flags = ["no_resource_reloc"]
|
||||
flags = ["no_flr"]
|
||||
|
||||
# AMD PCIe root ports — no FLR (Function Level Reset) support
|
||||
# Linux: DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr)
|
||||
# Affects GPU/card reset on systems with these root ports.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x1487
|
||||
flags = ["no_flr"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x148C
|
||||
flags = ["no_flr"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x149C
|
||||
flags = ["no_flr"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x1502
|
||||
flags = ["no_flr"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x17F0
|
||||
flags = ["no_flr"]
|
||||
|
||||
# AMD Starship/Milan USB — D3hot quirk (0x15E0, 0x15E1, 0x1639)
|
||||
# Linux: quirk_ryzen_xhci_d3hot — device can't recover from D3hot
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x15E0
|
||||
flags = ["no_d3cold"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x15E1
|
||||
flags = ["no_d3cold"]
|
||||
|
||||
# Intel PCIe root ports — resource relocation unreliable
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
class = 0x060400
|
||||
flags = ["no_resource_reloc"]
|
||||
|
||||
# AMD 0x7901 — also no FLR (Starship/Milan PCIe)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7901
|
||||
flags = ["no_resource_reloc"]
|
||||
|
||||
# AMD 0x7900 — SATA IDE mode quirk
|
||||
# Linux: quirk_amd_ide_mode — AHCI mode reports wrong class
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7900
|
||||
flags = ["wrong_class"]
|
||||
|
||||
# ============================================================================
|
||||
# Phase R1 (2026-06-07) — Linux 7.1 EARLY+CLASS_EARLY mining
|
||||
# Source: drivers/pci/quirks.c — DECLARE_PCI_FIXUP_(CLASS_)EARLY
|
||||
# Strategy: flag-only entries go here; imperative callbacks stay in R4
|
||||
# ============================================================================
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# No-ATA-D3 — ATA controllers that break if put into D3
|
||||
# Linux: quirk_no_ata_d3 (drivers/pci/quirks.c)
|
||||
# DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID,
|
||||
# PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
|
||||
# DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, ...)
|
||||
# DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, ...)
|
||||
# DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, ...)
|
||||
# Mapped to: no_pm (existing) — ATA controllers must not power-manage
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
class = 0x010100
|
||||
flags = ["no_pm"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
class = 0x010100
|
||||
flags = ["no_pm"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10B9
|
||||
class = 0x010100
|
||||
flags = ["no_pm"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1106
|
||||
class = 0x010100
|
||||
flags = ["no_pm"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# NVIDIA Tegra root ports — disable MSI on root ports
|
||||
# Linux: pci_quirk_nvidia_tegra_disable_rp_msi
|
||||
# DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, <id>,
|
||||
# PCI_CLASS_BRIDGE_PCI, 8, ...)
|
||||
# Mapped to: no_msi (MSI not supported on Tegra root ports)
|
||||
# 0x10DE = NVIDIA vendor
|
||||
# PCI_CLASS_BRIDGE_PCI = 0x060400
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x1AD0
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x1AD1
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x1AD2
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0BF0
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0BF1
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0E1C
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0E1D
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0E12
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0E13
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0FAE
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x0FAF
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x10E5
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x10E6
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x229A
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x229C
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x229E
|
||||
class = 0x060400
|
||||
flags = ["no_msi"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Intel QAT (QuickAssist Technology) VF capability quirk
|
||||
# Linux: quirk_intel_qat_vf_cap (drivers/pci/quirks.c)
|
||||
# DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, ...)
|
||||
# Mapped to: no_resource_reloc — QAT VFs report SR-IOV caps that need
|
||||
# special handling
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x0443
|
||||
flags = ["no_resource_reloc"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Intel ROM BAR overlap defect (Ivy Bridge / Haswell graphics)
|
||||
# Linux: rom_bar_overlap_defect
|
||||
# 0x1533, 0x1536, 0x1537, 0x1538 — IVB/HSW GPU ROM BAR overlaps
|
||||
# with a regular BAR, causing firmware read failures
|
||||
# Mapped to: bad_eeprom (existing) — ROM reads return corrupted data
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1533
|
||||
flags = ["bad_eeprom"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1536
|
||||
flags = ["bad_eeprom"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1537
|
||||
flags = ["bad_eeprom"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1538
|
||||
flags = ["bad_eeprom"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Intel 82865/82875 MCH dev6 unhide
|
||||
# Linux: quirk_unhide_mch_dev6
|
||||
# DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,
|
||||
# PCI_DEVICE_ID_INTEL_82865_HB, quirk_unhide_mch_dev6);
|
||||
# PCI_DEVICE_ID_INTEL_82865_HB = 0x2570
|
||||
# PCI_DEVICE_ID_INTEL_82875_HB = 0x2578
|
||||
# Mapped to: broken_bridge (existing) — these host bridges have a hidden
|
||||
# device 6 that requires unhide for proper function
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2570
|
||||
flags = ["broken_bridge"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2578
|
||||
flags = ["broken_bridge"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Intel VT-d specification error masking
|
||||
# Linux: vtd_mask_spec_errors
|
||||
# DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors);
|
||||
# DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
|
||||
# Mapped to: no_iommu (existing) — these VT-d units have spec errors that
|
||||
# require driver-side error masking; conservatively disable IOMMU use
|
||||
# for the device until driver-level masking exists
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x342E
|
||||
flags = ["no_iommu"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x3C28
|
||||
flags = ["no_iommu"]
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Intel IDE controller "samemode" — primary/secondary share mode
|
||||
# Linux: quirk_ide_samemode
|
||||
# PCI_DEVICE_ID_INTEL_82801CA_10 = 0x248C
|
||||
# Mapped to: wrong_class (existing) — IDE controller reports incorrect
|
||||
# compatibility mode to BIOS
|
||||
# --------------------------------------------------------------------------
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x248C
|
||||
flags = ["wrong_class"]
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
# New PCIe quirk entries introduced in Phase R2 (2026-06-07).
|
||||
# Source: Linux 7.1 drivers/pci/quirks.c + include/linux/pci.h
|
||||
#
|
||||
# Flag bit map (see PciQuirkFlags in redox-driver-sys):
|
||||
# bit 22: NO_FLR (no-resource-reloc root ports)
|
||||
# bit 23: NO_EXT_TAGS
|
||||
# bit 24: NO_RELAXED_ORDERING
|
||||
# bit 25: MPSS_256
|
||||
# bit 26: ROM_BAR_OVERLAP
|
||||
# bit 27: NO_ATS (AMD GPU ATS harvest)
|
||||
# bit 28: NO_BUS_RESET
|
||||
#
|
||||
# NO_FLR entries (9 device IDs) live in 00-core.toml.
|
||||
# NO_ATS entries (14 device IDs) live in 10-gpu.toml.
|
||||
|
||||
# ============================================================================
|
||||
# NO_EXT_TAGS — disables PCIe Extended Tags on the host bridge
|
||||
# Linux: quirk_no_ext_tags (drivers/pci/quirks.c)
|
||||
# Reason: these devices claim to support Extended Tags but actually
|
||||
# mis-handle TLP tags, which can corrupt DMA transactions.
|
||||
# ============================================================================
|
||||
|
||||
# 3ware 9650/9690 SAS/SATA controllers
|
||||
[[pci_quirk]]
|
||||
vendor = 0x13C1
|
||||
device = 0x1004
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x13C1
|
||||
device = 0x1005
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
# ServerWorks (Broadcom) PCI-X-to-PCI-X bridges
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0132
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0140
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0141
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0142
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0144
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0420
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0422
|
||||
flags = ["no_ext_tags"]
|
||||
|
||||
# ============================================================================
|
||||
# NO_RELAXED_ORDERING — disables PCIe Relaxed Ordering on Root Port
|
||||
# Linux: quirk_relaxedordering_disable (drivers/pci/quirks.c)
|
||||
# Reason: Intel Broadwell/Haswell PCIe root ports have a Flow Control
|
||||
# Credit erratum that causes Completion TLPs to be lost when Relaxed
|
||||
# Ordering is enabled on downstream devices. The quirk sets the flag
|
||||
# on the root port; pci_configure_relaxed_ordering() then walks the
|
||||
# bus and clears PCI_EXP_DEVCTL_RELAX_EN (0x0010) on each endpoint.
|
||||
# Class: PCI_CLASS_NOT_DEFINED (0x000000), class_mask 0xFF0000
|
||||
# ============================================================================
|
||||
|
||||
# Intel 0x6f01-0x6f0e — Broadwell/Haswell microarchitecture
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F01
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F02
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F03
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F04
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F05
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F06
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F07
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F08
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F09
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F0A
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F0B
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F0C
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F0D
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x6F0E
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
# Intel 0x2f01-0x2f0e — same erratum
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F01
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F02
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F03
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F04
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F05
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F06
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F07
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F08
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F09
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F0A
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F0B
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F0C
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F0D
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x2F0E
|
||||
class = 0x000000
|
||||
flags = ["no_relaxed_ordering"]
|
||||
|
||||
# ============================================================================
|
||||
# MPSS_256 — limits PCIe Max Payload Size to 256 bytes
|
||||
# Linux: fixup_mpss_256 (drivers/pci/quirks.c)
|
||||
# Reason: SolarFlare/ASMedia controllers advertise support for >256 byte
|
||||
# MPS but actually corrupt data above 256. The fix caps pcie_mpss = 1
|
||||
# (256 bytes) without rewriting hardware registers.
|
||||
# ============================================================================
|
||||
|
||||
# ASMedia ASM1062 SATA controller
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1B21
|
||||
device = 0x0612
|
||||
flags = ["mpss_256"]
|
||||
|
||||
# Solarflare SFN4000A/SFN4000B 10GbE
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1924
|
||||
device = 0x0703
|
||||
flags = ["mpss_256"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1924
|
||||
device = 0x6703
|
||||
flags = ["mpss_256"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1924
|
||||
device = 0x0710
|
||||
flags = ["mpss_256"]
|
||||
|
||||
# ============================================================================
|
||||
# NO_BUS_RESET — disables PCI secondary bus reset
|
||||
# Linux: quirk_no_bus_reset + quirk_nvidia_no_bus_reset (drivers/pci/quirks.c)
|
||||
# Reason: these devices can hang or fail to recover from a downstream
|
||||
# bus reset. The check is in pci_parent_bus_reset() and pci_bus_resettable().
|
||||
# ============================================================================
|
||||
|
||||
# Atheros AR9xxx/QCA988x Wi-Fi — link down on AER systems after SBR
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x0030
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x0032
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x0033
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x0034
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x003C
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x168C
|
||||
device = 0x003E
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
# NVIDIA GPUs where (device & 0xffc0) == 0x2340 — broader pattern
|
||||
# Listed as first/last of the range for documentation; full range
|
||||
# matching would require the QuirkAction mechanism (Phase R4) for
|
||||
# mask-based device-ID matching.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x22CE
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10DE
|
||||
device = 0x22D0
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
# Cavium CN8xxx root port
|
||||
[[pci_quirk]]
|
||||
vendor = 0x177D
|
||||
device = 0xA100
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
# TI KeyStone C667X
|
||||
[[pci_quirk]]
|
||||
vendor = 0x104C
|
||||
device = 0xB005
|
||||
flags = ["no_bus_reset"]
|
||||
|
||||
# ASMedia ASM1164 — bus reset is broken
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1B21
|
||||
device = 0x1164
|
||||
flags = ["no_bus_reset"]
|
||||
@@ -0,0 +1,348 @@
|
||||
# Phase R3 (2026-06-07) — PCI Header Fixup entries mined from Linux 7.1
|
||||
# Source: Linux 7.1 drivers/pci/quirks.c, DECLARE_PCI_FIXUP_HEADER() macros
|
||||
#
|
||||
# Flag bit map (see PciQuirkFlags in redox-driver-sys):
|
||||
# bit 32: DMA_ALT
|
||||
# bit 33: NO_PM_RESET
|
||||
# bit 34: IO_1K
|
||||
# bit 35: NTB_BAR_FIX
|
||||
#
|
||||
# This file targets the 25-30 most AMD64-relevant HEADER fixup entries
|
||||
# out of 255 in Linux 7.1. Skipped entries are listed at the bottom
|
||||
# of the doc/QUIRKS-SYSTEM.md Phase R3 implementation report.
|
||||
#
|
||||
# Phase R4 (2026-06-07) — added `action` field to entries whose Linux
|
||||
# fixup needs imperative config-space writes. Entries that are pure
|
||||
# flag-markers (NO_PM_RESET) remain action-less.
|
||||
|
||||
# ============================================================================
|
||||
# WRONG_CLASS — forces IDE → AHCI class code change at header enumeration
|
||||
# Linux: quirk_amd_ide_mode (drivers/pci/quirks.c)
|
||||
# Reason: AMD Hudson-2 and ATI IXP600/700 SATA controllers report IDE
|
||||
# class (0x0101) when wired in IDE compatibility mode, which causes
|
||||
# the wrong driver to bind. The fixup rewrites the class code to
|
||||
# 0x0106 (SATA) so AHCI driver attaches.
|
||||
# Flag: WRONG_CLASS (bit 19, from R0) — signal that class has been
|
||||
# rewritten and downstream drivers should re-read.
|
||||
# ============================================================================
|
||||
|
||||
# ATI IXP600 SATA IDE controller
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4380
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "amd_ide_class_fix" }
|
||||
|
||||
# ATI IXP700 SATA IDE controller
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4390
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "amd_ide_class_fix" }
|
||||
|
||||
# AMD Hudson-2 SATA IDE
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7800
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "amd_ide_class_fix" }
|
||||
|
||||
# AMD 0x7900 (pre-Hudson FCH) SATA IDE
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7900
|
||||
flags = ["wrong_class"]
|
||||
action = { kind = "callback", name = "amd_ide_class_fix" }
|
||||
|
||||
# ============================================================================
|
||||
# NO_ASPM — disable ASPM L0s on Intel ICH9/10/X58 PCIe endpoints
|
||||
# Linux: quirk_disable_aspm_l0s (drivers/pci/quirks.c)
|
||||
# Reason: certain Intel PCIe devices report ASPM L0s support in the
|
||||
# Link Capabilities register but actually corrupt TLP data when L0s
|
||||
# is enabled. The fixup clears PCI_EXP_LNKCTL_ASPM_L0S (bit 0) of
|
||||
# the Link Control register before driver probe.
|
||||
# Common on Core i5/i7 era boards and X58 workstations.
|
||||
# Flag: NO_ASPM (bit 5, from R0).
|
||||
# ============================================================================
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10A7
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10A9
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10B6
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10C6
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10C7
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10C8
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10D6
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10DB
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10DD
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10E1
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10EC
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10F1
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x10F4
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1508
|
||||
flags = ["no_aspm"]
|
||||
action = { kind = "callback", name = "intel_no_aspm_l0s" }
|
||||
|
||||
# ============================================================================
|
||||
# DMA_ALT — DMA aliasing for bridges and devices that misreport requester ID
|
||||
# Linux: quirk_use_pcie_bridge_dma_alias (drivers/pci/quirks.c)
|
||||
# Reason: certain PCIe-to-PCI bridges (Asmedia, Tundra, ITE, Intel 82801)
|
||||
# forward downstream requester IDs incorrectly during DMA, breaking
|
||||
# IOMMU group assignment and causing DMA faults.
|
||||
# Flag: DMA_ALT (bit 32, Phase R3).
|
||||
# ============================================================================
|
||||
|
||||
# Asmedia ASM1083/1085 PCIe-PCI bridge — 0x1080
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1B21
|
||||
device = 0x1080
|
||||
flags = ["dma_alt", "no_aspm"]
|
||||
action = { kind = "callback", name = "asmedia_func0_dma_alias" }
|
||||
|
||||
# Tundra Semiconductor Tsi384 PCI-X-to-PCI-X bridge — 0x8113
|
||||
# Used on some server platforms.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10E3
|
||||
device = 0x8113
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "tundra_func0_dma_alias" }
|
||||
|
||||
# ITE IT8892 PCIe-PCI bridge
|
||||
# https://bugzilla.kernel.org/show_bug.cgi?id=73551
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1283
|
||||
device = 0x8892
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "ite_func0_dma_alias" }
|
||||
|
||||
# ITE IT8893 — same problem as IT8892
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1283
|
||||
device = 0x8893
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "ite_func0_dma_alias" }
|
||||
|
||||
# Intel 82801 ICH8/9/10 PCIe root port — 0x244e
|
||||
# https://bugzilla.kernel.org/show_bug.cgi?id=44881#c49
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x244E
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "intel_bridge_dma_alias" }
|
||||
|
||||
# ============================================================================
|
||||
# DMA_ALT — function-0 DMA alias
|
||||
# Linux: quirk_dma_func0_alias (drivers/pci/quirks.c)
|
||||
# Reason: certain multi-function devices (Ricoh card readers, Glenfly
|
||||
# GPUs) report their requester ID as function 0 regardless of which
|
||||
# function initiated the DMA. This breaks device isolation in IOMMU
|
||||
# groups. The fixup registers a function-0 alias.
|
||||
# ============================================================================
|
||||
|
||||
# Ricoh R5C832 card reader
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1180
|
||||
device = 0xE832
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "ricoh_func0_dma_alias" }
|
||||
|
||||
# Ricoh R5C476 card reader
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1180
|
||||
device = 0xE476
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "ricoh_func0_dma_alias" }
|
||||
|
||||
# Glenfly GFX display adapter — function 0
|
||||
[[pci_quirk]]
|
||||
vendor = 0x6766
|
||||
device = 0x3D40
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "glenfly_func0_dma_alias" }
|
||||
|
||||
# Glenfly GFX display adapter — function 1
|
||||
[[pci_quirk]]
|
||||
vendor = 0x6766
|
||||
device = 0x3D41
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "glenfly_func0_dma_alias" }
|
||||
|
||||
# ============================================================================
|
||||
# DMA_ALT — fixed DMA alias
|
||||
# Linux: quirk_fixed_dma_alias (drivers/pci/quirks.c)
|
||||
# Reason: Adaptec Series 2 RAID/HBA does not implement the standard
|
||||
# function-level DMA aliasing. A fixed alias is registered based on
|
||||
# a static lookup table.
|
||||
# ============================================================================
|
||||
|
||||
# Adaptec Series 2 (0x9005/0x0285)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x9005
|
||||
device = 0x0285
|
||||
flags = ["dma_alt"]
|
||||
action = { kind = "callback", name = "adaptec2_func0_dma_alias" }
|
||||
|
||||
# ============================================================================
|
||||
# NO_PM_RESET — Mellanox adapters that hang on PM reset
|
||||
# Linux: quirk_no_pm_reset (drivers/pci/quirks.c)
|
||||
# Reason: Mellanox ConnectX-3 and ConnectX-4 adapters report PCI PM
|
||||
# reset capability but actually hang when PM reset is asserted.
|
||||
# The fixup clears the PM reset capability bit.
|
||||
# Flag: NO_PM_RESET (bit 33, Phase R3).
|
||||
# ============================================================================
|
||||
|
||||
# Mellanox ConnectX-3 (0xcb84)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15B3
|
||||
device = 0xCB84
|
||||
flags = ["no_pm_reset"]
|
||||
|
||||
# Mellanox ConnectX-3 Pro (0xcf6c)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15B3
|
||||
device = 0xCF6C
|
||||
flags = ["no_pm_reset"]
|
||||
|
||||
# Mellanox ConnectX-4 (0xcf70)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15B3
|
||||
device = 0xCF70
|
||||
flags = ["no_pm_reset"]
|
||||
|
||||
# Mellanox ConnectX-4 Lx (0xcf80)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15B3
|
||||
device = 0xCF80
|
||||
flags = ["no_pm_reset"]
|
||||
|
||||
# ============================================================================
|
||||
# MSI mapping enable on HyperTransport bridges
|
||||
# Linux: ht_enable_msi_mapping (drivers/pci/quirks.c)
|
||||
# Reason: ServerWorks HT1000 PXB and AMD 8132 bridges do not enable
|
||||
# MSI mapping in their PCI config space by default, which blocks
|
||||
# downstream devices from using MSI/MSI-X.
|
||||
# The fixup forces the HT MSI mapping capability bit on.
|
||||
# Flag: NO_MSI (bit 0) is the inverse — used to signal that MSI is
|
||||
# not yet usable until the HT mapping fixup completes.
|
||||
# ============================================================================
|
||||
|
||||
# ServerWorks HT1000 PCI-X Bridge
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1166
|
||||
device = 0x0036
|
||||
flags = ["no_msi"]
|
||||
action = { kind = "callback", name = "ht_enable_msi_mapping" }
|
||||
|
||||
# AMD 8132 PCI-X Bridge
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7458
|
||||
flags = ["no_msi"]
|
||||
action = { kind = "callback", name = "ht_enable_msi_mapping" }
|
||||
|
||||
# ============================================================================
|
||||
# IO_1K — Intel P64H2 1K I/O granularity enable
|
||||
# Linux: quirk_p64h2_1k_io (drivers/pci/quirks.c)
|
||||
# Reason: Intel P64H2 is a server-class PCIe switch that requires
|
||||
# I/O space allocated at 1 KB granularity (not the 4 KB default)
|
||||
# for downstream devices. The fixup sets the 1K bit.
|
||||
# Flag: IO_1K (bit 34, Phase R3).
|
||||
# ============================================================================
|
||||
|
||||
# Intel P64H2 PCI Express-to-PCI/PCI-X Bridge
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1460
|
||||
flags = ["io_1k"]
|
||||
action = { kind = "callback", name = "p64h2_1k_io" }
|
||||
|
||||
# ============================================================================
|
||||
# NTB_BAR_FIX — Intel Ivytown NTB BAR size misreport fix
|
||||
# Linux: quirk_intel_ntb (drivers/pci/quirks.c)
|
||||
# Reason: Intel Sandy Bridge Xeon NTB (Non-Transparent Bridge) hardware
|
||||
# reports incorrect BAR sizes in the NTB config space. The fixup
|
||||
# forces a PCI_COMMAND_MEMORY toggle so the driver re-evaluates with
|
||||
# corrected sizes.
|
||||
# Flag: NTB_BAR_FIX (bit 35, Phase R3).
|
||||
# Action: intel_ntb_bar_fix (Phase R4) — imperative callback.
|
||||
# ============================================================================
|
||||
|
||||
# Intel Xeon E5 NTB primary — 0x0e08
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x0E08
|
||||
flags = ["ntb_bar_fix"]
|
||||
action = { kind = "callback", name = "intel_ntb_bar_fix" }
|
||||
|
||||
# Intel Xeon E5 NTB secondary — 0x0e0d
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x0E0D
|
||||
flags = ["ntb_bar_fix"]
|
||||
action = { kind = "callback", name = "intel_ntb_bar_fix" }
|
||||
@@ -0,0 +1,472 @@
|
||||
# Phase R5 (2026-06-07) — PCI Final Fixup entries mined from Linux 7.1
|
||||
# Source: Linux 7.1 drivers/pci/quirks.c, DECLARE_PCI_FIXUP_FINAL() macros
|
||||
#
|
||||
# Flag bit map (see PciQuirkFlags in redox-driver-sys):
|
||||
# bit 36: BROKEN_INTX_MASKING (quirk_broken_intx_masking)
|
||||
# bit 37: NO_PME (pci_fixup_no_d0_pme, pci_fixup_no_msi_no_pme)
|
||||
# bit 38: PCI_PROBLEM_FAIL (pci_pci_problems PCIPCI_FAIL)
|
||||
# bit 39: PCI_PROBLEM_TRITON (pci_pci_problems PCIPCI_TRITON)
|
||||
# bit 40: PCI_PROBLEM_NATOMA (pci_pci_problems PCIPCI_NATOMA)
|
||||
# bit 41: PCI_PROBLEM_VIAETBF (pci_pci_problems PCIPCI_VIAETBF)
|
||||
# bit 42: PCI_PROBLEM_VSFX (pci_pci_problems PCIPCI_VSFX)
|
||||
# bit 43: PCI_PROBLEM_ALIMAGIK (pci_pci_problems PCIPCI_ALIMAGIK)
|
||||
# bit 44: PCI_AGP_FAIL (pci_pci_problems PCIAGP_FAIL)
|
||||
# bit 45: BUS_NO_MMRBC (quirk_amd_8131_mmrbc; subordinate bus flag)
|
||||
#
|
||||
# This file targets the 50 most AMD64-relevant FINAL fixup entries
|
||||
# out of 233 in Linux 7.1. Deferred entries (NEEDS_INFRA / PM /
|
||||
# device-tree) are listed in the doc/QUIRKS-SYSTEM.md Phase R5 report.
|
||||
#
|
||||
# Categories:
|
||||
# 1. PCI bridge aliasing and forwarding quirks (config-RMW)
|
||||
# 2. BAR sizing and resource allocation fixes (callbacks)
|
||||
# 3. DMA address mask / MSI disable quirks (flag-setters)
|
||||
# 4. Device-specific post-enumeration workarounds
|
||||
|
||||
# ============================================================================
|
||||
# Category 1 — PCI bridge aliasing and forwarding (config-space RMW)
|
||||
#
|
||||
# These handlers do a single config-space read-modify-write, so they are
|
||||
# expressed directly as inline `QuirkAction::ClearBit` / `SetBit` actions.
|
||||
# No callback is needed.
|
||||
# ============================================================================
|
||||
|
||||
# Mellanox Tavor (T2) — pci_disable_parity.
|
||||
# Linux quirk clears PCI_COMMAND_PARITY (bit 6 of offset 0x04) because
|
||||
# the device raises spurious parity errors that flood the AER log.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15b3
|
||||
device = 0x1007
|
||||
flags = []
|
||||
action = { kind = "clear_bit", offset = 0x04, width = "word", bit = 6 }
|
||||
|
||||
# Mellanox Tavor Bridge
|
||||
[[pci_quirk]]
|
||||
vendor = 0x15b3
|
||||
device = 0x1008
|
||||
flags = []
|
||||
action = { kind = "clear_bit", offset = 0x04, width = "word", bit = 6 }
|
||||
|
||||
# Cyrix PCI Master — quirk_mediagx_master.
|
||||
# Linux clears bit 1 of byte 0x41 to disable bus-master retries that
|
||||
# hang the MediaGX northbridge. rev-gated; only applies to rev 0x00.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x110a
|
||||
device = 0x0001
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x00
|
||||
flags = []
|
||||
action = { kind = "clear_bit", offset = 0x41, width = "byte", bit = 1 }
|
||||
|
||||
# Intel 82454NX PXB — quirk_disable_pxb.
|
||||
# Linux clears bit 6 of word 0x40 only for rev 0x04 (erratum 3).
|
||||
# Other revisions of the same device ID do not need the fixup.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x84cb
|
||||
revision_lo = 0x04
|
||||
revision_hi = 0x04
|
||||
flags = []
|
||||
action = { kind = "clear_bit", offset = 0x40, width = "word", bit = 6 }
|
||||
|
||||
# VIA VT8237 — quirk_via_vt8237_bypass_apic_deassert.
|
||||
# Linux sets bit 3 of byte 0x5B to bypass APIC de-assert, which is
|
||||
# required for the integrated APIC to function under IO-APIC mode.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1106
|
||||
device = 0x3227
|
||||
flags = []
|
||||
action = { kind = "set_bit", offset = 0x5B, width = "byte", bit = 3 }
|
||||
|
||||
# ============================================================================
|
||||
# Category 2 — BAR sizing and resource allocation fixes (callbacks)
|
||||
#
|
||||
# These require callbacks because they are multi-register writes
|
||||
# (AMD FE Gate) or rev-gated (AMD 8131 MMRBC).
|
||||
# ============================================================================
|
||||
|
||||
# AMD-762 northbridge — quirk_amd_ordering.
|
||||
# Enables posted-write ordering via two config-space writes (0x4C |= 6,
|
||||
# 0x84 |= 0x800000). Without this fix, posted writes can complete out
|
||||
# of order, corrupting scatter-gather DMA buffers.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x700C
|
||||
flags = []
|
||||
action = { kind = "callback", name = "amd_fe_gate_ordering" }
|
||||
|
||||
# AMD 8131 PCI-X bridge — quirk_amd_8131_mmrbc.
|
||||
# Rev ≤ 0x12 has a PCI-X MMRBC bug. The Linux fix sets
|
||||
# PCI_BUS_FLAGS_NO_MMRBC on the subordinate bus. Red Bear has no bus
|
||||
# property type, so we model it as a device-level `bus_no_mmrbc` flag
|
||||
# that the PCI scheme daemon checks before honoring MMRBC.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7450
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x12
|
||||
flags = ["bus_no_mmrbc"]
|
||||
action = { kind = "callback", name = "amd_8131_mmrbc" }
|
||||
|
||||
# ============================================================================
|
||||
# Category 3 — DMA / MSI disable quirks (flag-setters via existing NO_MSI)
|
||||
#
|
||||
# These handlers only set a dev->no_msi flag, so they translate to the
|
||||
# existing `no_msi` PciQuirkFlags bit.
|
||||
# ============================================================================
|
||||
|
||||
# ATI SBx00 southbridge (6 device IDs) — quirk_no_msi.
|
||||
# SBx00 chipsets have a known MSI hardware defect; Linux forces
|
||||
# legacy IRQ for the SMBus/audio functions.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4386
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4387
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4388
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4389
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x438a
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x438b
|
||||
flags = ["no_msi"]
|
||||
|
||||
# Intel E7520/E7320/E7525 Memory Controller Hubs — quirk_pcie_mch.
|
||||
# These MCHs have DMA alias issues with the IOMMU; Linux disables
|
||||
# MSI as a side-effect of the workaround.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x3590
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x3592
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x359e
|
||||
flags = ["no_msi"]
|
||||
|
||||
# ============================================================================
|
||||
# Category 4 — Device-specific post-enumeration workarounds
|
||||
# ============================================================================
|
||||
|
||||
# --- NO_ATS: AMD harvest / dGPUs that cannot use Address Translation ---
|
||||
|
||||
# AMD Stoney Ridge dGPU
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x98e4
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Iceland dGPU
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x6900
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Navi10 (RX 5000 series) — five device IDs
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7310
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7312
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7318
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7319
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731a
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731b
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731e
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731f
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Navi14 (RX 5500 series)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7340
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7341
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7347
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x734f
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Raven Ridge dGPU
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x15d8
|
||||
flags = ["no_ats"]
|
||||
|
||||
# Intel IPU E2000 — quirk_intel_e2000_no_ats.
|
||||
# Rev < 0x20 of the IPU has broken ATS support. Linux disables ATS
|
||||
# before driver init; the rev gate prevents the fix from triggering
|
||||
# on later silicon that has working ATS.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1451
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x1f
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1452
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x1f
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1453
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x1f
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1454
|
||||
revision_lo = 0x00
|
||||
revision_hi = 0x1f
|
||||
flags = ["no_ats"]
|
||||
|
||||
# --- BROKEN_INTX_MASKING: devices that advertise MSI masking but the
|
||||
# bit is non-functional. Driver must fall back to MSI-X.
|
||||
|
||||
# Chelsio T3 1GbE
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1425
|
||||
device = 0x0030
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# Ralink RT2800 802.11n
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1814
|
||||
device = 0x0601
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# Ceton InfiniTV4
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1b7c
|
||||
device = 0x0004
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# Creative SB20K2
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1102
|
||||
device = 0x000B
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# Realtek RTL8169
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10ec
|
||||
device = 0x8169
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# Intel i40e XL710/X710 family (representative subset of 16 IDs)
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1572
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1574
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1580
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x37d2
|
||||
flags = ["broken_intx_masking"]
|
||||
|
||||
# --- NO_PME: devices that advertise PME from D0 but cannot actually wake ---
|
||||
|
||||
# Asmedia ASM2142 USB 3.1 controller — pci_fixup_no_d0_pme.
|
||||
# The controller's D0 PME state is broken; clearing it prevents
|
||||
# spurious wake events.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1b21
|
||||
device = 0x2142
|
||||
flags = ["no_pme"]
|
||||
|
||||
# Pericom PI7C9X — pci_fixup_no_msi_no_pme.
|
||||
# Both MSI and PME are broken; the driver falls back to legacy IRQ
|
||||
# and ignores D0 wake.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x12D8
|
||||
device = 0x400e
|
||||
flags = ["no_msi", "no_pme"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x12D8
|
||||
device = 0x400f
|
||||
flags = ["no_msi", "no_pme"]
|
||||
|
||||
# ============================================================================
|
||||
# Category 5 — pci_pci_problems global flags
|
||||
#
|
||||
# Linux's pci_pci_problems is a process-global u32 bitmask. Red Bear
|
||||
# models each problem as an individual PciQuirkFlags bit so consumers
|
||||
# can query them like any other quirk flag.
|
||||
# ============================================================================
|
||||
|
||||
# PCI_PROBLEM_FAIL — SI 5597/496 host bridges. The PCI-PCI bridge
|
||||
# emulation is broken; Linux falls back to conservative timing.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1039
|
||||
device = 0x5597
|
||||
flags = ["pci_problem_fail"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1039
|
||||
device = 0x0496
|
||||
flags = ["pci_problem_fail"]
|
||||
|
||||
# PCI_AGP_FAIL — AMD 8151_0 only when rev 0x13. AGP transactions
|
||||
# corrupt memory on this specific stepping.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1022
|
||||
device = 0x7454
|
||||
revision_lo = 0x13
|
||||
revision_hi = 0x13
|
||||
flags = ["pci_agp_fail"]
|
||||
|
||||
# PCI_PROBLEM_TRITON — Intel 82437/82437VX/82439/82439TX Triton.
|
||||
# Triton northbridges need extra PCI-PCI bridge turn-around cycles.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x122d
|
||||
flags = ["pci_problem_triton"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7030
|
||||
flags = ["pci_problem_triton"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1250
|
||||
flags = ["pci_problem_triton"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7100
|
||||
flags = ["pci_problem_triton"]
|
||||
|
||||
# PCI_PROBLEM_VIAETBF — VIA 82C597_0.
|
||||
# Errata in the ETBF (Early Transaction Buffer) cause livelocks.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1106
|
||||
device = 0x0597
|
||||
flags = ["pci_problem_viaetbf"]
|
||||
|
||||
# PCI_PROBLEM_VSFX — VIA 82C576.
|
||||
# The VSFX (Video Side FX) bridge has broken posted-write ordering.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1106
|
||||
device = 0x0576
|
||||
flags = ["pci_problem_vsfx"]
|
||||
|
||||
# PCI_PROBLEM_ALIMAGIK — ALi M1647 / M1651.
|
||||
# The Aladdin V/V+ northbridges combine ALi-ali-MAGiK and Triton
|
||||
# problems; both bit patterns are needed to disable all fast paths.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10b9
|
||||
device = 0x1647
|
||||
flags = ["pci_problem_alimagik"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x10b9
|
||||
device = 0x1651
|
||||
flags = ["pci_problem_alimagik"]
|
||||
|
||||
# PCI_PROBLEM_NATOMA — Intel 82441 / 82443LX / 82443BX.
|
||||
# The Natoma core needs special PCI-PCI bridge handling.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x1237
|
||||
flags = ["pci_problem_natoma"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7180
|
||||
flags = ["pci_problem_natoma"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7181
|
||||
flags = ["pci_problem_natoma"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7190
|
||||
flags = ["pci_problem_natoma"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7191
|
||||
flags = ["pci_problem_natoma"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x8086
|
||||
device = 0x7192
|
||||
flags = ["pci_problem_natoma"]
|
||||
@@ -1,4 +1,8 @@
|
||||
# GPU display controller quirks.
|
||||
#
|
||||
# Sources: Linux 7.1 drivers/pci/quirks.c, drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
||||
# Policy: Only add entries for hardware Red Bear targets (2020+ AMD/Intel GPUs).
|
||||
# Review-gate each entry on Linux-backed evidence.
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
@@ -15,6 +19,72 @@ vendor = 0x10DE
|
||||
class = 0x030000
|
||||
flags = ["no_d3cold", "need_firmware"]
|
||||
|
||||
# AMD Navi 10 variants (0x7310-0x731F) — ATS harvest required
|
||||
# Linux: DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7310, quirk_amd_harvest_no_ats)
|
||||
# These Navi 10 sub-variants have broken ATS (Address Translation Services).
|
||||
# Phase R2 (2026-06-07): converted from no_aspm placeholder to dedicated
|
||||
# no_ats flag (PciQuirkFlags::NO_ATS = 1 << 27).
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7312
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7318
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7319
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731A
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731B
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731E
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x731F
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Navi 14 variants (0x7340, 0x7341, 0x7347, 0x734F) — ATS harvest
|
||||
# Linux: DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats)
|
||||
# Phase R2: converted to no_ats.
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7340
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7341
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x7347
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x734F
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD specific SKU quirks
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x744C
|
||||
@@ -25,6 +95,103 @@ vendor = 0x1002
|
||||
device = 0x73EF
|
||||
flags = ["need_firmware", "dma_32bit_only"]
|
||||
|
||||
# AMD Stoney (0x98E4) and Iceland (0x6900) — ATS harvest
|
||||
# Older GPUs, included for completeness as they may appear in laptops
|
||||
# Phase R2: converted to no_ats.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x98E4
|
||||
flags = ["no_ats"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x6900
|
||||
flags = ["no_ats"]
|
||||
|
||||
# AMD Raven/Renoir (0x15D8) — ATS harvest with subsystem-specific filter
|
||||
# Linux only applies when subsystem_vendor=0xEA50 and specific subsystem_device.
|
||||
# Red Bear applies broadly until subsystem matching is refined.
|
||||
# Phase R2: converted to no_ats.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x15D8
|
||||
flags = ["no_ats"]
|
||||
|
||||
# ATI audio function — MSI broken on ATI SBx00 (0x4386-0x438B, 0x4390-0x4394)
|
||||
# Linux: quirk_no_msi + quirk_disable_all_msi
|
||||
# These are southbridge audio functions, not GPUs, but they share the bus.
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4386
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4387
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4388
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4389
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x438A
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x438B
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4390
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4391
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4392
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4393
|
||||
flags = ["no_msi"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4394
|
||||
flags = ["no_msi"]
|
||||
|
||||
# ATI SBx00 SATA — IDE mode quirk (0x4373-0x4375, IXP600/700 SATA)
|
||||
# Linux: quirk_amd_ide_mode — forces IDE mode on SATA controllers
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4373
|
||||
flags = ["wrong_class"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4374
|
||||
flags = ["wrong_class"]
|
||||
|
||||
[[pci_quirk]]
|
||||
vendor = 0x1002
|
||||
device = 0x4375
|
||||
flags = ["wrong_class"]
|
||||
|
||||
[[usb_quirk]]
|
||||
vendor = 0x0BDA
|
||||
product = 0x8153
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Audio controller and codec quirks.
|
||||
# These apply to HDA controllers and codec devices.
|
||||
#
|
||||
# Phase R2 (2026-06-07) — the audio_force_eapd, audio_single_cmd, and
|
||||
# audio_position_fix_lpib flags are now defined in PciQuirkFlags (bits
|
||||
# 29-31). Prior to R2 these names were silently dropped by the TOML
|
||||
# parser with a warning; they now resolve correctly. Source: Linux 7.1
|
||||
# sound/pci/hda/patch_hdmi.c and sound/pci/hda/hda_intel.c.
|
||||
|
||||
# Intel ICH8 HDA — force EAPD on outputs
|
||||
[[pci_quirk]]
|
||||
|
||||
Reference in New Issue
Block a user