lg-gram-16z90tp: Phase 0 — collision fixes, quirks pipeline, firmware tables

Host: LG Gram 16Z90TP-G.AL89C (Arrow Lake-H, Core Ultra 7 255H).
Plan: local/docs/LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md

- drivers.d: scope e1000d + rtl8168d matches to subclass 0 (Ethernet);
  the vendor+class wildcard also claimed Intel/Realtek Wi-Fi (subclass
  0x80) and collided with redbear-iwlwifi (e.g. BE201 8086:7740)
- xhci_table: add universal SPURIOUS_SUCCESS rule for hci_version > 0x96
  (Linux xhci.c:5477); LG Gram 8086:7ec0/777d now get exactly Linux's
  flag set (0x200009810); flag-parity test added
- quirks: repair system-quirk pipeline — dmi_system_quirk entries with
  flags like force_s2idle silently parsed to empty sets. Add
  SystemQuirkFlags (4 flags), DmiSystemQuirkRule, dual-namespace TOML
  parsing, quirks::system_quirks() consumer API, and the LG 16Z90TP
  DMI anchor (board_name match)
- firmware: iwlwifi candidate tables prefer the c-prefixed iwlmld
  series (c106..c101) for BE201/CNVi; gf-a0 capped at 100 per
  host/linux-firmware evidence; fallback chains updated
- firmware-loader: map flat iwlwifi-* requests into the post-2026
  linux-firmware intel/iwlwifi/ layout (builtins + TOML fallbacks)

Tests: redox-driver-sys 72, firmware-loader 11, redbear-iwlwifi 8,
redbear-wifictl 21 all pass; all four components cook for
x86_64-unknown-redox; make lint-config clean.
This commit is contained in:
2026-07-20 23:41:18 +09:00
parent c89898f1f4
commit 8060a9640b
11 changed files with 965 additions and 27 deletions
+278
View File
@@ -28,6 +28,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -66,6 +83,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -100,6 +134,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -174,6 +225,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -198,6 +266,10 @@ command = ["/usr/lib/drivers/e1000d"]
[[driver.match]]
vendor = 0x8086
class = 2
# Ethernet only (subclass 0x00) — without this filter the wildcard also claims
# Intel Wi-Fi (class 0x02 subclass 0x80, e.g. BE201 8086:7740) and collides with
# redbear-iwlwifi. Same defect class fixed for rtl8168d below.
subclass = 0
[[driver]]
name = "rtl8168d"
@@ -208,6 +280,8 @@ command = ["/usr/lib/drivers/rtl8168d"]
[[driver.match]]
vendor = 0x10EC
class = 2
# Realtek also ships class 0x02 subclass 0x80 Wi-Fi (RTL8852 etc.) — scope to Ethernet.
subclass = 0
[[driver]]
name = "rtl8139d"
@@ -257,6 +331,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -336,6 +427,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -386,6 +494,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -424,6 +549,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -503,6 +645,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -537,6 +696,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -571,6 +747,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -614,6 +807,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -648,6 +858,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -688,6 +915,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -728,6 +972,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
@@ -768,6 +1029,23 @@ chain = ["amdgpu/dmcub_dcn20.bin"]
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-100.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-94.ucode", "iwlwifi-bz-b0-gf-a0-92.ucode", "iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
[[fallback]]
pattern = "iwlwifi-bz-b0-fm-c0-c106.ucode"
chain = ["iwlwifi-bz-b0-fm-c0-c105.ucode", "iwlwifi-bz-b0-fm-c0-c104.ucode", "iwlwifi-bz-b0-fm-c0-c103.ucode", "iwlwifi-bz-b0-fm-c0-c102.ucode", "iwlwifi-bz-b0-fm-c0-c101.ucode", "iwlwifi-bz-b0-fm-c0-101.ucode", "iwlwifi-bz-b0-fm-c0-100.ucode", "iwlwifi-bz-b0-fm-c0-94.ucode", "iwlwifi-bz-b0-fm-c0-92.ucode"]
# linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026.
[[fallback]]
pattern = "iwlwifi-*.ucode"
chain = ["intel/iwlwifi/iwlwifi-*.ucode"]
[[fallback]]
pattern = "iwlwifi-*.pnvm"
chain = ["intel/iwlwifi/iwlwifi-*.pnvm"]
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
+6
View File
@@ -9,6 +9,10 @@ command = ["/usr/lib/drivers/e1000d"]
[[driver.match]]
vendor = 0x8086
class = 2
# Ethernet only (subclass 0x00) — without this filter the wildcard also claims
# Intel Wi-Fi (class 0x02 subclass 0x80, e.g. BE201 8086:7740) and collides with
# redbear-iwlwifi. Same defect class fixed for rtl8168d below.
subclass = 0
[[driver]]
name = "rtl8168d"
@@ -19,6 +23,8 @@ command = ["/usr/lib/drivers/rtl8168d"]
[[driver.match]]
vendor = 0x10EC
class = 2
# Realtek also ships class 0x02 subclass 0x80 Wi-Fi (RTL8852 etc.) — scope to Ethernet.
subclass = 0
[[driver]]
name = "rtl8139d"
@@ -0,0 +1,337 @@
# LG Gram 16Z90TP-G.AL89C — Host Compatibility Plan
**Created:** 2026-07-20
**Status:** Planning — no implementation started
**Source evidence:** Host dmesg (Linux 7.1.3-1-MANJARO), six-point codebase recon
(drivers/PCI-ID inventory, redox-drm Intel state, redbear-iwlwifi state, IOMMU/kernel
state, ACPI/power state, USB/input/audio state)
**Host class:** Modern Intel laptop (Arrow Lake-H), first-class bare-metal target
---
## 1. Host Profile
| Property | Value |
|---|---|
| Model | LG Electronics 16Z90TP-G.AL89C (2025) |
| BIOS | Phoenix A1ZJ3000 X64, 2024-12-26, UEFI 2.7, Secure Boot **off** |
| CPU | Intel Core Ultra 7 255H (Arrow Lake-H), family 0x6 model 0xC5, 16 cores (hybrid P/E/LP-E), x2APIC, TSC 3.69 GHz, HWP, TM1, CET/IBT |
| RAM | 32 GB |
| GPU | Intel Meteor Lake graphics [8086:7d51], display version 14.00, VT-d active |
| Storage | SK Hynix NVMe [1c5c:1959] (nvme0, 16 queues) |
| Wi-Fi | Intel Wi-Fi 7 BE201 320MHz [8086:7740] CNVi (crf 0x2001910, cnv 0x80930), fw `bz-b0-fm-c0-c102.ucode`, **op_mode iwlmld** |
| Bluetooth | Intel [8087:0037] (USB-attached CNVi BT), fw `ibt-0093-0291.sfi` + `.ddc` |
| Audio | HDA [8086:7728] via **SOF/cAVS** (sof-arl.ri, IPC4, ALC298 codec, 2× DMIC, HDMI) |
| USB | xHCI ×2: [8086:7ec0] (USB4-adjacent), [8086:777d]; Linux quirks `0x200009810` |
| Input | PS/2 i8042 keyboard (AUX **disabled**); I2C-HID multitouch touchpad 04CA:00CC on LPSS DesignWare I2C [8086:7778/7779] |
| Camera | UVC 1.50 [30c9:00f2] |
| IOMMU | Intel VT-d, 2× DRHD (0xfc800000/0xfc801000), IRQ remapping, **force-enabled by platform** |
| Power | EC at 0x66/0x62 (GPE 0x6e), BAT0, ADP1, lid, sleep/power buttons, thermal zone, fan PNP0C0B, **S0ix only (LPIT; no S3)**, LG WMI, TPM2 |
| Misc PCI | LPC 8086:7702, SMBus 8086:7722, SPI 8086:7723, UART 8086:7745, MEI 8086:7770, GNA 8086:774c, VPU/NPU 8086:7d1d, proc-thermal 8086:7d03, PMC telemetry 8086:777f, ISH 8087:0AC2 |
| Notable quirks | HPET dysfunctional in PC10 (Linux force-disables); no wired Ethernet — **Wi-Fi is the only network device** |
---
## 2. Device-by-Device Support Matrix (dmesg vs. codebase recon)
Legend: ✅ = expected to work today (code match + mature path) · 🟡 = code exists, gap or unproven · ❌ = no support
| Device | ID | Red Bear component | Verdict | Evidence |
|---|---|---|---|---|
| UEFI boot | — | bootloader fork | ✅ | Standard Phoenix UEFI 2.7; boot proven on AMD/Intel bare metal |
| CPU/SMP | 0x6/0xC5 | kernel x2APIC dual-path | ✅ | `local_apic.rs` x2 via CPUID; 16-core boot expected |
| HPET | — | kernel | ✅ (n/a) | Redox uses LAPIC/TSC timers; HPET-dysfunctional quirk harmless |
| NVMe | 1c5c:1959 | `nvmed` (class 1/8) | ✅ | Class-based match; initfs-capable |
| xHCI ×2 | 8086:7ec0, 8086:777d | `xhcid` | ✅→🟡 | Class match 0x0C/0x03/0x30 + Intel baseline quirks; 7ec0 (USB4-adjacent) has no specific quirk entry; unvalidated on HW |
| PS/2 keyboard | i8042 | kernel `serio` + `ps2d` | ✅ | AUX-disabled handled (`test_aux_port``SECOND_DISABLED`); QEMU + BM proven |
| VESA console | — | `vesad`+`fbcond` | ✅ | Boot framebuffer path, always present |
| iGPU | 8086:7d51 | `redox-drm` Intel | 🟡 | 0x7D51 **is** in `INTEL_GEN12_MTL_IDS`; but display init assumes Gen8-era register layout; DMC preload gated but **never loaded to HW**; no GuC/HuC |
| Legacy iGPU fb | 8086:7d51 | `ihdgd` | 🟡 | Also claims 0x7D51 — priority vs redox-drm must be enforced |
| Wi-Fi BE201 | 8086:7740 | `redbear-iwlwifi` | 🟡→❌ | ID in table, fw family correct (`bz-b0-fm-c0`), **but** Mini-MVM is iwlmvm-era and BE201 needs **iwlmld**; fw API 102 vs expected 92100; zero HW validation |
| BT | 8087:0037 | `redbear-btusb` | 🟡 | Recipe exists (bounded BLE slice); Intel bootload/fw-load (sfi+ddc) untested |
| Audio HDA | 8086:7728 | `ihdad` | ❌ (arch) | Class-matched and will probe, but cAVS/SOF platform — legacy HDA cannot reach ALC298 behind the DSP; needs SOF port |
| USB audio (dongle) | — | `redbear-usbaudiod` | ✅ (interim) | UAC1 full impl; viable interim audio |
| Touchpad | 04CA:00CC | `intel-lpss-i2cd`/`dw-acpi-i2cd` + `i2c-hidd` | 🟡 | Chain compiles; controller ACPI HID likely **not in any SUPPORTED_IDS**; no BM validation; single-touch parsing only |
| I2C controllers | 8086:7778/7779 | same | 🟡 | ACPI-HID matching may miss Arrow Lake HIDs; PCI-ID fallback matching absent |
| Camera | 30c9:00f2 | — | ❌ | No UVC driver anywhere |
| Battery/AC | BAT0/ADP1 | `acpid` AML `_BST`/`_PSR` | 🟡 | Polling works; **no event notifications** (no GPE) |
| Lid/buttons | PNP0C0D/C/E | — | ❌ | Zero lid code; button GPE re-enable documented as caller's job |
| GPE/EC events | GPE 0x6e | `acpid`/`ec.rs` | ❌ | EC byte protocol exists; no GPE dispatch, no QR_EC loop |
| Thermal zones | TZ00 | `acpid`+`thermald` | 🟡 | `_TMP`/`_PSV`/`_CRT` + passive cooling via cpufreq works; fan is soft-model only |
| CPU freq | ARL-H | `cpufreqd` HWP/EPP | ✅ | Code explicitly notes Arrow Lake-H HWP; MSR path generic |
| CPU temp/RAPL | — | `coretempd`, `redbear-power` | ✅ | MSR 0x19C/0x1A2/0x606+; no model gating needed |
| Suspend | S0ix/LPIT | `acpid` s2idle | 🟡→❌ | Prep sequence exists; **no LPIT parser, MWAIT loop unwired, no _PRW wake mgmt**; S3 absent on this host |
| Shutdown/reboot | S5/reset | `acpid`/kernel | ✅ | Implemented; robustness tracked in ACPI-IMPROVEMENT-PLAN |
| IOMMU (VT-d) | DMAR | `iommu` daemon | ✅ (safe no-op) | AMD-Vi only; detects DMAR, logs, registers empty scheme; **do not set REDBEAR_DMAR_INIT=1** (gl_sts hang risk) |
| LPC/SMBus/SPI/UART/MEI/GNA/VPU/PMC/ISH/TPM | various | — | ❌ | No drivers; none are boot-critical |
| LG WMI hotkeys | — | — | ❌ | No WMI subsystem |
| USB-C eth dongle (interim net) | — | `redbear-ecmd` | ✅ (interim) | CDC-ECM driver exists — **only viable interim network path** (no wired NIC on host) |
### 2.1 Critical config-level defect found during recon
**e1000d wildcard collision.** `local/config/drivers.d/10-network.toml` matches
`vendor=0x8086 class=2` with no subclass filter → on this host it would claim the
BE201 Wi-Fi (class 0x02 subclass 0x80) and collide with `redbear-iwlwifi`.
The pcid-side `e1000d/config.toml` whitelist is correct; the driver-manager entry
is too broad. **Must fix (Phase 0) — add `subclass = 0x00`.**
### 2.2 Known non-issues (verified, do not re-investigate)
- VT-d force-enabled: harmless — `iommu` daemon is a clean no-op on DMAR-only machines.
- HPET dysfunctional: kernel timers don't need HPET.
- AUX port disabled: `ps2d` handles it.
- PCI root ports/LPC/host bridge: bus-layer devices, no userspace driver needed by design.
- x2APIC: fully supported; IRQ remapping absence does not block MSI/MSI-X delivery.
---
## 3. Boot Path Analysis (redbear-mini on this host)
```
UEFI 2.7 (Phoenix) → Red Bear bootloader (✅ expected)
→ kernel: x2APIC detect (✅), 16-core SMP (✅), MADT (✅), MCFG ECAM 0xC0000000 (✅)
→ initfs: pcid → nvmed (✅ SK Hynix) → rootfs mount (✅)
→ vesad + fbcond console (✅)
→ pcid-spawner + driver-manager:
xhcid ×2 (✅ class match, Intel baseline quirks — watch 7ec0)
ps2d (✅)
ihdad (🟡 probes, finds no usable codec — must fail gracefully, not hang)
redbear-iwlwifi (🟡 probes, fw API mismatch likely — must fail gracefully)
e1000d (❌ COLLISION — Phase 0 fix)
→ acpid: RSDP/FADT/DSDT/SSDT/EC (✅), battery/AC poll (🟡), shutdown (✅)
→ cpufreqd HWP (✅), coretempd (✅), thermald (🟡)
→ login prompt (✅ expected) — redbear-mini usable with keyboard + USB-Ethernet dongle
```
Expected first-boot result: **boots to login on VESA console with working keyboard,
NVMe, USB, CPU power management, battery readout, and shutdown — but no touchpad,
no network (without USB dongle), no DRM/KMS, no audio, no suspend.**
---
## 4. Multiphase Plan
Phase ordering respects the canonical subsystem order (IRQ/low-level → USB → Wi-Fi →
BT → desktop) but prioritizes host boot-blockers and the no-wired-NIC reality.
Every phase ends with a validation gate on the **real host** (this machine is
available — that changes everything vs. prior plans blocked on hardware access).
Evidence language per project rules: compile-visible ≠ QEMU-bounded ≠ hardware-validated.
Effort scale: S (<1 week) · M (13 weeks) · L (38 weeks) · XL (8+ weeks)
---
### PHASE 0 — Host bring-up prerequisites (S, config-level, zero risk)
> **STATUS: COMPLETE (2026-07-20).** All items landed; affected components
> cross-compile for `x86_64-unknown-redox`; all host-side test suites pass
> (redox-driver-sys 72, firmware-loader 11, redbear-iwlwifi 8, redbear-wifictl 21).
| # | Work item | Files | Notes |
|---|---|---|---|
| 0.1 | **Fix e1000d wildcard collision** — add `subclass = 0x00` to e1000d match | `local/config/drivers.d/10-network.toml` + embedded copy in `config/redbear-device-services.toml` | ✅ DONE — same defect class also fixed for `rtl8168d` (Realtek ships subclass-0x80 Wi-Fi too) |
| 0.2 | Add DMI quirk-table entry for `LG Electronics 16Z90TP` | `redbear-quirks/source/quirks.d/50-system.toml` | ✅ DONE — **and repaired the whole system-quirk pipeline**: the sibling LG entries' flags (`force_s2idle` etc.) silently parsed to empty sets (unknown names dropped). Added `SystemQuirkFlags` + `DmiSystemQuirkRule` + dual-namespace parsing in `toml_loader.rs` + `quirks::system_quirks()` consumer API in redox-driver-sys. 16Z90TP entry matches on `board_name = "16Z90TP"` (exact-match semantics; product_name carries the SKU suffix) |
| 0.3 | Verify/port xHCI quirks for 8086:7ec0 & 8086:777d — decode Linux `0x200009810` | `redox-driver-sys/source/src/quirks/xhci_table.rs` | ✅ DONE — decoded as `SPURIOUS_SUCCESS \| LPM_SUPPORT \| INTEL_HOST \| AVOID_BEI \| DEFAULT_PM_RUNTIME_ALLOW`. Missing piece was the **universal `hci_version > 0x96 → SPURIOUS_SUCCESS`** rule (Linux `xhci.c:5477`); added it + a flag-parity test pinning the LG Gram controllers to the exact Linux flag set. The `>= 0x120 → DEFAULT_PM_RUNTIME_ALLOW` rule already existed |
| 0.4 | Confirm graphics spawn priority: redox-drm wins over ihdgd for 0x7D51 | `drivers.d/30-graphics.toml`, `pcid.d/intel_gpu.toml`, `redbear-{mini,full}.toml` | ✅ VERIFIED CORRECT — redox-drm Intel entry priority 61 > vesad 60; redbear-mini empties `/etc/pcid.d/ihdgd.toml`; redbear-full overrides it to spawn redox-drm; `/etc/pcid.d` overrides `/usr/lib/pcid.d` via `config_for_dirs()` BTreeMap; base package stages into `/usr/lib/pcid.d` so no layer collision. No change needed |
| 0.5 | Stage firmware blobs | `local/firmware/`, `redbear-iwlwifi/main.rs`, `redbear-wifictl/backend.rs`, `firmware-loader/blob.rs`, `redbear-device-services.toml` | ✅ DONE — staged host-verified blobs (iwlwifi bz-b0-fm-c0 **c101/c102/c103/c106** + pnvm, gf-a0 set, i915/mtl_dmc.bin + guc/huc/gsc, ibt-0093-0291.sfi/.ddc). **Key discovery:** the `c`-prefixed series is the iwlmld firmware — candidate tables rewritten to prefer c106→c101 over the legacy 92101 series. **Fixed firmware path gap:** new linux-firmware ships iwlwifi under `intel/iwlwifi/`; added wildcard path-map to firmware-loader builtins + `/etc/firmware-fallbacks.d/10-iwlwifi.toml`. Image path confirmed: `redbear-firmware` recipe ships the full set (cache has c106) |
**Phase 0 discoveries beyond the original scope (all fixed, none deferred):**
1. `rtl8168d` had the same wildcard collision as e1000d → fixed with the same `subclass = 0` filter.
2. The `[[dmi_system_quirk]]` TOML entries in `50-system.toml` were **dead data** — every system flag silently dropped by the parser, and no consumer API existed. Now a real pipeline: `SystemQuirkFlags``DmiSystemQuirkRule``quirks::system_quirks()` → consumers (acpid/ps2d wiring lands in Phases 45).
3. `integrate-redbear.sh` AMD-only firmware staging into `firmware-loader/source/firmware/amdgpu/` never reaches the image (package ships only the binary) — the real image path is the `redbear-firmware` recipe (full linux-firmware install, local 2.8 GB cache already present). Documented here; the dead staging path is legacy cleanup, not Phase 0 scope.
4. Firmware fallback chains in `redbear-device-services.toml` are embedded 16× (fragment composition); updates must use replace-all edits.
**Gate 0:** ✅ changed components cook successfully for the target;
`redbear-iwlwifi`, `redbear-wifictl`, `firmware-loader`, `redox-driver-sys` all build + publish.
---
### PHASE 1 — Bare-metal boot validation (S, evidence-first)
This host is available — run the existing validation harnesses against it and
record everything. **No code changes in this phase except genuine boot-blocker fixes.**
| # | Work item | How |
|---|---|---|
| 1.1 | Boot `redbear-mini` live ISO on host; capture full boot log to `local/docs/boot-logs/lg-16z90tp-*.log` | USB stick; serial capture if console fails |
| 1.2 | Validate: 16-core SMP, NVMe root, xHCI enumeration (both controllers), PS/2 keyboard, VESA console at native panel resolution, battery/AC readout, HWP P-states, coretemp, ACPI shutdown + reboot | Manual + `redbear-info`, `redbear-ecmd` |
| 1.3 | Validate USB-Ethernet interim networking: CDC-ECM dongle → `redbear-ecmd` → DHCP | `redbear-netctl` |
| 1.4 | Run bounded low-level controller proofs (MSI-X, xHCI IRQ, PS/2, timer) | `local/scripts/test-lowlevel-controllers-qemu.sh` analogues on BM; record results |
| 1.5 | Add host entry to `local/docs/HARDWARE-VALIDATION-MATRIX.md` with honest evidence levels | Per row: compile / QEMU / BM-validated |
| 1.6 | Fix only true boot-blockers discovered (root-cause fixes per ABSOLUTE RULE) | Triage as found |
**Gate 1:** redbear-mini boots to login on the host with keyboard + NVMe + USB +
shutdown/reboot verified. This is the " minimally usable " milestone.
---
### PHASE 2 — CPU & platform power validation (SM)
| # | Work item | Files | Effort |
|---|---|---|---|
| 2.1 | Validate `cpufreqd` HWP on ARL-H: governor switching, EPP hints, per-core HWP_REQUEST | `local/recipes/system/cpufreqd/` | S |
| 2.2 | Validate RAPL domains (pkg/pp0/pp1/dram/platform) in `redbear-power`; check 0x64D platform energy on ARL | `redbear-power/source/src/msr.rs` | S |
| 2.3 | Validate `coretempd` + `thermald` passive cooling loop under load (stress via cub builds) | thermald + cpufreqd integration | S |
| 2.4 | Hybrid topology: feed CPUID leaf 0x1A P/E/LP-E classification (exists in redbear-power) into cpufreqd per-cluster governor policy | `cpufreqd`, `redbear-power/cpuid.rs` | M |
| 2.5 | Serial console bring-up via DBG2 16550 (0x3f8) for headless debugging of later phases | kernel/boot config | S |
**Gate 2:** `redbear-power` shows correct per-cluster frequencies, temps, RAPL power;
thermal throttling engages and recovers under sustained load.
---
### PHASE 3 — Display: VESA → DRM/KMS on Meteor Lake (L, critical path for desktop)
Follows `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` Workstream C.
| # | Work item | Files | Effort |
|---|---|---|---|
| 3.1 | Validate vesad at native panel mode (eDP; likely 2560×1600); confirm fbcond + any framebuffer consumers | vesad/bootloader EDID handoff | S |
| 3.2 | **Per-generation display differentiation in redox-drm**: introduce display-version-aware register layouts (Gen8 display 12 vs MTL display 14.00). Reference: `local/reference/linux-7.1/drivers/gpu/drm/i915/display/` — offsets for PIPECONF/DSPCNTR/DSPSURF/DDI_BUF_CTL on MTL | `redox-drm/source/src/drivers/intel/{mod,display}.rs` | L |
| 3.3 | Real connector/EDID bring-up on eDP: GMBUS read at panel; bounded modeset proof via `redbear-drm-display-check` on the host | display.rs + test-drm-display-runtime.sh | M |
| 3.4 | **DMC firmware load sequence**: CSS header parse, DMA-to-DMC-store, DC state enable — port from Linux i915 `intel_dmc.c`. Consume the already-preloaded `mtl_dmc.bin` | `intel/mod.rs`, new `intel/dmc.rs`; firmware-loader | ML |
| 3.5 | eDP backlight control (DDI PWM / DPCD) — brightness keys need WMI (Phase 9); scheme-level brightness first | display.rs / new backlight module | M |
| 3.6 | GuC/HuC/GSC: manifest entries now, load sequences **deferred** (render path, not display blocker). Document as convergence work in DRM plan | `main.rs` firmware keys | S (manifest only) |
**Gate 3:** `redox-drm` drives the internal panel at native resolution with correct
EDID modeset + page flips on the host; vesad remains as fallback. **This unblocks the
whole desktop path (Qt6/KWin) on this machine.**
---
### PHASE 4 — Touchpad: I2C-HID chain bring-up (M)
| # | Work item | Files | Effort |
|---|---|---|---|
| 4.1 | Identify actual ACPI `_HID` of the two LPSS I2C controllers on the host (`/sys/bus/acpi/devices/*/hid` under Linux); add to `SUPPORTED_IDS` of the right driver (`intel-lpss-i2cd` or `dw-acpi-i2cd`). If the platform exposes them PCI-only, add PCI-ID (8086:7778/7779) matching as a complement to ACPI-HID matching | `local/sources/base/drivers/i2c/*` | S |
| 4.2 | Controller bring-up: BAR/IRQ from `_CRS`, DesignWare init sequence, bus speed from ACPI; validate register-level transactions against Linux `i2c-designware` behavior | same | M |
| 4.3 | `i2c-hidd`: probe 04CA:00CC (PNP0C50), `_DSM` HID descriptor, report descriptor fetch; IRQ line via `_CRS` (GPIO/IRQ resource → `/scheme/irq`) | `local/sources/base/drivers/input/i2c-hidd/` | M |
| 4.4 | Multitouch digitizer report parsing (ABS_MT_* slots, tracking IDs) + forwarding through inputd → evdevd gesture module | `i2c-hidd/hid.rs`, `evdevd/gesture.rs` | M |
| 4.5 | Host validation: pointer, click, two-finger scroll; palm-rejection tuning | — | S |
**Gate 4:** Touchpad fully usable on host (pointer + multitouch scroll + click).
---
### PHASE 5 — Laptop ACPI events: GPE/EC/lid/buttons (ML)
This phase removes the biggest "not a real laptop" gap: event-driven power state.
| # | Work item | Files | Effort |
|---|---|---|---|
| 5.1 | **GPE dispatch infrastructure in acpid**: SCI via `/scheme/irq` (ACPI `sci_int` from FADT), GPE status/enable block access, per-GPE handler registry | `local/sources/base/drivers/acpid/src/{main,acpi}.rs` | L |
| 5.2 | EC event loop: `SCI_EVT` poll/IRQ → `QR_EC` query → dispatch `_Qxx` AML methods; wire battery/AC change notifications (`\_SB.BAT0` notify 0x80) | `acpid/ec.rs`, new `acpid/gpe.rs` | M |
| 5.3 | Lid switch (PNP0C0D `_LID`) + power/sleep fixed events (PM1_STS PWRBTN/SLPBTN) → scheme surfaces + kstop events | acpid + sessiond consumers | M |
| 5.4 | Event-driven `redbear-upower` (replace polling with notify-driven refresh) | `redbear-upower` | S |
| 5.5 | Fan: real PNP0C0B/EC fan control replacing thermald soft model | `thermald/fan.rs`, acpid EC | M |
**Gate 5:** Unplug/replug AC → instant battery/AC event; close/open lid → event
logged; power button → clean shutdown flow; fan responds to thermal load.
---
### PHASE 6 — Wi-Fi BE201: the iwlmld gap (XL, hardest network work)
Pre-agreed reality: **this is not a device-ID add.** The Mini-MVM layer is
iwlmvm-era; BE201 firmware is iwlmld-era with different command IDs, RX
descriptors, and notification dispatch. Respect `WIFI-IMPLEMENTATION-PLAN.md`
phases W0W7.
| # | Work item | Files | Effort |
|---|---|---|---|
| 6.0 | De-risk transport on older silicon first: if any AX210-class card is available (USB/M.2 test card), validate existing Mini-MVM path end-to-end on the host's sibling hardware before touching iwlmld | redbear-iwlwifi | S (if HW available) |
| 6.1 | Firmware plumbing: add API-102 candidates `iwlwifi-bz-b0-fm-c0-102.ucode` to tables in `main.rs` + `redbear-wifictl/backend.rs`; extend `fetch-firmware.sh`; TLV parser audit vs API 102 | `redbear-iwlwifi/source/src/{main.rs,linux_mvm.c}` | S |
| 6.2 | **Mini-MLD layer**: port Linux 7.1 `drivers/net/wireless/intel/iwlwifi/mld/` structures — new RX/multi-link descriptor format, notification IDs, op-mode registration; gate MLD vs MVM on device family (BZ→MLD) | new `linux_mld.{c,h}` beside `linux_mvm.{c,h}`; `linux_port.c` op-mode dispatch | XL |
| 6.3 | Bounded runtime ladder on host: probe → fw boot alive → scan (see real SSID) → association → DHCP → reconnect persistence. Use existing `redbear-phase5-wifi-*` in-guest harness | redbear-wifictl + test scripts | M (iterative) |
| 6.4 | Integration: netctl profile, boot-time autoconnect, honest `redbear-info` states | wifictl, config fragments | S |
**Gate 6:** BE201 associates with the host's AP and passes traffic on the host —
real wireless connectivity, not bounded simulation.
---
### PHASE 7 — Bluetooth: Intel CNVi BT (M)
| # | Work item | Files | Effort |
|---|---|---|---|
| 7.1 | Intel BT firmware load in `redbear-btusb`: bootloader-mode detection, `ibt-0093-0291.sfi` download, DDC apply — port from Linux `btintel.c` | `local/recipes/drivers/redbear-btusb/` | M |
| 7.2 | HCI bring-up on the host: reset → read version → operational mode; bounded BLE battery-level slice validation via existing harness | btusb + `test-bluetooth-qemu.sh` host analogue | M |
| 7.3 | `redbear-btctl` scan/pair/connect on host | redbear-btctl | S |
**Gate 7:** `redbear-btctl` sees and connects to a BLE peripheral on the host.
---
### PHASE 8 — Audio: SOF/cAVS (XL, largest single effort)
| # | Work item | Files | Effort |
|---|---|---|---|
| 8.0 | Interim (do first): USB-audio dongle path via `redbear-usbaudiod` validated on host — documented as the interim answer | redbear-usbaudiod | S |
| 8.1 | Probe ihdad on 8086:7728 to record exact failure mode (expected: no codecs behind DSP); ensure graceful failure, never a boot hang | `ihdad/src/hda/device.rs` | S |
| 8.2 | **SOF/AVS port**: cAVS 2.5 (ARL) DSP bring-up — power gating, ROM boot, `sof-arl.ri` firmware download via firmware-loader, IPC4 channel, HDA link DMA. Reference: `local/reference/linux-7.1/sound/soc/sof/intel/` + `sound/soc/intel/avs/`; revive `local/docs/archived/INTEL-HDA-IMPLEMENTATION-PLAN.md` HDA-011 track | new `local/recipes/drivers/redbear-sof/` (per LINUX REFERENCE SOURCE POLICY: implemented in-tree, Linux as reference only) | XL |
| 8.3 | ALC298 codec verbs over the HDA link; speaker + headphone jack routing; DMIC later | sof codec layer | L |
**Gate 8:** Speaker playback on the host. (DMIC + HDMI audio are post-gate follow-ups.)
---
### PHASE 9 — Platform extras (post-core, SM each)
| # | Item | Notes | Effort |
|---|---|---|---|
| 9.1 | **Suspend (s2idle) completion**: LPIT parser (ACPI 6.5 §5.2.9.9), MWAIT idle-loop wiring, `_PRW` wake-device enumeration, GPE wake re-arm. The host has **no S3** — this is the only suspend path | `acpid`, kernel idle | L |
| 9.2 | LG WMI hotkeys: WMI subsystem (PNP0C14 GUID dispatch) → brightness/rfkill/volume events → evdev | new `redbear-wmi` | M |
| 9.3 | UVC camera: new `redbear-uvcd` (UVC 1.1/1.5) — well-specified; reference Linux `drivers/media/usb/uvc/` | new recipe | L |
| 9.4 | ISH sensor hub (8087:0AC2): only if a consumer exists (auto-rotate/ALS). Lowest priority | — | M |
| 9.5 | Intel VT-d runtime (`intel_vtd.rs` in iommu daemon): converges acpid's orphaned DMAR parser into the daemon (per ACPI-IMPROVEMENT-PLAN ownership note). Value: DMA isolation for later Wi-Fi/GPU hardening | `local/recipes/system/iommu/` | L |
| 9.6 | Non-critical devices documented as permanent no-driver: MEI, GNA, VPU/NPU, PMC telemetry, SMBus, SPI, UART, TPM — with one-line justification each (no consumer) | this doc | S |
**No stubs anywhere in this phase — per local/AGENTS.md zero-tolerance policy,
each item is a real implementation or it does not ship.**
---
### PHASE 10 — Validation, quirks, and hardening (continuous)
| # | Item |
|---|---|
| 10.1 | Keep `HARDWARE-VALIDATION-MATRIX.md` row for 16Z90TP current after every phase gate |
| 10.2 | Every discovered hardware workaround → data-driven quirk entry (compiled table or `redbear-quirks` TOML + DMI match), never an `#ifdef`-style special case |
| 10.3 | Boot logs per milestone archived to `local/docs/boot-logs/` |
| 10.4 | Durability: all source changes land as fork commits (`local/sources/*`) or patches (`local/patches/*`) in the same session — per DURABILITY POLICY |
| 10.5 | Upstream-sync safety: any new generic infrastructure (GPE dispatch, Mini-MLD, SOF) is implemented in the canonical component (acpid / redbear-iwlwifi / new recipe), not as host-specific hacks |
---
## 5. Dependency Graph
```
Phase 0 (collision fix, quirks, firmware) ──► Phase 1 (BM boot validation)
Phase 1 ──► Phase 2 (power validation)
Phase 1 ──► Phase 3 (display) ──► desktop path (Qt6/KWin on host)
Phase 1 ──► Phase 4 (touchpad) ──► usable laptop input
Phase 1 ──► Phase 5 (ACPI events) ──► Phase 9.1 (suspend)
Phase 1 ──► Phase 6 (Wi-Fi, XL) ──► network without dongle
Phase 1 ──► Phase 7 (Bluetooth)
Phase 1 ──► Phase 8 (audio SOF, XL)
Phase 3+4+5+6 complete = "daily-drivable laptop" milestone
```
## 6. Suggested Execution Order (effort-sequenced)
1. **Phase 0 + 1** — boot the host, fix the e1000d collision, capture the matrix (week 1)
2. **Phase 4 (touchpad)** + **Phase 2 (power)** — makes it a *usable* laptop (weeks 13)
3. **Phase 5 (ACPI events)** — makes it a *real* laptop (weeks 36)
4. **Phase 3 (display DRM)** — desktop path on the host (weeks 310, parallel)
5. **Phase 6 (Wi-Fi iwlmld)** — the XL rock to push (start early, longest lead time)
6. **Phase 7 (BT)**, **Phase 8 (audio)** — after their USB/PCI substrates are proven
7. **Phase 9 extras** — as capacity allows
## 7. Explicitly Out of Scope (per policies)
- No removal/ignore/comment-out of any package or device entry that fails to probe
(ABSOLUTE RULE) — failures get root-cause fixes or honest "unsupported" reporting.
- No new branches, repos, or submodules without the documented necessity case.
- Linux kernel source is reference-only; all ports are in-tree implementations.
- TPM2/secure-boot/ME features — no consumer, no plan.
+47
View File
@@ -88,6 +88,53 @@ and `/etc/quirks.d/*.toml` can now add `[[dmi_system_quirk]]` rules with
`match.*` keys plus optional `pci_vendor` / `pci_device` selectors. Runtime use
now reads live SMBIOS strings from `acpid` via `/scheme/acpi/dmi`.
A single `flags = [...]` array in a `[[dmi_system_quirk]]` entry may mix
PCI-level flag names and system-level flag names; the loader splits them
against both mappings (`PCI_FLAG_NAMES` and `SYSTEM_FLAG_NAMES`) and warns
only when a name is in neither. System-level flags land in
`DmiSystemQuirkRule` and are accumulated machine-wide by
`quirks::system_quirks()`:
```rust
let flags = redox_driver_sys::quirks::system_quirks();
if flags.contains(SystemQuirkFlags::FORCE_S2IDLE) { /* skip S3 */ }
```
> **Note on matching semantics:** DMI field matching is exact string equality,
> not substring. For product families whose DMI `product_name` carries a SKU
> suffix (e.g. `16Z90TP-G.AL89C`), match on the stable `board_name`
> (e.g. `16Z90TP`) instead.
### System Quirks (SystemQuirkFlags)
Machine-wide flags matched by DMI data rather than PCI ID. Mirrors Linux's
DMI-matched platform quirks (`drivers/acpi/resource.c`
`irq1_level_low_skip_override[]`, `drivers/input/keyboard/atkbd.c` fixups,
`drivers/acpi/sleep.c` s2idle preferences). Consumers are the daemons that own
the subsystem.
| Flag | Consumer | Meaning |
|------|----------|---------|
| `FORCE_S2IDLE` | acpid | Firmware lacks/breaks `\_S3`; use s2idle (Modern Standby) for all sleep |
| `ACPI_IRQ1_SKIP_OVERRIDE` | acpid | Keep the DSDT's ActiveLow trigger for IRQ1 (i8042 keyboard) |
| `KBD_DEACTIVATE_FIXUP` | ps2d | Skip the AT keyboard deactivate command on cleanup/reconnect |
| `NO_LEGACY_PM1B` | acpid | Single PM1 control block (no PM1b); belt-and-braces alongside the FADT check |
TOML names: `force_s2idle`, `acpi_irq1_skip_override`, `kbd_deactivate_fixup`,
`no_legacy_pm1b`.
### Firmware path-map fallbacks
`firmware-loader`'s builtin fallback table maps the historical flat
`/lib/firmware/iwlwifi-*` request paths into the post-2026 linux-firmware
layout (`intel/iwlwifi/iwlwifi-*`):
- `iwlwifi-*.ucode``intel/iwlwifi/iwlwifi-*.ucode`
- `iwlwifi-*.pnvm``intel/iwlwifi/iwlwifi-*.pnvm`
The same entries exist in `/etc/firmware-fallbacks.d/10-iwlwifi.toml`
(embedded in `config/redbear-device-services.toml`).
## Available Quirk Flags
### ACPI Quirks (AcpiQuirkFlags)
@@ -484,17 +484,29 @@ fn intel_firmware_candidates(
let (stems, pnvm): (Vec<&'static str>, Option<&'static str>) = match (device_id, subsystem_id) {
(0x7740, 0x4090) => (
vec![
"iwlwifi-bz-b0-gf-a0-92.ucode",
"iwlwifi-bz-b0-gf-a0-94.ucode",
"iwlwifi-bz-b0-gf-a0-100.ucode",
"iwlwifi-bz-b0-gf-a0-94.ucode",
"iwlwifi-bz-b0-gf-a0-92.ucode",
],
Some("iwlwifi-bz-b0-gf-a0.pnvm"),
),
(0x7740, _) => (
vec![
"iwlwifi-bz-b0-fm-c0-92.ucode",
"iwlwifi-bz-b0-fm-c0-94.ucode",
// CNVi BE201 (LG Gram 16Z90TP, host-verified 2026-07-20): the
// "c"-prefixed series is the iwlmld firmware; c102 is what
// production Linux 7.1 loads on the host, c106 is the newest
// in the current linux-firmware snapshot. The unprefixed
// series is the older iwlmvm API and is kept as fallback.
"iwlwifi-bz-b0-fm-c0-c106.ucode",
"iwlwifi-bz-b0-fm-c0-c105.ucode",
"iwlwifi-bz-b0-fm-c0-c104.ucode",
"iwlwifi-bz-b0-fm-c0-c103.ucode",
"iwlwifi-bz-b0-fm-c0-c102.ucode",
"iwlwifi-bz-b0-fm-c0-c101.ucode",
"iwlwifi-bz-b0-fm-c0-101.ucode",
"iwlwifi-bz-b0-fm-c0-100.ucode",
"iwlwifi-bz-b0-fm-c0-94.ucode",
"iwlwifi-bz-b0-fm-c0-92.ucode",
],
Some("iwlwifi-bz-b0-fm-c0.pnvm"),
),
@@ -77,8 +77,7 @@ bitflags::bitflags! {
/// Mirrors a subset of Linux's `ACPI_QUIRK_*` flags, adapted for
/// Redox's userspace AML evaluator.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AcpiQuirkFlags: u64 {
const OSI_DISABLE_LINUX = 1 << 0;
pub struct AcpiQuirkFlags: u64 { const OSI_DISABLE_LINUX = 1 << 0;
const OSI_DISABLE_VISTA = 1 << 1;
const OSI_DISABLE_WIN7 = 1 << 2;
const OSI_DISABLE_WIN8 = 1 << 3;
@@ -97,6 +96,56 @@ bitflags::bitflags! {
}
}
bitflags::bitflags! {
/// Flags for platform/system quirks, matched by DMI data rather than PCI ID.
///
/// These mirror Linux's DMI-matched platform quirks:
/// - `drivers/acpi/resource.c` `irq1_level_low_skip_override[]`
/// - `drivers/input/keyboard/atkbd.c` LG/Dell/HP/Lenovo keyboard fixups
/// - `drivers/acpi/sleep.c` s2idle/S3 platform preferences
///
/// Unlike [`PciQuirkFlags`], system quirks apply to the whole machine and
/// are consumed by whichever daemon owns the subsystem (acpid for sleep
/// and IRQ-override flags, ps2d for keyboard flags).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct SystemQuirkFlags: u64 {
/// Firmware does not advertise `\_S3` or has a broken S3; sleep
/// transitions must use s2idle (Modern Standby / S0ix). Consumer: acpid.
const FORCE_S2IDLE = 1 << 0;
/// Keep the DSDT's ActiveLow trigger for IRQ1 (i8042 keyboard); do not
/// apply the default ActiveHigh resource override. Consumer: acpid.
const ACPI_IRQ1_SKIP_OVERRIDE = 1 << 1;
/// Skip the AT keyboard deactivate command on cleanup/reconnect;
/// affected laptops drop keys or wedge the controller otherwise.
/// Consumer: ps2d.
const KBD_DEACTIVATE_FIXUP = 1 << 2;
/// Platform has a single PM1 control block (no PM1b); belt-and-braces
/// alongside the FADT `pm1b_control_block == 0` check. Consumer: acpid.
const NO_LEGACY_PM1B = 1 << 3;
}
}
/// A DMI-matched system quirk rule: applies [`SystemQuirkFlags`] machine-wide
/// when the DMI data matches. Loaded from `[[dmi_system_quirk]]` TOML entries.
#[derive(Clone, Debug)]
pub struct DmiSystemQuirkRule {
pub dmi_match: dmi::DmiMatchRule,
pub flags: SystemQuirkFlags,
}
/// Machine-wide system quirks for the current host, best-effort.
///
/// Reads DMI from `/scheme/acpi/dmi` and accumulates [`SystemQuirkFlags`]
/// from every matching `[[dmi_system_quirk]]` entry in `/etc/quirks.d/`.
/// Returns an empty set when DMI or the quirk files are unavailable (early
/// boot), which every consumer must treat as "no quirks".
pub fn system_quirks() -> SystemQuirkFlags {
let Ok(dmi_info) = dmi::read_dmi_info() else {
return SystemQuirkFlags::empty();
};
toml_loader::load_dmi_system_quirks(&dmi_info).unwrap_or_default()
}
bitflags::bitflags! {
/// Flags for USB device quirks.
///
@@ -1,6 +1,7 @@
use super::{
dmi::{self, DmiInfo, DmiMatchRule, DmiPciQuirkRule},
PciQuirkEntry, PciQuirkFlags, UsbQuirkEntry, UsbQuirkFlags, PCI_QUIRK_ANY_ID,
DmiSystemQuirkRule, PciQuirkEntry, PciQuirkFlags, SystemQuirkFlags, UsbQuirkEntry,
UsbQuirkFlags, PCI_QUIRK_ANY_ID,
};
use crate::pci::PciDeviceInfo;
use std::borrow::Cow;
@@ -34,7 +35,7 @@ pub(crate) fn load_dmi_pci_quirks(
info: &PciDeviceInfo,
dmi_info: &DmiInfo,
) -> Result<PciQuirkFlags, ()> {
let entries = read_toml_dmi_entries().map_err(|_| ())?;
let (entries, _) = read_toml_dmi_entries().map_err(|_| ())?;
Ok(dmi::apply_dmi_pci_quirk_rules(
info,
Some(dmi_info),
@@ -42,6 +43,24 @@ pub(crate) fn load_dmi_pci_quirks(
))
}
/// Accumulate machine-wide [`SystemQuirkFlags`] from all `[[dmi_system_quirk]]`
/// TOML entries whose DMI rule matches this system.
///
/// Used by daemons that own a subsystem with platform-quirked behavior
/// (acpid: sleep/IRQ-override flags, ps2d: keyboard flags). The DMI data is
/// read from `/scheme/acpi/dmi` by the caller via
/// [`dmi::read_dmi_info`].
pub fn load_dmi_system_quirks(dmi_info: &DmiInfo) -> Result<SystemQuirkFlags, ()> {
let (_, system_entries) = read_toml_dmi_entries().map_err(|_| ())?;
let mut flags = SystemQuirkFlags::empty();
for rule in &system_entries {
if rule.dmi_match.matches(dmi_info) {
flags |= rule.flags;
}
}
Ok(flags)
}
fn bounded_u16(val: &toml::Value, field: &str, path: &str) -> Option<u16> {
match val.as_integer() {
Some(v) => u16::try_from(v).ok().or_else(|| {
@@ -120,6 +139,19 @@ const PCI_FLAG_NAMES: &[(&str, PciQuirkFlags)] = &[
("no_pme", PciQuirkFlags::NO_PME),
];
const SYSTEM_FLAG_NAMES: &[(&str, SystemQuirkFlags)] = &[
("force_s2idle", SystemQuirkFlags::FORCE_S2IDLE),
(
"acpi_irq1_skip_override",
SystemQuirkFlags::ACPI_IRQ1_SKIP_OVERRIDE,
),
(
"kbd_deactivate_fixup",
SystemQuirkFlags::KBD_DEACTIVATE_FIXUP,
),
("no_legacy_pm1b", SystemQuirkFlags::NO_LEGACY_PM1B),
];
const USB_FLAG_NAMES: &[(&str, UsbQuirkFlags)] = &[
("no_string_fetch", UsbQuirkFlags::NO_STRING_FETCH),
("reset_delay", UsbQuirkFlags::RESET_DELAY),
@@ -385,8 +417,9 @@ fn parse_usb_toml(doc: &toml::Value, out: &mut Vec<UsbQuirkEntry>, path: &str) {
}
}
fn read_toml_dmi_entries() -> std::io::Result<Vec<DmiPciQuirkRule>> {
fn read_toml_dmi_entries() -> std::io::Result<(Vec<DmiPciQuirkRule>, Vec<DmiSystemQuirkRule>)> {
let mut entries = Vec::new();
let mut system_entries = Vec::new();
for path in sorted_toml_files(QUIRKS_DIR)? {
let path_str = path.display().to_string();
let content = match std::fs::read_to_string(&path) {
@@ -403,12 +436,17 @@ fn read_toml_dmi_entries() -> std::io::Result<Vec<DmiPciQuirkRule>> {
continue;
}
};
parse_dmi_toml(&doc, &mut entries, &path_str);
parse_dmi_toml(&doc, &mut entries, &mut system_entries, &path_str);
}
Ok(entries)
Ok((entries, system_entries))
}
fn parse_dmi_toml(doc: &toml::Value, out: &mut Vec<DmiPciQuirkRule>, path: &str) {
fn parse_dmi_toml(
doc: &toml::Value,
out: &mut Vec<DmiPciQuirkRule>,
system_out: &mut Vec<DmiSystemQuirkRule>,
path: &str,
) {
let Some(arr) = doc.get("dmi_system_quirk").and_then(|v| v.as_array()) else {
return;
};
@@ -438,14 +476,38 @@ fn parse_dmi_toml(doc: &toml::Value, out: &mut Vec<DmiPciQuirkRule>, path: &str)
},
None => PCI_QUIRK_ANY_ID,
};
let flags = parse_flags(table, path, "PCI", PCI_FLAG_NAMES);
// A single `flags` array may mix PCI-level and system-level flag
// names; split them against both mappings and warn only when a name
// is in neither.
let names: &[toml::Value] = table
.get("flags")
.and_then(|v| v.as_array())
.map(Vec::as_slice)
.unwrap_or(&[]);
for name in names.iter().filter_map(toml::Value::as_str) {
if flag_from_name(name, PCI_FLAG_NAMES).is_none()
&& flag_from_name(name, SYSTEM_FLAG_NAMES).is_none()
{
log::warn!("quirks: {path}: unknown quirk flag '{name}'");
}
}
let flags = parse_flags_from_names(names, PCI_FLAG_NAMES);
let system_flags = parse_flags_from_names(names, SYSTEM_FLAG_NAMES);
out.push(DmiPciQuirkRule {
dmi_match,
dmi_match: dmi_match.clone(),
vendor,
device,
flags,
});
if !system_flags.is_empty() {
system_out.push(DmiSystemQuirkRule {
dmi_match,
flags: system_flags,
});
}
}
}
@@ -477,6 +539,13 @@ mod tests {
}
}
fn parse_both(doc: &toml::Value) -> (Vec<DmiPciQuirkRule>, Vec<DmiSystemQuirkRule>) {
let mut rules = Vec::new();
let mut system_rules = Vec::new();
parse_dmi_toml(doc, &mut rules, &mut system_rules, "test.toml");
(rules, system_rules)
}
#[test]
fn dmi_toml_matches_sys_vendor_and_product_name() {
let doc = r#"
@@ -490,8 +559,7 @@ mod tests {
.parse::<toml::Value>()
.unwrap();
let mut rules = Vec::new();
parse_dmi_toml(&doc, &mut rules, "test.toml");
let (rules, _) = parse_both(&doc);
assert_eq!(rules.len(), 1);
let dmi_info = DmiInfo {
@@ -521,8 +589,7 @@ mod tests {
.parse::<toml::Value>()
.unwrap();
let mut rules = Vec::new();
parse_dmi_toml(&doc, &mut rules, "test.toml");
let (rules, _) = parse_both(&doc);
assert_eq!(rules.len(), 1);
assert_eq!(rules[0].vendor, 0x8086);
assert_eq!(rules[0].device, PCI_QUIRK_ANY_ID);
@@ -554,8 +621,7 @@ mod tests {
.parse::<toml::Value>()
.unwrap();
let mut rules = Vec::new();
parse_dmi_toml(&doc, &mut rules, "test.toml");
let (rules, _) = parse_both(&doc);
let flags = dmi::apply_dmi_pci_quirk_rules(&make_info(0x1002, 0x73BF), None, &rules);
assert!(flags.is_empty());
@@ -573,9 +639,68 @@ mod tests {
.parse::<toml::Value>()
.unwrap();
let mut rules = Vec::new();
parse_dmi_toml(&doc, &mut rules, "test.toml");
let (rules, _) = parse_both(&doc);
assert!(rules.is_empty());
}
#[test]
fn dmi_toml_system_flags_split_from_pci_flags() {
// The LG Gram 16Z90TP quirk entry mixes a system flag set in one
// `flags` array; system flags must land in DmiSystemQuirkRule and
// not be silently dropped (regression: they previously parsed to
// empty sets).
let doc = r#"
[[dmi_system_quirk]]
flags = ["force_s2idle", "acpi_irq1_skip_override", "kbd_deactivate_fixup", "no_legacy_pm1b"]
match.sys_vendor = "LG Electronics"
match.product_name = "16Z90TP-G.AL89C"
"#
.parse::<toml::Value>()
.unwrap();
let (rules, system_rules) = parse_both(&doc);
assert_eq!(rules.len(), 1);
assert!(rules[0].flags.is_empty());
assert_eq!(system_rules.len(), 1);
let want = SystemQuirkFlags::FORCE_S2IDLE
| SystemQuirkFlags::ACPI_IRQ1_SKIP_OVERRIDE
| SystemQuirkFlags::KBD_DEACTIVATE_FIXUP
| SystemQuirkFlags::NO_LEGACY_PM1B;
assert_eq!(system_rules[0].flags, want);
let dmi_info = DmiInfo {
sys_vendor: Some("LG Electronics".to_string()),
product_name: Some("16Z90TP-G.AL89C".to_string()),
board_vendor: None,
board_name: Some("16Z90TP".to_string()),
board_version: None,
product_version: None,
bios_version: None,
};
assert!(system_rules[0].dmi_match.matches(&dmi_info));
let other = DmiInfo {
sys_vendor: Some("LG Electronics".to_string()),
product_name: Some("17U70P".to_string()),
..DmiInfo::default()
};
assert!(!system_rules[0].dmi_match.matches(&other));
}
#[test]
fn dmi_toml_mixed_pci_and_system_flags_route_to_both_tables() {
let doc = r#"
[[dmi_system_quirk]]
pci_vendor = 0x8086
flags = ["no_aspm", "kbd_deactivate_fixup"]
match.sys_vendor = "Dell Inc."
"#
.parse::<toml::Value>()
.unwrap();
let (rules, system_rules) = parse_both(&doc);
assert_eq!(rules[0].flags, PciQuirkFlags::NO_ASPM);
assert_eq!(system_rules[0].flags, SystemQuirkFlags::KBD_DEACTIVATE_FIXUP);
}
}
@@ -304,6 +304,17 @@ pub const XHCI_QUIRK_TABLE: &[Entry] = &[
// === Cadence ==========================================================
Entry { vendor: PCI_VENDOR_ID_CDNS, device: 0x0200, flags: F::CDNS_SCTX_QUIRK, ..Entry::WILDCARD },
// === Spec rule: xHCI > 0.96 gets SPURIOUS_SUCCESS =====================
// xhci_gen_setup() (xhci.c:5477): controllers following the xHCI 1.0+
// spec emit a spurious success event after a short transfer; the flag
// tells the event handler to ignore it.
Entry {
hci_version_lo: 0x0097,
hci_version_hi: 0xFFFF,
flags: F::SPURIOUS_SUCCESS,
..Entry::WILDCARD
},
// === Spec rule: xHCI 1.2+ gets DEFAULT_PM_RUNTIME_ALLOW ===============
Entry {
hci_version_lo: 0x0120,
@@ -586,6 +597,31 @@ mod tests {
assert!(q.contains(F::CDNS_SCTX_QUIRK));
}
#[test]
fn spec_rule_xhci_above_0_96_gets_spurious_success() {
// xhci.c:5477 — universal for hci_version > 0x96.
let q = lookup(0x1234, 0x5678, 0x00, 0x0120);
assert!(q.contains(F::SPURIOUS_SUCCESS));
let q2 = lookup(0x1234, 0x5678, 0x00, 0x0096);
assert!(!q2.contains(F::SPURIOUS_SUCCESS));
}
#[test]
fn lg_gram_arrow_lake_xhci_matches_linux_flag_set() {
// LG Gram 16Z90TP dmesg: xhci_hcd 8086:7ec0/8086:777d report
// quirks 0x200009810 = SPURIOUS_SUCCESS | LPM_SUPPORT | INTEL_HOST |
// AVOID_BEI | DEFAULT_PM_RUNTIME_ALLOW at hci_version 0x120.
for dev in [0x7ec0u16, 0x777d] {
let q = lookup(PCI_VENDOR_ID_INTEL, dev, 0x00, 0x0120);
let want = F::SPURIOUS_SUCCESS
| F::LPM_SUPPORT
| F::INTEL_HOST
| F::AVOID_BEI
| F::DEFAULT_PM_RUNTIME_ALLOW;
assert_eq!(q, want, "0x{:04x} flag set diverges from Linux", dev);
}
}
#[test]
fn spec_rule_xhci_1_2_gets_default_pm_runtime_allow() {
let q = lookup(0x1234, 0x5678, 0x00, 0x0120);
@@ -596,7 +632,12 @@ mod tests {
#[test]
fn unknown_vendor_no_quirks_unless_spec_rule_applies() {
let q = lookup(0x1234, 0x5678, 0x00, 0x0100);
// hci_version 0x96 is below both universal spec rules (SPURIOUS_SUCCESS
// needs > 0x96, DEFAULT_PM_RUNTIME_ALLOW needs >= 0x120).
let q = lookup(0x1234, 0x5678, 0x00, 0x0096);
assert_eq!(q, F::empty());
// At hci_version 0x100 only the SPURIOUS_SUCCESS spec rule applies.
let q2 = lookup(0x1234, 0x5678, 0x00, 0x0100);
assert_eq!(q2, F::SPURIOUS_SUCCESS);
}
}
@@ -217,6 +217,16 @@ impl FirmwareFallback {
"iwlwifi-*-83.ucode".to_string(),
vec!["iwlwifi-*-77.ucode".to_string()],
);
// linux-firmware moved iwlwifi payloads into intel/iwlwifi/ (2026);
// consumers request the historical flat /lib/firmware/iwlwifi-* paths.
fallbacks.insert(
"iwlwifi-*.ucode".to_string(),
vec!["intel/iwlwifi/iwlwifi-*.ucode".to_string()],
);
fallbacks.insert(
"iwlwifi-*.pnvm".to_string(),
vec!["intel/iwlwifi/iwlwifi-*.pnvm".to_string()],
);
Self { fallbacks }
}
@@ -1170,10 +1180,24 @@ mod tests {
vec![
"iwlwifi-bz-b0-gf-a0-83.ucode".to_string(),
"iwlwifi-bz-b0-gf-a0-77.ucode".to_string(),
"intel/iwlwifi/iwlwifi-bz-b0-gf-a0-92.ucode".to_string(),
]
);
}
#[test]
fn fallback_chain_maps_flat_iwlwifi_into_intel_subdir() {
// linux-firmware ships iwlwifi blobs under intel/iwlwifi/ since 2026;
// drivers request the historical flat paths.
let fallbacks = FirmwareFallback::builtins();
let chain = fallbacks.get_fallback_chain("iwlwifi-bz-b0-fm-c0-c102.ucode");
assert_eq!(chain, vec!["intel/iwlwifi/iwlwifi-bz-b0-fm-c0-c102.ucode".to_string()]);
let chain = fallbacks.get_fallback_chain("iwlwifi-bz-b0-fm-c0.pnvm");
assert_eq!(chain, vec!["intel/iwlwifi/iwlwifi-bz-b0-fm-c0.pnvm".to_string()]);
}
#[test]
fn load_uses_fallback_and_populates_persistent_cache() {
let root = temp_root("rbos-fw-fallback");
@@ -74,6 +74,16 @@ match.board_name = "X570 AORUS MASTER"
# no_legacy_pm1b — Single-PM1a hardware (LG firmware does
# not implement PM1b_CNT). Tells acpid
# to skip the SLP_TYPb write path.
#
# 16Z90TP-G.AL89C (Core Ultra 7 255H / Arrow Lake-H, dmesg-verified
# 2026-07-20): matched on board_name "16Z90TP" because DMI
# product_name carries the SKU suffix ("16Z90TP-G.AL89C") and the
# matcher is exact-equality; board_name is the stable family string.
[[dmi_system_quirk]]
flags = ["force_s2idle", "acpi_irq1_skip_override", "kbd_deactivate_fixup", "no_legacy_pm1b"]
match.sys_vendor = "LG Electronics"
match.board_name = "16Z90TP"
[[dmi_system_quirk]]
flags = ["force_s2idle", "acpi_irq1_skip_override", "kbd_deactivate_fixup", "no_legacy_pm1b"]
match.sys_vendor = "LG Electronics"
@@ -886,17 +886,26 @@ fn intel_firmware_candidates(
let (stems, pnvm): (Vec<&'static str>, Option<&'static str>) = match (device_id, subsystem_id) {
(0x7740, 0x4090) => (
vec![
"iwlwifi-bz-b0-gf-a0-92.ucode",
"iwlwifi-bz-b0-gf-a0-94.ucode",
"iwlwifi-bz-b0-gf-a0-100.ucode",
"iwlwifi-bz-b0-gf-a0-94.ucode",
"iwlwifi-bz-b0-gf-a0-92.ucode",
],
Some("iwlwifi-bz-b0-gf-a0.pnvm"),
),
(0x7740, _) => (
vec![
"iwlwifi-bz-b0-fm-c0-92.ucode",
"iwlwifi-bz-b0-fm-c0-94.ucode",
// Keep in sync with redbear-iwlwifi main.rs — the "c"-prefixed
// series is iwlmld firmware (production: c102 on the host).
"iwlwifi-bz-b0-fm-c0-c106.ucode",
"iwlwifi-bz-b0-fm-c0-c105.ucode",
"iwlwifi-bz-b0-fm-c0-c104.ucode",
"iwlwifi-bz-b0-fm-c0-c103.ucode",
"iwlwifi-bz-b0-fm-c0-c102.ucode",
"iwlwifi-bz-b0-fm-c0-c101.ucode",
"iwlwifi-bz-b0-fm-c0-101.ucode",
"iwlwifi-bz-b0-fm-c0-100.ucode",
"iwlwifi-bz-b0-fm-c0-94.ucode",
"iwlwifi-bz-b0-fm-c0-92.ucode",
],
Some("iwlwifi-bz-b0-fm-c0.pnvm"),
),