diff --git a/drivers/pcid/src/driver_interface/mod.rs b/drivers/pcid/src/driver_interface/mod.rs index 21622caa03..5cf16e34a2 100644 --- a/drivers/pcid/src/driver_interface/mod.rs +++ b/drivers/pcid/src/driver_interface/mod.rs @@ -302,6 +302,23 @@ pub struct PciFunctionHandle { channel: File, config: SubdriverArguments, mapped_bars: [Option; 6], + irq_mode_hint: Option, + disable_accel_hint: bool, +} + +fn read_irq_mode_hint() -> Option { + match env::var("REDBEAR_DRIVER_PCI_IRQ_MODE") { + Ok(v) if !v.is_empty() => Some(v), + Ok(_) => None, + Err(_) => None, + } +} + +fn read_disable_accel_hint() -> bool { + match env::var("REDBEAR_DRIVER_DISABLE_ACCEL") { + Ok(v) if v == "1" || v.eq_ignore_ascii_case("true") || v == "yes" => true, + _ => false, + } } fn send(w: &mut File, message: &T) { @@ -378,9 +395,26 @@ impl PciFunctionHandle { channel, config, mapped_bars: [const { None }; 6], + irq_mode_hint: read_irq_mode_hint(), + disable_accel_hint: read_disable_accel_hint(), } } + /// Returns the IRQ-mode hint read from `REDBEAR_DRIVER_PCI_IRQ_MODE` at + /// connect time, or `None` if the env var was unset. Drivers should + /// honour this hint when allocating interrupt vectors. + pub fn irq_mode_hint(&self) -> Option<&str> { + self.irq_mode_hint.as_deref() + } + + /// Returns the disable-acceleration hint read from + /// `REDBEAR_DRIVER_DISABLE_ACCEL` at connect time. Drivers (notably + /// GPU drivers) should suppress hardware acceleration paths when this + /// returns `true`. + pub fn disable_accel_hint(&self) -> bool { + self.disable_accel_hint + } + pub fn into_inner_fd(self) -> RawFd { self.channel.into_raw_fd() } @@ -544,3 +578,65 @@ pub fn pci_daemon !>(f: F) -> ! { f(daemon, pcid_handle) }) } + +#[cfg(test)] +mod hint_tests { + use super::{read_disable_accel_hint, read_irq_mode_hint}; + use std::sync::Mutex; + + static ENV_LOCK: Mutex<()> = Mutex::new(()); + + #[test] + fn irq_mode_hint_returns_none_when_unset() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + unsafe { std::env::remove_var("REDBEAR_DRIVER_PCI_IRQ_MODE") }; + assert!(read_irq_mode_hint().is_none()); + } + + #[test] + fn irq_mode_hint_returns_some_when_set() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + unsafe { std::env::set_var("REDBEAR_DRIVER_PCI_IRQ_MODE", "intx_or_msi") }; + let v = read_irq_mode_hint(); + unsafe { std::env::remove_var("REDBEAR_DRIVER_PCI_IRQ_MODE") }; + assert_eq!(v.as_deref(), Some("intx_or_msi")); + } + + #[test] + fn irq_mode_hint_returns_none_for_empty_value() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + unsafe { std::env::set_var("REDBEAR_DRIVER_PCI_IRQ_MODE", "") }; + let v = read_irq_mode_hint(); + unsafe { std::env::remove_var("REDBEAR_DRIVER_PCI_IRQ_MODE") }; + assert!(v.is_none()); + } + + #[test] + fn disable_accel_hint_defaults_false() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + unsafe { std::env::remove_var("REDBEAR_DRIVER_DISABLE_ACCEL") }; + assert!(!read_disable_accel_hint()); + } + + #[test] + fn disable_accel_hint_accepts_truthy_values() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + for truthy in &["1", "true", "TRUE", "yes"] { + unsafe { std::env::set_var("REDBEAR_DRIVER_DISABLE_ACCEL", truthy) }; + let v = read_disable_accel_hint(); + unsafe { std::env::remove_var("REDBEAR_DRIVER_DISABLE_ACCEL") }; + assert!(v, "value {:?} should be truthy", truthy); + } + } + + #[test] + fn disable_accel_hint_rejects_falsy_values() { + let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + for falsy in &["0", "false", "no", ""] { + unsafe { std::env::set_var("REDBEAR_DRIVER_DISABLE_ACCEL", falsy) }; + let v = read_disable_accel_hint(); + unsafe { std::env::remove_var("REDBEAR_DRIVER_DISABLE_ACCEL") }; + assert!(!v, "value {:?} should be falsy", falsy); + } + } +}