From bf803aed94c8b5fc5883bef77dbece3122e427f6 Mon Sep 17 00:00:00 2001 From: Vasilito Date: Sat, 9 May 2026 01:33:22 +0100 Subject: [PATCH] fix: pass driver-manager PCI targets to wifi --- .../source/src/c_headers/linux/compiler.h | 2 + .../redbear-iwlwifi/source/src/main.rs | 161 ++++++++++++++++-- 2 files changed, 145 insertions(+), 18 deletions(-) diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/compiler.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/compiler.h index 149488bf7c..89cd0df3cf 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/compiler.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/compiler.h @@ -23,7 +23,9 @@ #define READ_ONCE(var) \ (*((volatile typeof(var) *)&(var))) +#ifndef offsetof #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) +#endif #define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs b/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs index 109b812589..0102287644 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/main.rs @@ -2,17 +2,50 @@ use std::env; use std::fs; use std::path::PathBuf; +use log::{LevelFilter, Metadata, Record, debug, info, warn}; #[cfg(target_os = "redox")] use redox_driver_sys::memory::{CacheType, MmioProt}; #[cfg(target_os = "redox")] use redox_driver_sys::pci::PciDevice; -use redox_driver_sys::pci::{PciLocation, PCI_VENDOR_ID_INTEL}; +use redox_driver_sys::pci::{PCI_VENDOR_ID_INTEL, PciLocation}; #[cfg(target_os = "redox")] use std::ffi::CString; use thiserror::Error; +struct StderrLogger; + +impl log::Log for StderrLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= log_level_from_env() + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + eprintln!("[{}] redbear-iwlwifi: {}", record.level(), record.args()); + } + } + + fn flush(&self) {} +} + +fn log_level_from_env() -> LevelFilter { + match env::var("REDBEAR_IWLWIFI_LOG").as_deref() { + Ok("trace") => LevelFilter::Trace, + Ok("debug") => LevelFilter::Debug, + Ok("warn") => LevelFilter::Warn, + Ok("error") => LevelFilter::Error, + _ => LevelFilter::Info, + } +} + +fn init_logging() { + static LOGGER: StderrLogger = StderrLogger; + let _ = log::set_logger(&LOGGER); + log::set_max_level(log_level_from_env()); +} + #[cfg(target_os = "redox")] -use linux_kpi::firmware::{release_firmware, request_firmware, Firmware}; +use linux_kpi::firmware::{Firmware, release_firmware, request_firmware}; #[repr(C)] #[derive(Default)] @@ -159,6 +192,7 @@ const IWL_CSR_RESET_REG_FLAG_SW_RESET: u32 = 0x00000080; const IWL_CSR_GP_CNTRL_REG_FLAG_INIT_DONE: u32 = 0x00000004; fn main() { + init_logging(); let mut args = env::args().skip(1); let firmware_root = env::var_os("REDBEAR_IWLWIFI_FIRMWARE_ROOT") .map(PathBuf::from) @@ -248,6 +282,7 @@ fn run_connect_action( security: &str, key: Option<&str>, ) { + let target = target.or_else(default_pcid_target); match detect_candidates(firmware_root) { Ok(candidates) => { let candidate = match select_candidate(candidates, target.as_deref()) { @@ -303,6 +338,7 @@ fn run_device_action( action: fn(&Candidate, &PathBuf) -> Result, DriverError>, action_name: &str, ) { + let target = target.or_else(default_pcid_target); match detect_candidates(firmware_root) { Ok(candidates) => { let candidate = match select_candidate(candidates, target.as_deref()) { @@ -331,6 +367,25 @@ fn run_device_action( } } +fn default_pcid_target() -> Option { + let raw = env::var("PCID_DEVICE_PATH").ok()?; + normalize_pcid_target(&raw) +} + +fn normalize_pcid_target(raw: &str) -> Option { + let entry = raw.strip_prefix("/scheme/pci/").unwrap_or(raw).trim(); + if entry.is_empty() { + return None; + } + + let parts = entry.splitn(3, "--").collect::>(); + if parts.len() != 3 { + return Some(entry.to_string()); + } + + Some(format!("{}:{}:{}", parts[0], parts[1], parts[2])) +} + fn select_candidate( candidates: Vec, target: Option<&str>, @@ -393,6 +448,11 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result, DriverEr let pci_root = env::var_os("REDBEAR_IWLWIFI_PCI_ROOT") .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from("/scheme/pci")); + info!( + "scanning PCI root {} for Intel Wi-Fi devices; firmware_root={}", + pci_root.display(), + firmware_root.display() + ); let entries = fs::read_dir(&pci_root) .map_err(|err| DriverError::Pci(format!("failed to read {}: {err}", pci_root.display())))?; @@ -400,9 +460,18 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result, DriverEr for entry in entries.flatten() { let config_path = entry.path().join("config"); let Ok(config) = fs::read(&config_path) else { + debug!( + "skipping PCI entry without readable config: {}", + config_path.display() + ); continue; }; if config.len() < 48 { + debug!( + "skipping short PCI config {} bytes={}", + config_path.display(), + config.len() + ); continue; } let vendor_id = u16::from_le_bytes([config[0x00], config[0x01]]); @@ -410,6 +479,14 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result, DriverEr let class_code = config[0x0B]; let subclass = config[0x0A]; if vendor_id != PCI_VENDOR_ID_INTEL || class_code != 0x02 || subclass != 0x80 { + debug!( + "skipping PCI config {} vendor={:04x} device={:04x} class={:02x} subclass={:02x}", + config_path.display(), + vendor_id, + device_id, + class_code, + subclass + ); continue; } let subsystem_id = u16::from_le_bytes([config[0x2E], config[0x2F]]); @@ -425,6 +502,19 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result, DriverEr .filter(|candidate| firmware_root.join(candidate).exists()) .cloned(); + info!( + "candidate {} device={:04x} subsystem={:04x} family={} selected_ucode={} pnvm={}", + location, + device_id, + subsystem_id, + family, + selected_ucode.as_deref().unwrap_or("missing"), + pnvm_found + .as_deref() + .or(pnvm_candidate.as_deref()) + .unwrap_or("none") + ); + out.push(Candidate { location, config_path, @@ -570,11 +660,23 @@ fn prepare_candidate( candidate: &Candidate, firmware_root: &PathBuf, ) -> Result, DriverError> { + info!( + "preparing firmware for {} family={} root={}", + candidate.location, + candidate.family, + firmware_root.display() + ); if let Ok(lines) = linux_kpi_prepare_candidate(candidate) { return Ok(lines); } let selected = candidate.selected_ucode.clone().ok_or_else(|| { + warn!( + "missing firmware for {} family={} expected={}", + candidate.location, + candidate.family, + candidate.ucode_candidates.join(",") + ); DriverError::Unsupported(format!( "missing firmware for {} (expected one of: {})", candidate.family, @@ -1338,6 +1440,19 @@ mod tests { path } + #[test] + fn normalizes_driver_manager_pci_target() { + assert_eq!( + normalize_pcid_target("/scheme/pci/0000--00--14.3").as_deref(), + Some("0000:00:14.3") + ); + assert_eq!( + normalize_pcid_target("0000:00:14.3").as_deref(), + Some("0000:00:14.3") + ); + assert_eq!(normalize_pcid_target(" "), None); + } + #[test] fn detects_intel_candidate() { let pci = temp_root("rbos-iwlwifi-pci"); @@ -1362,10 +1477,12 @@ mod tests { let candidates = detect_candidates(&fw).unwrap(); assert_eq!(candidates.len(), 1); assert_eq!(candidates[0].family, "intel-bz-arrow-lake"); - assert!(candidates[0] - .ucode_candidates - .iter() - .any(|name| name.contains("iwlwifi-bz-b0-gf-a0-92.ucode"))); + assert!( + candidates[0] + .ucode_candidates + .iter() + .any(|name| name.contains("iwlwifi-bz-b0-gf-a0-92.ucode")) + ); } #[test] @@ -1393,12 +1510,16 @@ mod tests { let lines = prepare_candidate(&candidate, &fw).unwrap(); assert!(lines.iter().any(|line| line == "status=firmware-ready")); - assert!(lines - .iter() - .any(|line| line.contains("selected_pnvm=iwlwifi-bz-b0-gf-a0.pnvm"))); - assert!(lines - .iter() - .any(|line| line.contains("selected_ucode=iwlwifi-bz-b0-gf-a0-92.ucode"))); + assert!( + lines + .iter() + .any(|line| line.contains("selected_pnvm=iwlwifi-bz-b0-gf-a0.pnvm")) + ); + assert!( + lines + .iter() + .any(|line| line.contains("selected_ucode=iwlwifi-bz-b0-gf-a0-92.ucode")) + ); } #[test] @@ -1426,9 +1547,11 @@ mod tests { let lines = init_transport_candidate(&candidate, &fw).unwrap(); assert!(lines.iter().any(|line| line == "status=transport-ready")); - assert!(lines - .iter() - .any(|line| line.contains("bar0_addr=host-skipped"))); + assert!( + lines + .iter() + .any(|line| line.contains("bar0_addr=host-skipped")) + ); } #[test] @@ -1456,9 +1579,11 @@ mod tests { let lines = activate_candidate(&candidate, &fw).unwrap(); assert!(lines.iter().any(|line| line == "status=nic-activated")); - assert!(lines - .iter() - .any(|line| line.contains("activation=host-skipped"))); + assert!( + lines + .iter() + .any(|line| line.contains("activation=host-skipped")) + ); } #[test]