Get the PCI bus number range
This commit is contained in:
parent
5499436807
commit
f055a387a7
|
|
@ -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<RangeInclusive<u8>> {
|
||||
// We follow the Linux's PCI device tree to obtain the register information
|
||||
// about the PCI bus. See also the specification at
|
||||
// <https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt>.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<RangeInclusive<u8>> {
|
||||
// We follow the Linux's PCI device tree to obtain the register information
|
||||
// about the PCI bus. See also the specification at
|
||||
// <https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt>.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<RangeInclusive<u8>> {
|
||||
// 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
|
||||
// <https://www.intel.com/Assets/PDF/datasheet/290562.pdf>.
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<PciBus> = 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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue