From 1561767ac9ecb10dac4334a4e46be373d17e9510 Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Sun, 7 Jun 2026 21:06:51 +0300 Subject: [PATCH] redbear-iwlwifi: log PCI quirk flags at Wi-Fi device detection (Gap 12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R1-R10 audit Gap 12: redbear-iwlwifi had zero PCI quirk consumption at Wi-Fi device detection time. The linux-kpi crate ships pci_has_quirk and pci_get_quirk_flags for consumers in C-land, but the Rust-side lookup function lookup_pci_quirks was not called from this driver. Every Intel Wi-Fi NIC passed the data-driven quirk table without a single log line. This change: - Adds source/src/quirks.rs with one public function, log_wifi_quirks(location, vendor, device) that: 1. Builds a PciDeviceInfo from the candidate's location and the just-parsed vendor / device IDs. 2. Calls redox_driver_sys::quirks::lookup_pci_quirks. 3. Logs the resulting flag word (info-level on a hit, debug-level on empty). 4. Returns the flags so the caller can gate probe / interrupt selection on specific bits (NO_MSI, NO_MSIX, DISABLE_ACCEL) in a follow-up. - Wires the call into detect_candidates() at src/main.rs:494, right after the Intel vendor / class / subclass match — the canonical identification point. The location is now available (it was already parsed via parse_location_from_config_path) and vendor_id / device_id are in scope from the PCI config read. Implementation note: this module bypasses the linux_kpi::pci::pci_get_quirk_flags C FFI because that function takes *mut PciDev and the bus / dev / func fields are private to the linux-kpi crate. The underlying lookup is identical — linux-kpi's FFI is a thin wrapper around the same redox_driver_sys function we call here. Going through PciDeviceInfo directly is the natural Rust path; the C FFI remains available for C-side consumers that already hold a struct pci_dev*. 3 unit tests cover the wiring: - zeroed device returns empty - unmatched vendor returns empty - real Intel NIC ID round-trips through PciQuirkFlags without losing bits No Cargo.toml change needed: redox-driver-sys was already a direct dependency. --- .../redbear-iwlwifi/source/src/main.rs | 3 + .../redbear-iwlwifi/source/src/quirks.rs | 93 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 local/recipes/drivers/redbear-iwlwifi/source/src/quirks.rs diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs b/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs index 0102287644..6cfa61e567 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs @@ -12,6 +12,8 @@ use redox_driver_sys::pci::{PCI_VENDOR_ID_INTEL, PciLocation}; use std::ffi::CString; use thiserror::Error; +mod quirks; + struct StderrLogger; impl log::Log for StderrLogger { @@ -491,6 +493,7 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result, DriverEr } let subsystem_id = u16::from_le_bytes([config[0x2E], config[0x2F]]); let location = parse_location_from_config_path(&config_path)?; + quirks::log_wifi_quirks(location, vendor_id, device_id); let (family, ucode_candidates, pnvm_candidate) = intel_firmware_candidates(device_id, subsystem_id); let selected_ucode = ucode_candidates diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/quirks.rs b/local/recipes/drivers/redbear-iwlwifi/source/src/quirks.rs new file mode 100644 index 0000000000..1aad627ff5 --- /dev/null +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/quirks.rs @@ -0,0 +1,93 @@ +//! R1–R10 audit Gap 12: PCI quirk flag reporting at Wi-Fi device detection. +//! +//! `redox_driver_sys::quirks::lookup_pci_quirks` is the data-driven +//! lookup the audit identified as missing. redbear-iwlwifi now +//! calls it at detection time and logs the resulting flag word. +//! Future revisions can gate probe / interrupt selection on +//! specific bits (NO_MSI, NO_MSIX, DISABLE_ACCEL) without +//! further FFI work. +//! +//! Note: this module bypasses the `linux_kpi::pci::pci_get_quirk_flags` +//! C FFI because that function takes a `*mut PciDev` whose `bus`, +//! `dev`, `func` fields are private to the linux-kpi crate. The +//! underlying lookup is the same `lookup_pci_quirks` we call here; +//! linux-kpi is just a C-ABI wrapper around it. Going through +//! `PciDeviceInfo` directly is the natural Rust path. + +use redox_driver_sys::pci::{PciDeviceInfo, PciLocation}; +use redox_driver_sys::quirks::{lookup_pci_quirks, PciQuirkFlags}; + +/// Run the data-driven quirk lookup for the given PCI device and +/// log the resulting flag word. Returns the flags so the caller +/// can react to specific bits. +pub(crate) fn log_wifi_quirks(location: PciLocation, vendor: u16, device: u16) -> PciQuirkFlags { + let info = PciDeviceInfo { + location, + vendor_id: vendor, + device_id: device, + subsystem_vendor_id: 0, + subsystem_device_id: 0, + revision: 0, + class_code: 0, + subclass: 0, + prog_if: 0, + header_type: 0, + irq: None, + bars: Vec::new(), + capabilities: Vec::new(), + }; + let flags = lookup_pci_quirks(&info); + if !flags.is_empty() { + log::info!( + "redbear-iwlwifi: quirks for {:04X}:{:04X} at {} flags=0x{:016X}", + vendor, + device, + location, + flags.bits(), + ); + } else { + log::debug!( + "redbear-iwlwifi: no quirks for {:04X}:{:04X} at {}", + vendor, + device, + location, + ); + } + flags +} + +#[cfg(test)] +mod tests { + use super::*; + + fn loc(bus: u8, device: u8, function: u8) -> PciLocation { + PciLocation { + segment: 0, + bus, + device, + function, + } + } + + #[test] + fn log_wifi_quirks_returns_empty_for_zeroed_device() { + let flags = log_wifi_quirks(loc(0, 0, 0), 0, 0); + assert!(flags.is_empty()); + } + + #[test] + fn log_wifi_quirks_returns_empty_for_unmatched_vendor() { + let flags = log_wifi_quirks(loc(1, 2, 0), 0xDEAD, 0xBEEF); + assert!(flags.is_empty()); + } + + #[test] + fn log_wifi_quirks_returns_known_flag_for_intel_wifi() { + let flags = log_wifi_quirks(loc(2, 0, 0), 0x8086, 0x1533); + // Round-trip through the bitset to confirm the value + // survives the conversion. Whether flags is empty or not + // depends on whether the table has this entry. + let parsed = PciQuirkFlags::from_bits_truncate(flags.bits()); + assert_eq!(parsed.bits(), flags.bits()); + } +}