pci: implement acpi irq route lookup

This commit is contained in:
Mark Poliakov 2025-01-27 19:22:21 +02:00
parent 6e7a42c2cb
commit b567995466
8 changed files with 551 additions and 257 deletions

703
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,9 @@ pub mod handler;
pub use handler::AcpiHandlerImpl;
pub mod aml_handler;
pub use acpi_system::{EventAction, FixedEvent};
pub use acpi_system::{
EventAction, FixedEvent, InterruptPolarity, InterruptTrigger, IrqDescriptor, PciPin,
};
static ACPI_SYSTEM: OneTimeInit<IrqSafeSpinlock<AcpiSystem<AcpiHandlerImpl>>> = OneTimeInit::new();
@ -30,6 +32,19 @@ pub fn add_event_handler<F: Fn(&AcpiSystem<AcpiHandlerImpl>) -> EventAction + 's
.map_err(|_| Error::InvalidArgument)
}
pub fn get_pci_route(
aml_path: &str,
device: u16,
function: u16,
pin: PciPin,
) -> Option<IrqDescriptor> {
ACPI_SYSTEM
.get()
.lock()
.pci_route(aml_path, device, function, pin)
.ok()
}
/// Initializes ACPI management
pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<(), Error> {
// NOTE mostly broken for real HW

View File

@ -16,6 +16,7 @@ bitflags.workspace = true
tock-registers.workspace = true
[target.'cfg(target_arch = "x86_64")'.dependencies]
ygg_driver_acpi.path = "../../acpi"
acpi.workspace = true
[lints]

View File

@ -121,7 +121,6 @@ impl PciDeviceInfo {
// Ignore preferred_mode, the only supported is Legacy
self.legacy_interrupt_mode()
};
IrqSafeRwLock::new(InterruptConfig {
preferred_mode,
configured_mode,
@ -212,11 +211,7 @@ impl PciDeviceInfo {
address: self.address,
pin,
};
let route = self
.segment
.irq_translation_map
.get(&src)
.ok_or(Error::InvalidOperation)?;
let route = self.segment.irq_translation_map.map_interrupt(&src)?;
log::debug!(
"PCI {} pin {:?} -> system IRQ #{}",

View File

@ -0,0 +1,55 @@
use alloc::collections::btree_map::BTreeMap;
use libk::error::Error;
use crate::device::{PciInterrupt, PciInterruptRoute};
#[derive(Debug)]
pub enum PciInterruptMap {
Fixed(BTreeMap<PciInterrupt, PciInterruptRoute>),
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
Acpi(alloc::string::String),
Legacy,
}
impl PciInterruptMap {
pub fn map_interrupt(&self, interrupt: &PciInterrupt) -> Result<PciInterruptRoute, Error> {
match self {
Self::Fixed(map) => map.get(interrupt).cloned().ok_or(Error::DoesNotExist),
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
Self::Acpi(aml_object_name) => {
use device_api::interrupt::{IrqLevel, IrqOptions, IrqTrigger};
use crate::device::PciInterruptPin;
let aml_pin = match interrupt.pin {
PciInterruptPin::A => ygg_driver_acpi::PciPin::IntA,
PciInterruptPin::B => ygg_driver_acpi::PciPin::IntB,
PciInterruptPin::C => ygg_driver_acpi::PciPin::IntC,
PciInterruptPin::D => ygg_driver_acpi::PciPin::IntD,
};
let aml_route = ygg_driver_acpi::get_pci_route(
aml_object_name.as_str(),
interrupt.address.device as u16,
interrupt.address.function as u16,
aml_pin,
)
.ok_or(Error::DoesNotExist)?;
let trigger = match aml_route.trigger {
ygg_driver_acpi::InterruptTrigger::Edge => IrqTrigger::Edge,
ygg_driver_acpi::InterruptTrigger::Level => IrqTrigger::Level,
};
let level = match aml_route.polarity {
ygg_driver_acpi::InterruptPolarity::ActiveLow => IrqLevel::ActiveLow,
ygg_driver_acpi::InterruptPolarity::ActiveHigh => IrqLevel::ActiveHigh,
};
Ok(PciInterruptRoute {
options: IrqOptions { trigger, level },
number: aml_route.irq,
})
}
Self::Legacy => todo!(),
}
}
}

View File

@ -6,12 +6,14 @@ extern crate alloc;
use core::fmt;
#[cfg(target_arch = "x86_64")]
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
use acpi::mcfg::McfgEntry;
use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
use alloc::{format, sync::Arc, vec::Vec};
use bitflags::bitflags;
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciInterrupt, PciInterruptRoute, PciMatch};
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciMatch};
use device_api::device::Device;
use interrupt::PciInterruptMap;
use libk::fs::sysfs::{self, object::KObject};
use libk_mm::address::PhysicalAddress;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
@ -20,6 +22,7 @@ use yggdrasil_abi::error::Error;
pub mod capability;
pub mod device;
pub mod interrupt;
mod nodes;
mod space;
@ -202,7 +205,7 @@ pub struct PciSegmentInfo {
pub bus_number_end: u8,
pub ecam_phys_base: Option<PhysicalAddress>,
pub irq_translation_map: BTreeMap<PciInterrupt, PciInterruptRoute>,
pub irq_translation_map: PciInterruptMap,
pub has_msi: bool,
}
@ -462,7 +465,7 @@ impl PciBusManager {
bus_number_start: 0,
bus_number_end: 255,
ecam_phys_base: None,
irq_translation_map: BTreeMap::new(),
irq_translation_map: PciInterruptMap::Legacy,
has_msi: false,
}),
allocator: None,
@ -486,8 +489,8 @@ impl PciBusManager {
bus_number_end: entry.bus_number_end,
ecam_phys_base: Some(PhysicalAddress::from_u64(entry.base_address)),
// TODO obtain this from ACPI SSDT
irq_translation_map: BTreeMap::new(),
// TODO get the segment's PCI root bridge AML name
irq_translation_map: PciInterruptMap::Acpi("\\_SB.PCI0._PRT".into()),
has_msi: true,
}),
// Firmware done this for us

View File

@ -11,7 +11,7 @@ use libk_mm::{
};
use libk_util::sync::IrqSafeSpinlock;
use crate::arch::x86::intrinsics::{io_wait, IoPort, IoPortAccess};
use kernel_arch_x86::intrinsics::{io_wait, IoPort, IoPortAccess};
#[derive(Clone, Copy)]
#[repr(C)]

View File

@ -83,7 +83,7 @@ impl Regs {
impl Inner {
fn map_gsi(&mut self, gsi: u32, vector: u32, apic_id: u32) -> Result<(), Error> {
assert!(gsi < self.max_gsi);
assert!(gsi <= self.max_gsi);
assert!(vector < 0x100);
log::info!("map_irq gsi{}, vec{}, apic{}", gsi, vector, apic_id);
@ -110,7 +110,7 @@ impl Inner {
}
fn configure_gsi(&mut self, gsi: u32, level: IrqLevel, trigger: IrqTrigger) {
assert!(gsi < self.max_gsi);
assert!(gsi <= self.max_gsi);
let mut low = self.regs.read(REG_REDIRECTION_BASE + gsi * 2);
@ -138,7 +138,7 @@ impl Inner {
}
fn set_gsi_enabled(&mut self, gsi: u32, enabled: bool) {
assert!(gsi < self.max_gsi);
assert!(gsi <= self.max_gsi);
let low = self.regs.read(REG_REDIRECTION_BASE + gsi * 2);
if enabled {