fix: pass driver-manager PCI targets to wifi
This commit is contained in:
@@ -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)))
|
||||
|
||||
@@ -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<Vec<String>, 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<String> {
|
||||
let raw = env::var("PCID_DEVICE_PATH").ok()?;
|
||||
normalize_pcid_target(&raw)
|
||||
}
|
||||
|
||||
fn normalize_pcid_target(raw: &str) -> Option<String> {
|
||||
let entry = raw.strip_prefix("/scheme/pci/").unwrap_or(raw).trim();
|
||||
if entry.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let parts = entry.splitn(3, "--").collect::<Vec<_>>();
|
||||
if parts.len() != 3 {
|
||||
return Some(entry.to_string());
|
||||
}
|
||||
|
||||
Some(format!("{}:{}:{}", parts[0], parts[1], parts[2]))
|
||||
}
|
||||
|
||||
fn select_candidate(
|
||||
candidates: Vec<Candidate>,
|
||||
target: Option<&str>,
|
||||
@@ -393,6 +448,11 @@ fn detect_candidates(firmware_root: &PathBuf) -> Result<Vec<Candidate>, 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<Vec<Candidate>, 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<Vec<Candidate>, 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<Vec<Candidate>, 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<Vec<String>, 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]
|
||||
assert!(
|
||||
candidates[0]
|
||||
.ucode_candidates
|
||||
.iter()
|
||||
.any(|name| name.contains("iwlwifi-bz-b0-gf-a0-92.ucode")));
|
||||
.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
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("selected_pnvm=iwlwifi-bz-b0-gf-a0.pnvm")));
|
||||
assert!(lines
|
||||
.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")));
|
||||
.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
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("bar0_addr=host-skipped")));
|
||||
.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
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("activation=host-skipped")));
|
||||
.any(|line| line.contains("activation=host-skipped"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user