From f055a387a7281b89efa7bdb6d8d262aab45e105c Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Sun, 18 Jan 2026 11:04:10 +0800 Subject: [PATCH] Get the PCI bus number range --- kernel/comps/pci/src/arch/loongarch/mod.rs | 46 ++++++++++++++++------ kernel/comps/pci/src/arch/riscv/mod.rs | 44 ++++++++++++++++----- kernel/comps/pci/src/arch/x86/mod.rs | 13 +++--- kernel/comps/pci/src/device_info.rs | 9 ----- kernel/comps/pci/src/lib.rs | 16 +++----- 5 files changed, 83 insertions(+), 45 deletions(-) diff --git a/kernel/comps/pci/src/arch/loongarch/mod.rs b/kernel/comps/pci/src/arch/loongarch/mod.rs index 082964d8d..39117ce83 100644 --- a/kernel/comps/pci/src/arch/loongarch/mod.rs +++ b/kernel/comps/pci/src/arch/loongarch/mod.rs @@ -2,7 +2,7 @@ //! PCI bus access -use core::alloc::Layout; +use core::{alloc::Layout, ops::RangeInclusive}; use align_ext::AlignExt; use fdt::node::FdtNode; @@ -39,11 +39,10 @@ fn encode_as_address_offset(location: &PciDeviceLocation) -> u32 { | ((location.function as u32) << 12) } -pub(crate) fn has_pci_bus() -> bool { - PCI_ECAM_CFG_SPACE.is_completed() -} - -pub(crate) fn init() { +/// Initializes the platform-specific module for accessing the PCI configuration space. +/// +/// Returns a range for the PCI bus number, or [`None`] if there is no PCI bus. +pub(crate) fn init() -> Option> { // We follow the Linux's PCI device tree to obtain the register information // about the PCI bus. See also the specification at // . @@ -56,31 +55,56 @@ pub(crate) fn init() { .find_compatible(&["pci-host-ecam-generic"]) else { warn!("No generic PCI host controller node found in the device tree"); - return; + return None; }; let Some(mut reg) = pci.reg() else { warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); - return; + return None; }; let Some(region) = reg.next() else { warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); - return; + return None; }; if reg.next().is_some() { warn!( "PCI node should have exactly one `reg` property, but found {} `reg`s", reg.count() + 2 ); - return; + return None; } - // Initialize the MMIO allocator + let bus_range = if let Some(prop) = pci.property("bus-range") { + if prop.value.len() != 8 || prop.value[0..3] != [0, 0, 0] || prop.value[4..7] != [0, 0, 0] { + warn!( + "PCI node should have a `bus-range` property with two bytes, but found `{:?}`", + prop.value + ); + return None; + } + if prop.value[3] != 0 { + // TODO: We don't support this case because the base address corresponds to the first + // bus. Therefore, an offset must be applied to the bus value in `read32`/`write32`. + warn!( + "PCI node with a non-zero bus start `{}` is not supported yet", + prop.value[3] + ); + return None; + } + Some(prop.value[3]..=prop.value[7]) + } else { + // "bus-range: Optional property [..] If absent, defaults to <0 255> (i.e. all buses)." + Some(0..=255) + }; + + // Initialize the MMIO allocator. init_mmio_allocator_from_fdt(&pci); let addr_start = region.starting_address as usize; let addr_end = addr_start.checked_add(region.size.unwrap()).unwrap(); PCI_ECAM_CFG_SPACE.call_once(|| IoMem::acquire(addr_start..addr_end).unwrap()); + + bus_range } /// A simple MMIO allocator managing a linear region. diff --git a/kernel/comps/pci/src/arch/riscv/mod.rs b/kernel/comps/pci/src/arch/riscv/mod.rs index 544b38f33..ba3af277e 100644 --- a/kernel/comps/pci/src/arch/riscv/mod.rs +++ b/kernel/comps/pci/src/arch/riscv/mod.rs @@ -2,6 +2,8 @@ //! PCI bus access +use core::ops::RangeInclusive; + use log::warn; use ostd::{Error, arch::boot::DEVICE_TREE, io::IoMem, mm::VmIoOnce}; use spin::Once; @@ -33,11 +35,10 @@ fn encode_as_address_offset(location: &PciDeviceLocation) -> u32 { | ((location.function as u32) << 12) } -pub(crate) fn has_pci_bus() -> bool { - PCI_ECAM_CFG_SPACE.is_completed() -} - -pub(crate) fn init() { +/// Initializes the platform-specific module for accessing the PCI configuration space. +/// +/// Returns a range for the PCI bus number, or [`None`] if there is no PCI bus. +pub(crate) fn init() -> Option> { // We follow the Linux's PCI device tree to obtain the register information // about the PCI bus. See also the specification at // . @@ -50,28 +51,53 @@ pub(crate) fn init() { .find_compatible(&["pci-host-ecam-generic"]) else { warn!("No generic PCI host controller node found in the device tree"); - return; + return None; }; let Some(mut reg) = pci.reg() else { warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); - return; + return None; }; let Some(region) = reg.next() else { warn!("PCI node should have exactly one `reg` property, but found zero `reg`s"); - return; + return None; }; if reg.next().is_some() { warn!( "PCI node should have exactly one `reg` property, but found {} `reg`s", reg.count() + 2 ); - return; + return None; } + let bus_range = if let Some(prop) = pci.property("bus-range") { + if prop.value.len() != 8 || prop.value[0..3] != [0, 0, 0] || prop.value[4..7] != [0, 0, 0] { + warn!( + "PCI node should have a `bus-range` property with two bytes, but found `{:?}`", + prop.value + ); + return None; + } + if prop.value[3] != 0 { + // TODO: We don't support this case because the base address corresponds to the first + // bus. Therefore, an offset must be applied to the bus value in `read32`/`write32`. + warn!( + "PCI node with a non-zero bus start `{}` is not supported yet", + prop.value[3] + ); + return None; + } + Some(prop.value[3]..=prop.value[7]) + } else { + // "bus-range: Optional property [..] If absent, defaults to <0 255> (i.e. all buses)." + Some(0..=255) + }; + let addr_start = region.starting_address as usize; let addr_end = addr_start.checked_add(region.size.unwrap()).unwrap(); PCI_ECAM_CFG_SPACE.call_once(|| IoMem::acquire(addr_start..addr_end).unwrap()); + + bus_range } pub(crate) const MSIX_DEFAULT_MSG_ADDR: u32 = 0x2400_0000; diff --git a/kernel/comps/pci/src/arch/x86/mod.rs b/kernel/comps/pci/src/arch/x86/mod.rs index 76d882354..a8f3c2087 100644 --- a/kernel/comps/pci/src/arch/x86/mod.rs +++ b/kernel/comps/pci/src/arch/x86/mod.rs @@ -2,6 +2,8 @@ //! PCI bus access +use core::ops::RangeInclusive; + use ostd::{ Error, arch::device::io_port::{ReadWriteAccess, WriteOnlyAccess}, @@ -45,17 +47,18 @@ fn encode_as_port(location: &PciDeviceLocation) -> u32 { | (((location.function as u32) & 0b111) << 8) } -pub(crate) fn has_pci_bus() -> bool { - true -} - -pub(crate) fn init() { +/// Initializes the platform-specific module for accessing the PCI configuration space. +/// +/// Returns a range for the PCI bus number, or [`None`] if there is no PCI bus. +pub(crate) fn init() -> Option> { // We use `acquire_overlapping` to acquire the port at 0xCF8 because 0xCF9 may be used as a // reset control register in the PIIX4. Although the two ports overlap in their I/O range, they // serve completely different purposes. See // . PCI_ADDRESS_PORT.call_once(|| IoPort::acquire_overlapping(0xCF8).unwrap()); PCI_DATA_PORT.call_once(|| IoPort::acquire(0xCFC).unwrap()); + + Some(0..=255) } pub(crate) const MSIX_DEFAULT_MSG_ADDR: u32 = 0xFEE0_0000; diff --git a/kernel/comps/pci/src/device_info.rs b/kernel/comps/pci/src/device_info.rs index 76e7faef2..23736d5ac 100644 --- a/kernel/comps/pci/src/device_info.rs +++ b/kernel/comps/pci/src/device_info.rs @@ -16,15 +16,6 @@ pub struct PciDeviceLocation { } impl PciDeviceLocation { - // TODO: Find a proper way to obtain the bus range. For example, if the PCI bus is identified - // from a device tree, this information can be obtained from the `bus-range` field (e.g., - // `bus-range = <0x00 0x7f>`). - pub const MIN_BUS: u8 = 0; - #[cfg(not(target_arch = "loongarch64"))] - pub const MAX_BUS: u8 = 255; - #[cfg(target_arch = "loongarch64")] - pub const MAX_BUS: u8 = 127; - pub const MIN_DEVICE: u8 = 0; pub const MAX_DEVICE: u8 = 31; diff --git a/kernel/comps/pci/src/lib.rs b/kernel/comps/pci/src/lib.rs index 7736f9b71..132c3848f 100644 --- a/kernel/comps/pci/src/lib.rs +++ b/kernel/comps/pci/src/lib.rs @@ -80,24 +80,18 @@ fn pci_init() -> Result<(), ComponentInitError> { Ok(()) } -/// Checks if the system has a PCI bus. -pub fn has_pci_bus() -> bool { - crate::arch::has_pci_bus() -} - -/// PCI bus instance +/// The PCI bus instance. pub static PCI_BUS: Mutex = Mutex::new(PciBus::new()); fn init() { - crate::arch::init(); - - if !crate::arch::has_pci_bus() { + let Some(all_bus) = arch::init() else { + log::info!("no PCI bus was found"); return; - } + }; + log::info!("initializing the PCI bus with bus numbers `{:?}`", all_bus); let mut lock = PCI_BUS.lock(); - let all_bus = PciDeviceLocation::MIN_BUS..=PciDeviceLocation::MAX_BUS; let all_dev = PciDeviceLocation::MIN_DEVICE..=PciDeviceLocation::MAX_DEVICE; let all_func = PciDeviceLocation::MIN_FUNCTION..=PciDeviceLocation::MAX_FUNCTION;