use super::PciCapabilityAddress;
use crate::ConfigRegionAccess;
use bit_field::BitField;
#[derive(Clone, Copy, Debug)]
pub struct MsixCapability {
pub(super) address: PciCapabilityAddress,
table_size: u16,
table: u32,
pba: u32,
}
impl MsixCapability {
pub(crate) fn new(
address: PciCapabilityAddress,
control: u16,
access: impl ConfigRegionAccess,
) -> MsixCapability {
let table_size = control.get_bits(0..11) + 1;
let table = unsafe { access.read(address.address, address.offset + 0x04) };
let pba = unsafe { access.read(address.address, address.offset + 0x08) };
MsixCapability { address, table_size, table, pba }
}
pub fn set_enabled(&mut self, enabled: bool, access: impl ConfigRegionAccess) {
let mut control = unsafe { access.read(self.address.address, self.address.offset) };
control.set_bit(31, enabled);
unsafe {
access.write(self.address.address, self.address.offset, control);
}
}
pub fn enabled(&self, access: impl ConfigRegionAccess) -> bool {
let control = unsafe { access.read(self.address.address, self.address.offset) };
control.get_bit(31)
}
pub fn set_function_mask(&mut self, mask: bool, access: impl ConfigRegionAccess) {
let mut control = unsafe { access.read(self.address.address, self.address.offset) };
control.set_bit(30, mask);
unsafe {
access.write(self.address.address, self.address.offset, control);
}
}
pub fn function_mask(&self, access: impl ConfigRegionAccess) -> bool {
let control = unsafe { access.read(self.address.address, self.address.offset) };
control.get_bit(30)
}
pub fn table_bar(&self) -> u8 {
self.table.get_bits(0..3) as u8
}
pub fn table_offset(&self) -> u32 {
self.table & !0b111
}
pub fn table_size(&self) -> u16 {
self.table_size
}
pub fn pba_bar(&self) -> u8 {
self.pba.get_bits(0..3) as u8
}
pub fn pba_offset(&self) -> u32 {
self.pba & !0b111
}
}