use crate::{
AcpiError,
AcpiTables,
Handler,
sdt::{
Signature,
mcfg::{Mcfg, McfgEntry},
},
};
use alloc::{
alloc::{Allocator, Global},
vec::Vec,
};
pub struct PciConfigRegions<A: Allocator = Global> {
pub regions: Vec<McfgEntry, A>,
}
impl PciConfigRegions<Global> {
pub fn new<H>(tables: &AcpiTables<H>) -> Result<PciConfigRegions<Global>, AcpiError>
where
H: Handler,
{
Self::new_in(tables, Global)
}
}
impl<A: Allocator> PciConfigRegions<A> {
pub fn new_in<H>(tables: &AcpiTables<H>, allocator: A) -> Result<PciConfigRegions<A>, AcpiError>
where
H: Handler,
{
let Some(mcfg) = tables.find_table::<Mcfg>() else { Err(AcpiError::TableNotFound(Signature::MCFG))? };
let regions = mcfg.entries().to_vec_in(allocator);
Ok(Self { regions })
}
pub fn physical_address(&self, segment_group_no: u16, bus: u8, device: u8, function: u8) -> Option<u64> {
let region = self.regions.iter().find(|region| {
region.pci_segment_group == segment_group_no
&& (region.bus_number_start..=region.bus_number_end).contains(&bus)
})?;
Some(
region.base_address
+ ((u64::from(bus - region.bus_number_start) << 20)
| (u64::from(device) << 15)
| (u64::from(function) << 12)),
)
}
}