-
Notifications
You must be signed in to change notification settings - Fork 2
Configurable PCI BDF Device IDs #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: gardenlinux
Are you sure you want to change the base?
Changes from all commits
9618d2e
9efc3ad
ee66fc1
fbd3b93
1ca7c38
3035868
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,15 +166,42 @@ impl PciBus { | |
| Ok(()) | ||
| } | ||
|
|
||
| pub fn next_device_id(&mut self) -> Result<u32> { | ||
| for (idx, device_id) in self.device_ids.iter_mut().enumerate() { | ||
| if !(*device_id) { | ||
| *device_id = true; | ||
| return Ok(idx as u32); | ||
| /// Allocates a PCI device ID on the bus. | ||
| /// | ||
| /// - `id`: ID to allocate on the bus. If [`None`], the next free | ||
| /// device ID on the bus is allocated, else the ID given is | ||
| /// allocated | ||
| /// | ||
| /// ## Errors | ||
| /// * Returns [`PciRootError::AlreadyInUsePciDeviceSlot`] in case | ||
| /// the ID requested is already allocated. | ||
| /// * Returns [`PciRootError::InvalidPciDeviceSlot`] in case the | ||
| /// requested ID exceeds the maximum number of devices allowed per | ||
| /// bus (see [`NUM_DEVICE_IDS`]). | ||
| /// * If `id` is [`None`]: Returns | ||
| /// [`PciRootError::NoPciDeviceSlotAvailable`] if no free device | ||
| /// slot is available on the bus. | ||
| pub fn allocate_device_id(&mut self, id: Option<u8>) -> Result<u32> { | ||
| if let Some(id) = id { | ||
| if (id as usize) < NUM_DEVICE_IDS { | ||
| if !self.device_ids[id as usize] { | ||
| self.device_ids[id as usize] = true; | ||
| Ok(id as u32) | ||
| } else { | ||
| Err(PciRootError::AlreadyInUsePciDeviceSlot(id as usize)) | ||
| } | ||
| } else { | ||
| Err(PciRootError::InvalidPciDeviceSlot(id as usize)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
| } | ||
| } else { | ||
| for (idx, device_id) in self.device_ids.iter_mut().enumerate() { | ||
| if !(*device_id) { | ||
| *device_id = true; | ||
| return Ok(idx as u32); | ||
| } | ||
| } | ||
| Err(PciRootError::NoPciDeviceSlotAvailable) | ||
| } | ||
|
|
||
| Err(PciRootError::NoPciDeviceSlotAvailable) | ||
| } | ||
|
|
||
| pub fn get_device_id(&mut self, id: usize) -> Result<()> { | ||
|
|
@@ -484,3 +511,98 @@ fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize) | |
| shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK), | ||
| ) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| // Note this useful idiom: importing names from outer (for mod tests) scope. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this comment from ChatGPT? :D |
||
| use super::*; | ||
|
|
||
| mod pci_bus_tests { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you are already in |
||
| use super::*; | ||
|
|
||
| #[derive(Debug)] | ||
| struct MocRelocDevice; | ||
|
|
||
| impl DeviceRelocation for MocRelocDevice { | ||
| fn move_bar( | ||
| &self, | ||
| _old_base: u64, | ||
| _new_base: u64, | ||
| _len: u64, | ||
| _pci_dev: &mut dyn PciDevice, | ||
| _region_type: PciBarRegionType, | ||
| ) -> std::result::Result<(), std::io::Error> { | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| fn setup_bus() -> PciBus { | ||
| let pci_root = PciRoot::new(None); | ||
| let moc_device_reloc = Arc::new(MocRelocDevice {}); | ||
| PciBus::new(pci_root, moc_device_reloc) | ||
| } | ||
|
|
||
| #[test] | ||
| // Test to acquire all IDs that can be acquired | ||
| fn allocate_device_id_next_free() { | ||
| // The first address is occupied by the root | ||
| let mut bus = setup_bus(); | ||
| for expected_id in 1..NUM_DEVICE_IDS { | ||
| assert_eq!(expected_id as u32, bus.allocate_device_id(None).unwrap()); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| // Test that requesting specific ID work | ||
| fn allocate_device_id_request_id() -> std::result::Result<(), Box<dyn std::error::Error>> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please return |
||
| // The first address is occupied by the root | ||
| let mut bus = setup_bus(); | ||
| let max_id = (NUM_DEVICE_IDS - 1).try_into()?; | ||
| assert_eq!(0x01_u32, bus.allocate_device_id(Some(0x01))?); | ||
| assert_eq!(0x10_u32, bus.allocate_device_id(Some(0x10))?); | ||
| assert_eq!(max_id as u32, bus.allocate_device_id(Some(max_id))?); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| // Test that requesting the same ID twice fails | ||
| fn allocate_device_id_request_id_twice_fails() | ||
| -> std::result::Result<(), Box<dyn std::error::Error>> { | ||
| let mut bus = setup_bus(); | ||
| let max_id = (NUM_DEVICE_IDS - 1).try_into()?; | ||
| bus.allocate_device_id(Some(max_id))?; | ||
| let _result = bus.allocate_device_id(Some(max_id)); | ||
| assert!(matches!( | ||
| PciRootError::AlreadyInUsePciDeviceSlot(max_id.into()), | ||
| _result | ||
| )); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| // Test to request an invalid ID | ||
| fn allocate_device_id_request_invalid_id_fails() | ||
| -> std::result::Result<(), Box<dyn std::error::Error>> { | ||
| let mut bus = setup_bus(); | ||
| let max_id = (NUM_DEVICE_IDS + 1).try_into()?; | ||
| let _result = bus.allocate_device_id(Some(max_id)); | ||
| assert!(matches!( | ||
| PciRootError::InvalidPciDeviceSlot(max_id.into()), | ||
| _result | ||
| )); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| // Test to acquire an ID when all IDs were already acquired | ||
| fn allocate_device_id_none_left() { | ||
| // The first address is occupied by the root | ||
| let mut bus = setup_bus(); | ||
| for expected_id in 1..NUM_DEVICE_IDS { | ||
| assert_eq!(expected_id as u32, bus.allocate_device_id(None).unwrap()); | ||
| } | ||
| let _result = bus.allocate_device_id(None); | ||
| assert!(matches!(PciRootError::NoPciDeviceSlotAvailable, _result)); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this changes should be merged into the commit where you introduced these lines, please