pci: implement acpi irq route lookup
This commit is contained in:
parent
6e7a42c2cb
commit
b567995466
703
Cargo.lock
generated
703
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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 #{}",
|
||||
|
55
kernel/driver/bus/pci/src/interrupt.rs
Normal file
55
kernel/driver/bus/pci/src/interrupt.rs
Normal 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!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user