Skip to content

feat: don't take explicit references to ConfigRegionAccess #22

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

Merged
merged 3 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/capability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl PciCapability {
id: u8,
address: PciCapabilityAddress,
extension: u16,
access: &impl ConfigRegionAccess,
access: impl ConfigRegionAccess,
) -> Option<PciCapability> {
match id {
0x00 => None, // null capability
Expand All @@ -89,19 +89,19 @@ impl PciCapability {
}
}

pub struct CapabilityIterator<'a, T: ConfigRegionAccess> {
pub struct CapabilityIterator<T: ConfigRegionAccess> {
address: PciAddress,
offset: u16,
access: &'a T,
access: T,
}

impl<'a, T: ConfigRegionAccess> CapabilityIterator<'a, T> {
pub(crate) fn new(address: PciAddress, offset: u16, access: &'a T) -> CapabilityIterator<'a, T> {
impl<T: ConfigRegionAccess> CapabilityIterator<T> {
pub(crate) fn new(address: PciAddress, offset: u16, access: T) -> CapabilityIterator<T> {
CapabilityIterator { address, offset, access }
}
}

impl<'a, T: ConfigRegionAccess> Iterator for CapabilityIterator<'a, T> {
impl<T: ConfigRegionAccess> Iterator for CapabilityIterator<T> {
type Item = PciCapability;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -117,7 +117,7 @@ impl<'a, T: ConfigRegionAccess> Iterator for CapabilityIterator<'a, T> {
id as u8,
PciCapabilityAddress { address: self.address, offset: self.offset },
extension,
self.access,
&self.access,
);
self.offset = next_ptr as u16;
if let Some(cap) = cap {
Expand Down
18 changes: 9 additions & 9 deletions src/capability/msi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,33 +82,33 @@ impl MsiCapability {
self.multiple_message_capable
}

pub fn ctrl(&self, access: &impl ConfigRegionAccess) -> u32 {
pub fn ctrl(&self, access: impl ConfigRegionAccess) -> u32 {
unsafe { access.read(self.address.address, self.address.offset) }
}

/// Is MSI capability enabled?
pub fn is_enabled(&self, access: &impl ConfigRegionAccess) -> bool {
pub fn is_enabled(&self, access: impl ConfigRegionAccess) -> bool {
let reg = unsafe { access.read(self.address.address, self.address.offset) };
reg.get_bit(16)
}

/// Enable or disable MSI capability
pub fn set_enabled(&self, enabled: bool, access: &impl ConfigRegionAccess) {
pub fn set_enabled(&self, enabled: bool, access: impl ConfigRegionAccess) {
let mut reg = unsafe { access.read(self.address.address, self.address.offset) };
reg.set_bit(16, enabled);
unsafe { access.write(self.address.address, self.address.offset, reg) };
}

/// Set how many interrupts the device will use. If requested count is bigger than supported count,
/// the second will be used.
pub fn set_multiple_message_enable(&self, data: MultipleMessageSupport, access: &impl ConfigRegionAccess) {
pub fn set_multiple_message_enable(&self, data: MultipleMessageSupport, access: impl ConfigRegionAccess) {
let mut reg = unsafe { access.read(self.address.address, self.address.offset) };
reg.set_bits(4..7, (data.min(self.multiple_message_capable)) as u32);
unsafe { access.write(self.address.address, self.address.offset, reg) };
}

/// Return how many interrupts the device is using
pub fn get_multiple_message_enable(&self, access: &impl ConfigRegionAccess) -> MultipleMessageSupport {
pub fn get_multiple_message_enable(&self, access: impl ConfigRegionAccess) -> MultipleMessageSupport {
let reg = unsafe { access.read(self.address.address, self.address.offset) };
MultipleMessageSupport::try_from(reg.get_bits(4..7) as u8).unwrap_or(MultipleMessageSupport::Int1)
}
Expand All @@ -125,7 +125,7 @@ impl MsiCapability {
address: u32,
vector: u8,
trigger_mode: TriggerMode,
access: &impl ConfigRegionAccess,
access: impl ConfigRegionAccess,
) {
unsafe { access.write(self.address.address, self.address.offset + 0x4, address) }
let data_offset = if self.is_64bit { 0xC } else { 0x8 };
Expand All @@ -140,7 +140,7 @@ impl MsiCapability {
/// # Note
/// Only supported on when device supports 64-bit addressing and per-vector masking. Otherwise
/// returns `0`
pub fn get_message_mask(&self, access: &impl ConfigRegionAccess) -> u32 {
pub fn get_message_mask(&self, access: impl ConfigRegionAccess) -> u32 {
if self.is_64bit && self.per_vector_masking {
unsafe { access.read(self.address.address, self.address.offset + 0x10) }
} else {
Expand All @@ -153,7 +153,7 @@ impl MsiCapability {
/// # Note
/// Only supported on when device supports 64-bit addressing and per-vector masking. Otherwise
/// will do nothing
pub fn set_message_mask(&self, access: &impl ConfigRegionAccess, mask: u32) {
pub fn set_message_mask(&self, access: impl ConfigRegionAccess, mask: u32) {
if self.is_64bit && self.per_vector_masking {
unsafe { access.write(self.address.address, self.address.offset + 0x10, mask) }
}
Expand All @@ -163,7 +163,7 @@ impl MsiCapability {
///
/// # Note
/// Only supported on when device supports 64-bit addressing. Otherwise will return `0`
pub fn get_pending(&self, access: &impl ConfigRegionAccess) -> u32 {
pub fn get_pending(&self, access: impl ConfigRegionAccess) -> u32 {
if self.is_64bit {
unsafe { access.read(self.address.address, self.address.offset + 0x14) }
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/capability/msix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl MsixCapability {
pub(crate) fn new(
address: PciCapabilityAddress,
control: u16,
access: &impl ConfigRegionAccess,
access: impl ConfigRegionAccess,
) -> MsixCapability {
let table_size = control.get_bits(0..11) + 1;
let table = unsafe { access.read(address.address, address.offset + 0x04) };
Expand All @@ -31,7 +31,7 @@ impl MsixCapability {
/// `[MsixCapability::table_bar]` and `[MsixCapability::table_offset]`. The caller is therefore
/// responsible for configuring this separately, as this crate does not have access to
/// arbitrary physical memory.
pub fn set_enabled(&mut self, enabled: bool, access: &impl ConfigRegionAccess) {
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 {
Expand Down
71 changes: 44 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ pub trait ConfigRegionAccess {
unsafe fn write(&self, address: PciAddress, offset: u16, value: u32);
}

impl<T: ConfigRegionAccess + ?Sized> ConfigRegionAccess for &T {
#[inline]
fn function_exists(&self, address: PciAddress) -> bool {
(**self).function_exists(address)
}

#[inline]
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
(**self).read(address, offset)
}

#[inline]
unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) {
(**self).write(address, offset, value)
}
}

#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum HeaderType {
Expand Down Expand Up @@ -129,12 +146,12 @@ impl PciHeader {
PciHeader(address)
}

pub fn id(&self, access: &impl ConfigRegionAccess) -> (VendorId, DeviceId) {
pub fn id(&self, access: impl ConfigRegionAccess) -> (VendorId, DeviceId) {
let id = unsafe { access.read(self.0, 0x00) };
(id.get_bits(0..16) as VendorId, id.get_bits(16..32) as DeviceId)
}

pub fn header_type(&self, access: &impl ConfigRegionAccess) -> HeaderType {
pub fn header_type(&self, access: impl ConfigRegionAccess) -> HeaderType {
/*
* Read bits 0..=6 of the Header Type. Bit 7 dictates whether the device has multiple functions and so
* isn't returned here.
Expand All @@ -147,7 +164,7 @@ impl PciHeader {
}
}

pub fn has_multiple_functions(&self, access: &impl ConfigRegionAccess) -> bool {
pub fn has_multiple_functions(&self, access: impl ConfigRegionAccess) -> bool {
/*
* Reads bit 7 of the Header Type, which is 1 if the device has multiple functions.
*/
Expand All @@ -156,7 +173,7 @@ impl PciHeader {

pub fn revision_and_class(
&self,
access: &impl ConfigRegionAccess,
access: impl ConfigRegionAccess,
) -> (DeviceRevision, BaseClass, SubClass, Interface) {
let field = unsafe { access.read(self.0, 0x08) };
(
Expand All @@ -167,17 +184,17 @@ impl PciHeader {
)
}

pub fn status(&self, access: &impl ConfigRegionAccess) -> StatusRegister {
pub fn status(&self, access: impl ConfigRegionAccess) -> StatusRegister {
let data = unsafe { access.read(self.0, 0x4).get_bits(16..32) };
StatusRegister::new(data as u16)
}

pub fn command(&self, access: &impl ConfigRegionAccess) -> CommandRegister {
pub fn command(&self, access: impl ConfigRegionAccess) -> CommandRegister {
let data = unsafe { access.read(self.0, 0x4).get_bits(0..16) };
CommandRegister::from_bits_retain(data as u16)
}

pub fn update_command<F>(&self, access: &impl ConfigRegionAccess, f: F)
pub fn update_command<F>(&self, access: impl ConfigRegionAccess, f: F)
where
F: FnOnce(CommandRegister) -> CommandRegister,
{
Expand Down Expand Up @@ -239,7 +256,7 @@ impl PciHeader {
pub struct EndpointHeader(PciAddress);

impl EndpointHeader {
pub fn from_header(header: PciHeader, access: &impl ConfigRegionAccess) -> Option<EndpointHeader> {
pub fn from_header(header: PciHeader, access: impl ConfigRegionAccess) -> Option<EndpointHeader> {
match header.header_type(access) {
HeaderType::Endpoint => Some(EndpointHeader(header.0)),
_ => None,
Expand All @@ -250,36 +267,36 @@ impl EndpointHeader {
PciHeader(self.0)
}

pub fn status(&self, access: &impl ConfigRegionAccess) -> StatusRegister {
pub fn status(&self, access: impl ConfigRegionAccess) -> StatusRegister {
self.header().status(access)
}

pub fn command(&self, access: &impl ConfigRegionAccess) -> CommandRegister {
pub fn command(&self, access: impl ConfigRegionAccess) -> CommandRegister {
self.header().command(access)
}

pub fn update_command<F>(&self, access: &impl ConfigRegionAccess, f: F)
pub fn update_command<F>(&self, access: impl ConfigRegionAccess, f: F)
where
F: FnOnce(CommandRegister) -> CommandRegister,
{
self.header().update_command(access, f);
}

pub fn capability_pointer(&self, access: &impl ConfigRegionAccess) -> u16 {
let status = self.status(access);
pub fn capability_pointer(&self, access: impl ConfigRegionAccess) -> u16 {
let status = self.status(&access);
if status.has_capability_list() {
unsafe { access.read(self.0, 0x34).get_bits(0..8) as u16 }
} else {
0
}
}

pub fn capabilities<'a, T: ConfigRegionAccess>(&self, access: &'a T) -> CapabilityIterator<'a, T> {
let pointer = self.capability_pointer(access);
pub fn capabilities<T: ConfigRegionAccess>(&self, access: T) -> CapabilityIterator<T> {
let pointer = self.capability_pointer(&access);
CapabilityIterator::new(self.0, pointer, access)
}

pub fn subsystem(&self, access: &impl ConfigRegionAccess) -> (SubsystemId, SubsystemVendorId) {
pub fn subsystem(&self, access: impl ConfigRegionAccess) -> (SubsystemId, SubsystemVendorId) {
let data = unsafe { access.read(self.0, 0x2c) };
(data.get_bits(16..32) as u16, data.get_bits(0..16) as u16)
}
Expand All @@ -289,7 +306,7 @@ impl EndpointHeader {
/// ### Note
/// 64-bit memory BARs use two slots, so if one is decoded in e.g. slot #0, this method should not be called
/// for slot #1
pub fn bar(&self, slot: u8, access: &impl ConfigRegionAccess) -> Option<Bar> {
pub fn bar(&self, slot: u8, access: impl ConfigRegionAccess) -> Option<Bar> {
if slot >= 6 {
return None;
}
Expand Down Expand Up @@ -380,10 +397,10 @@ impl EndpointHeader {
pub unsafe fn write_bar(
&mut self,
slot: u8,
access: &impl ConfigRegionAccess,
access: impl ConfigRegionAccess,
value: usize,
) -> Result<(), BarWriteError> {
match self.bar(slot, access) {
match self.bar(slot, &access) {
Some(Bar::Memory64 { .. }) => {
let offset = 0x10 + (slot as u16) * 4;
unsafe {
Expand All @@ -407,7 +424,7 @@ impl EndpointHeader {
}
}

pub fn interrupt(&self, access: &impl ConfigRegionAccess) -> (InterruptPin, InterruptLine) {
pub fn interrupt(&self, access: impl ConfigRegionAccess) -> (InterruptPin, InterruptLine) {
// According to the PCI Express Specification 4.0, Min_Gnt/Max_Lat registers
// must be read-only and hardwired to 00h.
let data = unsafe { access.read(self.0, 0x3c) };
Expand Down Expand Up @@ -477,7 +494,7 @@ impl EndpointHeader {
pub struct PciPciBridgeHeader(PciAddress);

impl PciPciBridgeHeader {
pub fn from_header(header: PciHeader, access: &impl ConfigRegionAccess) -> Option<PciPciBridgeHeader> {
pub fn from_header(header: PciHeader, access: impl ConfigRegionAccess) -> Option<PciPciBridgeHeader> {
match header.header_type(access) {
HeaderType::PciPciBridge => Some(PciPciBridgeHeader(header.0)),
_ => None,
Expand All @@ -488,32 +505,32 @@ impl PciPciBridgeHeader {
PciHeader(self.0)
}

pub fn status(&self, access: &impl ConfigRegionAccess) -> StatusRegister {
pub fn status(&self, access: impl ConfigRegionAccess) -> StatusRegister {
self.header().status(access)
}

pub fn command(&self, access: &impl ConfigRegionAccess) -> CommandRegister {
pub fn command(&self, access: impl ConfigRegionAccess) -> CommandRegister {
self.header().command(access)
}

pub fn update_command<F>(&self, access: &impl ConfigRegionAccess, f: F)
pub fn update_command<F>(&self, access: impl ConfigRegionAccess, f: F)
where
F: FnOnce(CommandRegister) -> CommandRegister,
{
self.header().update_command(access, f);
}

pub fn primary_bus_number(&self, access: &impl ConfigRegionAccess) -> u8 {
pub fn primary_bus_number(&self, access: impl ConfigRegionAccess) -> u8 {
let data = unsafe { access.read(self.0, 0x18).get_bits(0..8) };
data as u8
}

pub fn secondary_bus_number(&self, access: &impl ConfigRegionAccess) -> u8 {
pub fn secondary_bus_number(&self, access: impl ConfigRegionAccess) -> u8 {
let data = unsafe { access.read(self.0, 0x18).get_bits(8..16) };
data as u8
}

pub fn subordinate_bus_number(&self, access: &impl ConfigRegionAccess) -> u8 {
pub fn subordinate_bus_number(&self, access: impl ConfigRegionAccess) -> u8 {
let data = unsafe { access.read(self.0, 0x18).get_bits(16..24) };
data as u8
}
Expand Down