dt: fix pci interrupt-map parsing
This commit is contained in:
parent
d83b82ef45
commit
01dbac2132
@ -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]
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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 #{}",
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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! {
|
||||
|
@ -294,6 +294,10 @@ fn run_riscv64(
|
||||
bios,
|
||||
});
|
||||
|
||||
for device in devices {
|
||||
qemu.with_device(device);
|
||||
}
|
||||
|
||||
Ok(qemu.into_command())
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user