From f5475fc9a7eaa9cdef3e8aa4540268de773332c8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 29 Nov 2025 10:40:15 +0100 Subject: [PATCH] Deduplicate int vector handling between ihdad and rtl network drivers Xhcid and nvmed still use their own get_int_method function as they need need to distinguish between legacy, MSI and MSI-X interrupts. --- audio/ihdad/src/main.rs | 40 +------------ net/rtl8139d/src/main.rs | 73 +----------------------- net/rtl8168d/src/main.rs | 73 +----------------------- pcid/src/driver_interface/irq_helpers.rs | 54 ++++++++++++++++++ 4 files changed, 62 insertions(+), 178 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index c94184991c..3d9d32ca73 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -11,8 +11,7 @@ use std::usize; use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_first_msi_interrupt_on_bsp; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; use pcid_interface::PciFunctionHandle; pub mod hda; @@ -24,40 +23,6 @@ QEMU ICH9 8086:293E 82801H ICH8 8086:284B */ -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::debug!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - - if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - log::debug!("Legacy IRQ {}", irq); - - // legacy INTx# interrupt pins. - irq.irq_handle("ihdad") - } else { - panic!("ihdad: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("ihdad") - } else { - panic!("ihdad: no interrupts supported at all") - } -} - fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default(); @@ -78,8 +43,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdad"); { let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 97dc7921e8..bdd150982e 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,15 +1,10 @@ -use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::read_bsp_apic_id; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::{ - allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, -}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; +use pcid_interface::PciFunctionHandle; pub mod device; @@ -25,67 +20,6 @@ where } } -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::info!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::Msi(_) => panic!(), - PciFeatureInfo::MsiX(s) => s, - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate one msi vector. - - let method = { - // primary interrupter - let k = 0; - - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - log::debug!("Enabled MSI-X"); - - method - } else if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8139d") - } else { - panic!("rtl8139d: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8139d") - } else { - panic!("rtl8139d: no interrupts supported at all") - } -} - fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { let config = pcid_handle.config(); @@ -121,8 +55,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar = map_bar(&mut pcid_handle); - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8139d"); let mut scheme = NetworkScheme::new( move || unsafe { diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index c394f1c70e..c477c0aaeb 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -1,15 +1,10 @@ -use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::read_bsp_apic_id; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::{ - allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, -}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; +use pcid_interface::PciFunctionHandle; pub mod device; @@ -25,67 +20,6 @@ where } } -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::info!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::Msi(_) => panic!(), - PciFeatureInfo::MsiX(s) => s, - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate one msi vector. - - let method = { - // primary interrupter - let k = 0; - - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - log::debug!("Enabled MSI-X"); - - method - } else if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8168d") - } else { - panic!("rtl8168d: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8168d") - } else { - panic!("rtl8168d: no interrupts supported at all") - } -} - fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { let config = pcid_handle.config(); @@ -121,8 +55,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar = map_bar(&mut pcid_handle); - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8168d"); let mut scheme = NetworkScheme::new( move || unsafe { diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index f4221d0c68..0170380c69 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -227,3 +227,57 @@ pub fn allocate_first_msi_interrupt_on_bsp( interrupt_handle } + +/// Get the most optimal supported interrupt mechanism: either (in the order of preference): +/// MSI-X, MSI, and INTx# pin. Returns the handles to the interrupts. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn pci_allocate_interrupt_vector( + pcid_handle: &mut crate::driver_interface::PciFunctionHandle, + driver: &str, +) -> File { + let features = pcid_handle.fetch_all_features(); + + let has_msi = features.iter().any(|feature| feature.is_msi()); + let has_msix = features.iter().any(|feature| feature.is_msix()); + + if has_msix { + let capability_struct = match pcid_handle.feature_info(super::PciFeature::MsiX) { + super::PciFeatureInfo::MsiX(msix) => msix, + _ => unreachable!(), + }; + let mut info = unsafe { capability_struct.map_and_mask_all(pcid_handle) }; + + pcid_handle.enable_feature(crate::driver_interface::PciFeature::MsiX); + + let entry = info.table_entry_pointer(0); + + let bsp_cpu_id = read_bsp_apic_id() + .unwrap_or_else(|err| panic!("{driver}: failed to read BSP APIC ID: {err}")); + let (msg_addr_and_data, irq_handle) = allocate_single_interrupt_vector_for_msi(bsp_cpu_id); + entry.write_addr_and_data(msg_addr_and_data); + entry.unmask(); + + irq_handle + } else if has_msi { + allocate_first_msi_interrupt_on_bsp(pcid_handle) + } else if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { + // INTx# pin based interrupts. + irq.irq_handle(driver) + } else { + panic!("{driver}: no interrupts supported at all") + } +} + +// FIXME support MSI on non-x86 systems +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn pci_allocate_interrupt_vector( + pcid_handle: &mut crate::driver_interface::PcidServerHandle, + driver: &str, +) -> Vec { + if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { + // INTx# pin based interrupts. + irq.irq_handle(driver) + } else { + panic!("{driver}: no interrupts supported at all") + } +}