pci: Add support for reserving but not allocating slots

This can be used in a two pass approach where all configs that can hold
PCI devices are evaluated to reserve any specific PCI device IDs they
may need. Those device IDs will later be allocated when the devices are
added to the bus. The tri-state Free, Reserved, Allocated also catches
the problem of hotplugging a device with a specific, already used,
device ID.

Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-04-04 11:05:01 -07:00
parent 3a5fad22b9
commit 51a729a874
3 changed files with 76 additions and 37 deletions
+3 -3
View File
@@ -498,7 +498,7 @@ pub enum DeviceManagerError {
/// Could not reserve the PCI device ID.
#[error("Could not reserve the PCI device ID")]
GetPciDeviceId(#[source] pci::PciRootError),
ReservePciDeviceId(#[source] pci::PciRootError),
/// Could not give the PCI device ID back.
#[error("Could not give the PCI device ID back")]
@@ -4550,8 +4550,8 @@ impl DeviceManager {
.pci_bus
.lock()
.unwrap()
.get_device_id(pci_device_bdf.device() as usize)
.map_err(DeviceManagerError::GetPciDeviceId)?;
.allocate_device_id(Some(pci_device_bdf.device()))
.map_err(DeviceManagerError::AllocatePciDeviceId)?;
(pci_segment_id, pci_device_bdf, resources)
} else {
+15 -4
View File
@@ -164,6 +164,17 @@ impl PciSegment {
)
}
/// Reserves a device ID on this PCI segment, marking it as in-use
/// so that automatic allocation will not use it.
pub(crate) fn reserve_device_id(&self, device_id: u8) -> DeviceManagerResult<()> {
self.pci_bus
.lock()
.unwrap()
.reserve_device_id(device_id)
.map_err(DeviceManagerError::ReservePciDeviceId)?;
Ok(())
}
/// Allocates a device's ID on this PCI segment.
///
/// - `device_id`: Device ID to request for allocation
@@ -613,17 +624,17 @@ mod unit_tests {
}
#[test]
// Test to acquire a device ID that is invalid, one that is already taken
// and one being greater than the number of allowed devices per bus.
// Test that reserving an already taken device ID fails and that
// allocating an out-of-range device ID fails.
fn allocate_device_id_invalid_device_id() {
// The first address is occupied by the root
let already_taken_device_id = 0x0_u8;
let overflow_device_id = 0xff_u8;
let segment = setup();
let bdf_res = segment.allocate_device_id(Some(already_taken_device_id));
let bdf_res = segment.reserve_device_id(already_taken_device_id);
assert!(matches!(
bdf_res,
Err(DeviceManagerError::GetPciDeviceId(e)) if matches!(
Err(DeviceManagerError::ReservePciDeviceId(e)) if matches!(
e,
pci::PciRootError::AlreadyInUsePciDeviceSlot(0x0)
)