dt: fix pci interrupt-map parsing

This commit is contained in:
Mark Poliakov 2025-02-05 12:35:38 +02:00
parent d83b82ef45
commit 01dbac2132
10 changed files with 59 additions and 32 deletions

View File

@ -31,7 +31,6 @@ ygg_driver_net_loopback = { path = "driver/net/loopback" }
ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] }
ygg_driver_virtio_gpu = { path = "driver/virtio/gpu", features = ["pci"] }
ygg_driver_ahci = { path = "driver/block/ahci" }
ygg_driver_usb_xhci = { path = "driver/usb/xhci" }
ygg_driver_input = { path = "driver/input" }
memfs = { path = "driver/fs/memfs" }
@ -62,8 +61,9 @@ kernel-arch-riscv64.workspace = true
yboot-proto.workspace = true
kernel-arch-x86_64.workspace = true
kernel-arch-x86.workspace = true
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_nvme = { path = "driver/block/nvme" }
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
@ -89,6 +89,7 @@ kernel-arch-aarch64.workspace = true
kernel-arch-riscv64.workspace = true
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
[features]

View File

@ -322,6 +322,7 @@ pub(crate) unsafe fn map_device_memory(
let address = base_address + l2_offset;
Ok(RawDeviceMemoryMapping::from_raw_parts(
l2_aligned.into_u64(),
address,
base_address,
page_count,
@ -333,6 +334,7 @@ pub(crate) unsafe fn map_device_memory(
let address = base_address + l3_offset;
Ok(RawDeviceMemoryMapping::from_raw_parts(
l3_aligned.into_u64(),
address,
base_address,
page_count,

View File

@ -189,6 +189,7 @@ pub(crate) unsafe fn map_device_memory(
let address = base_address + l2_offset;
Ok(RawDeviceMemoryMapping::from_raw_parts(
l2_aligned.into_u64(),
address,
base_address,
page_count,
@ -202,6 +203,7 @@ pub(crate) unsafe fn map_device_memory(
let address = base_address + l3_offset;
Ok(RawDeviceMemoryMapping::from_raw_parts(
l3_aligned.into_u64(),
address,
base_address,
page_count,

View File

@ -1,12 +1,9 @@
//! PCI capability structures and queries
use core::mem::offset_of;
use alloc::{sync::Arc, vec, vec::Vec};
use device_api::interrupt::{
InterruptAffinity, InterruptHandler, MessageInterruptController, MsiInfo,
};
use kernel_arch_x86::intrinsics;
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use tock_registers::{
interfaces::{Readable, Writeable},
@ -18,6 +15,11 @@ use crate::PciBaseAddress;
use super::{PciCapability, PciCapabilityId, PciConfigurationSpace};
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
use core::mem::offset_of;
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
use kernel_arch_x86::intrinsics;
pub trait VirtioCapabilityData<'s, S: PciConfigurationSpace + ?Sized + 's>: Sized {
fn from_space_offset(space: &'s S, offset: usize) -> Self;
@ -87,6 +89,7 @@ pub struct MsiXEntry {
enum MsiXVectorTableAccess<'a> {
Memory(DeviceMemoryIoMut<'a, [MsiXEntry]>),
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
Io(u16),
}
@ -368,10 +371,13 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> {
table_size,
)
},
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
PciBaseAddress::Io(io) => unsafe {
log::info!("MSI-X table I/O: {:#x}", io + table_offset as u16);
MsiXVectorTable::io_from_raw_parts(io + table_offset as u16, table_size)
},
#[cfg(any(not(any(target_arch = "x86", target_arch = "x86_64")), rust_analyzer))]
PciBaseAddress::Io(_) => Err(Error::DoesNotExist),
}
}
@ -409,44 +415,52 @@ impl MsiXVectorTableAccess<'_> {
fn read_control(&mut self, vector: usize) -> u32 {
match self {
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
&mut Self::Io(base) => unsafe {
let a = base
+ (vector * size_of::<MsiXEntry>() + offset_of!(MsiXEntry, control)) as u16;
intrinsics::inl(a)
},
Self::Memory(vectors) => vectors[vector].control.get(),
}
}
fn write_address(&mut self, vector: usize, value: u64) {
match self {
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
&mut Self::Io(base) => unsafe {
let a = base + (vector * size_of::<MsiXEntry>()) as u16;
intrinsics::outl(a, value as u32);
intrinsics::outl(a + 4, (value >> 32) as u32);
},
Self::Memory(vectors) => vectors[vector].address.set(value),
}
}
fn write_data(&mut self, vector: usize, value: u32) {
match self {
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
&mut Self::Io(base) => unsafe {
let a =
base + (vector * size_of::<MsiXEntry>() + offset_of!(MsiXEntry, data)) as u16;
intrinsics::outl(a, value)
},
Self::Memory(vectors) => vectors[vector].data.set(value),
}
}
fn write_control(&mut self, vector: usize, value: u32) {
match self {
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
&mut Self::Io(base) => unsafe {
let a = base
+ (vector * size_of::<MsiXEntry>() + offset_of!(MsiXEntry, control)) as u16;
intrinsics::outl(a, value)
},
Self::Memory(vectors) => vectors[vector].control.set(value),
}
}
@ -461,6 +475,7 @@ impl MsiXVectorTable<'_> {
})
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
unsafe fn io_from_raw_parts(base: u16, len: usize) -> Result<Self, Error> {
Ok(Self {
access: MsiXVectorTableAccess::Io(base),

View File

@ -247,7 +247,11 @@ impl PciDeviceInfo {
address: self.address,
pin,
};
let route = self.segment.irq_translation_map.map_interrupt(&src)?;
let route = self
.segment
.irq_translation_map
.map_interrupt(&src)
.inspect_err(|e| log::warn!("Could not map PCI IRQ {pin:?}: {e:?}"))?;
log::debug!(
"PCI {} pin {:?} -> system IRQ #{}",

View File

@ -13,14 +13,10 @@ use alloc::{format, sync::Arc, vec::Vec};
use bitflags::bitflags;
use device::{PciBusDevice, PciDeviceInfo};
use device_api::device::Device;
use interrupt::PciInterruptMap;
use libk::fs::sysfs::{self, object::KObject};
use libk_mm::address::PhysicalAddress;
use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit,
};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use space::legacy;
use yggdrasil_abi::{error::Error, primitive_enum};
@ -512,7 +508,7 @@ impl PciBusManager {
cfg_base: PhysicalAddress,
bus_range: core::ops::Range<u8>,
ranges: Vec<PciAddressRange>,
interrupt_map: BTreeMap<PciInterrupt, PciInterruptRoute>,
interrupt_map: PciInterruptMap,
) -> Result<(), Error> {
let mut bus_segment = PciBusSegment {
info: Arc::new(PciSegmentInfo {

View File

@ -32,7 +32,6 @@ pub struct PcieInterruptMapIter<'a> {
interrupt_map: TProp<'a>,
offset: usize,
child_address_cells: usize,
interrupt_extra_cells: usize,
}
impl Iterator for PcieInterruptMapIter<'_> {
@ -45,32 +44,37 @@ impl Iterator for PcieInterruptMapIter<'_> {
// TODO handle interrupt-map-mask
// interrupt-map:
// * PCI address (+ 2 cells of ???)
// * Pin
// * Interrupt Controller Handle (phandle + N cells of ???)
// * Interrupt Controller Data (3 cells)
// * PCI address (#address-cells of PCI node)
// * Pin (1 cell)
// * Interrupt Controller Handle phandle
// * Interrupt Address (unused, #address-cells of interrupt-controller)
// * Interrupt Controller Data (#interrupt-cells of interrupt-controller)
let mut offset = self.offset;
let address = self.interrupt_map.read_cell(offset, 1)? as u32;
offset += 1 + self.child_address_cells;
let bus = (address >> 16) as u8;
let device = ((address >> 11) & 0x1F) as u8;
let function = ((address >> 8) & 0x7) as u8;
let (pin, phandle) = self.interrupt_map.read_cells_at(offset, (1, 1))?;
// pin + phandle + N cells of whatever
offset += 1 + self.interrupt_extra_cells;
offset += 2;
let interrupt_controller = lookup_phandle(phandle as u32, true)?;
let interrupt_address_cells = interrupt_controller.self_address_cells().unwrap_or(0);
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
// #address-cells of intc unused and assumed to be zeroes for now
offset += interrupt_address_cells;
let irq = map_interrupt_at(&interrupt_controller, &self.interrupt_map, offset)?;
let bus = (address >> 24) as u8;
let device = ((address >> 11) & 0x1F) as u8;
let function = ((address >> 8) & 0x7) as u8;
let pin = pin as u8;
offset += interrupt_cells;
let pin = pin as u8;
self.offset = offset;
Some(PcieInterruptEntry {
@ -85,17 +89,13 @@ impl Iterator for PcieInterruptMapIter<'_> {
}
/// Returns an iterator over the PCIe-controller's `interrupt-map`
pub fn pcie_interrupt_map(
node: &Arc<Node>,
interrupt_extra_cells: usize,
) -> Option<PcieInterruptMapIter<'static>> {
pub fn pcie_interrupt_map(node: &Arc<Node>) -> Option<PcieInterruptMapIter<'static>> {
let interrupt_map = node.property("interrupt-map")?;
let child_address_cells = node.prop_usize("#address-cells")?.checked_sub(1)?;
Some(PcieInterruptMapIter {
interrupt_map,
child_address_cells,
interrupt_extra_cells,
offset: 0,
})
}

View File

@ -211,6 +211,8 @@ impl DeviceTreeInterruptController for Gic {
// IRQ_TYPE_LEVEL_HIGH - 4
// IRQ_TYPE_LEVEL_LOW - 8
log::info!("MAP INTERRUPT offset={offset}");
let sizes = (1, 1, 1);
let (kind, number, options) = property.read_cells_at(offset, sizes)?;
let number = number as u32;

View File

@ -9,6 +9,7 @@ use device_tree::{
use libk_mm::address::PhysicalAddress;
use ygg_driver_pci::{
device::{PciInterrupt, PciInterruptPin, PciInterruptRoute},
interrupt::PciInterruptMap,
PciAddress, PciAddressRange, PciBusManager, PciRangeType,
};
@ -53,8 +54,8 @@ fn make_range(
})
}
fn make_interrupt_map(node: &Arc<Node>) -> Option<BTreeMap<PciInterrupt, PciInterruptRoute>> {
let interrupt_map = pcie_interrupt_map(node, 2)?;
fn make_interrupt_map(node: &Arc<Node>) -> Option<PciInterruptMap> {
let interrupt_map = pcie_interrupt_map(node)?;
let mut imap = BTreeMap::new();
for entry in interrupt_map {
@ -74,7 +75,7 @@ fn make_interrupt_map(node: &Arc<Node>) -> Option<BTreeMap<PciInterrupt, PciInte
imap.insert(src, dst);
}
Some(imap)
Some(PciInterruptMap::Fixed(imap))
}
device_tree_driver! {

View File

@ -294,6 +294,10 @@ fn run_riscv64(
bios,
});
for device in devices {
qemu.with_device(device);
}
Ok(qemu.into_command())
}