pci: Improves PCI device enumeration by suppporting multi-function detection

This commit is contained in:
Yuke Peng 2025-12-04 20:29:57 +08:00 committed by Tate, Hongliang Tian
parent c825c0d2c8
commit 4213908366
3 changed files with 41 additions and 28 deletions

View File

@ -52,6 +52,11 @@ impl PciCommonDevice {
self.header_type.device_type()
}
/// Checks whether the device is a multi-function device
pub fn has_multi_funcs(&self) -> bool {
self.header_type.has_multi_funcs()
}
/// Gets the PCI Command
pub fn command(&self) -> Command {
Command::from_bits_truncate(self.location.read16(PciCommonCfgOffset::Command as u16))

View File

@ -19,33 +19,17 @@ 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>`).
const MIN_BUS: u8 = 0;
pub const MIN_BUS: u8 = 0;
#[cfg(not(target_arch = "loongarch64"))]
const MAX_BUS: u8 = 255;
pub const MAX_BUS: u8 = 255;
#[cfg(target_arch = "loongarch64")]
const MAX_BUS: u8 = 127;
pub const MAX_BUS: u8 = 127;
const MIN_DEVICE: u8 = 0;
const MAX_DEVICE: u8 = 31;
pub const MIN_DEVICE: u8 = 0;
pub const MAX_DEVICE: u8 = 31;
const MIN_FUNCTION: u8 = 0;
const MAX_FUNCTION: u8 = 7;
/// Returns an iterator that enumerates all possible PCI device locations.
pub fn all() -> impl Iterator<Item = PciDeviceLocation> {
let all_bus = Self::MIN_BUS..=Self::MAX_BUS;
let all_dev = Self::MIN_DEVICE..=Self::MAX_DEVICE;
let all_func = Self::MIN_FUNCTION..=Self::MAX_FUNCTION;
all_bus
.flat_map(move |bus| all_dev.clone().map(move |dev| (bus, dev)))
.flat_map(move |(bus, dev)| all_func.clone().map(move |func| (bus, dev, func)))
.map(|(bus, dev, func)| PciDeviceLocation {
bus,
device: dev,
function: func,
})
}
pub const MIN_FUNCTION: u8 = 0;
pub const MAX_FUNCTION: u8 = 7;
}
impl PciDeviceLocation {

View File

@ -96,10 +96,34 @@ fn init() {
}
let mut lock = PCI_BUS.lock();
for location in PciDeviceLocation::all() {
let Some(device) = PciCommonDevice::new(location) else {
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;
for bus in all_bus {
for device in all_dev.clone() {
let mut device_location = PciDeviceLocation {
bus,
device,
function: PciDeviceLocation::MIN_FUNCTION,
};
let Some(first_function_device) = PciCommonDevice::new(device_location) else {
continue;
};
lock.register_common_device(device);
let has_multi_function = first_function_device.has_multi_funcs();
// Register function 0 in advance
lock.register_common_device(first_function_device);
if has_multi_function {
for function in all_func.clone().skip(1) {
device_location.function = function;
if let Some(common_device) = PciCommonDevice::new(device_location) {
lock.register_common_device(common_device);
}
}
}
}
}
}