Merge branch 'pci_interrupts_rework5' into 'master'

Deduplicate int vector handling between ihdad and rtl network drivers

See merge request redox-os/drivers!298
This commit is contained in:
Jeremy Soller
2025-11-29 06:41:39 -07:00
4 changed files with 62 additions and 178 deletions
+2 -38
View File
@@ -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)
+3 -70
View File
@@ -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 {
+3 -70
View File
@@ -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 {
+54
View File
@@ -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<File> {
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")
}
}