pci_types/capability/
mod.rs

1use crate::{ConfigRegionAccess, PciAddress};
2use bit_field::BitField;
3use core::fmt::Formatter;
4
5mod msi;
6mod msix;
7
8pub use msi::{MsiCapability, MultipleMessageSupport, TriggerMode};
9pub use msix::MsixCapability;
10
11#[derive(Clone, Copy)]
12pub struct PciCapabilityAddress {
13    pub address: PciAddress,
14    pub offset: u16,
15}
16
17impl core::fmt::Debug for PciCapabilityAddress {
18    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
19        write!(f, "{}, offset: {:02x}", self.address, self.offset)
20    }
21}
22
23/// PCI capabilities
24#[derive(Clone, Copy, Debug)]
25pub enum PciCapability {
26    /// Power management capability, Cap ID = `0x01`
27    PowerManagement(PciCapabilityAddress),
28    /// Accelerated graphics port capability, Cap ID = `0x02`
29    AcceleratedGraphicsPort(PciCapabilityAddress),
30    /// Vital product data capability, Cap ID = `0x3`
31    VitalProductData(PciCapabilityAddress),
32    /// Slot identification capability, Cap ID = `0x04`
33    SlotIdentification(PciCapabilityAddress),
34    /// Message signalling interrupts capability, Cap ID = `0x05`
35    Msi(MsiCapability),
36    /// CompactPCI HotSwap capability, Cap ID = `0x06`
37    CompactPCIHotswap(PciCapabilityAddress),
38    /// PCI-X capability, Cap ID = `0x07`
39    PciX(PciCapabilityAddress),
40    /// HyperTransport capability, Cap ID = `0x08`
41    HyperTransport(PciCapabilityAddress),
42    /// Vendor-specific capability, Cap ID = `0x09`
43    Vendor(PciCapabilityAddress),
44    /// Debug port capability, Cap ID = `0x0A`
45    DebugPort(PciCapabilityAddress),
46    /// CompactPCI Central Resource Control capability, Cap ID = `0x0B`
47    CompactPCICentralResourceControl(PciCapabilityAddress),
48    /// PCI Standard Hot-Plug Controller capability, Cap ID = `0x0C`
49    PciHotPlugControl(PciCapabilityAddress),
50    /// Bridge subsystem vendor/device ID capability, Cap ID = `0x0D`
51    BridgeSubsystemVendorId(PciCapabilityAddress),
52    /// AGP Target PCI-PCI bridge capability, Cap ID = `0x0E`
53    AGP3(PciCapabilityAddress),
54    /// PCI Express capability, Cap ID = `0x10`
55    PciExpress(PciCapabilityAddress),
56    /// MSI-X capability, Cap ID = `0x11`
57    MsiX(MsixCapability),
58    /// Unknown capability
59    Unknown { address: PciCapabilityAddress, id: u8 },
60}
61
62impl PciCapability {
63    fn parse(
64        id: u8,
65        address: PciCapabilityAddress,
66        extension: u16,
67        access: impl ConfigRegionAccess,
68    ) -> Option<PciCapability> {
69        match id {
70            0x00 => None, // null capability
71            0x01 => Some(PciCapability::PowerManagement(address)),
72            0x02 => Some(PciCapability::AcceleratedGraphicsPort(address)),
73            0x03 => Some(PciCapability::VitalProductData(address)),
74            0x04 => Some(PciCapability::SlotIdentification(address)),
75            0x05 => Some(PciCapability::Msi(MsiCapability::new(address, extension))),
76            0x06 => Some(PciCapability::CompactPCIHotswap(address)),
77            0x07 => Some(PciCapability::PciX(address)),
78            0x08 => Some(PciCapability::HyperTransport(address)),
79            0x09 => Some(PciCapability::Vendor(address)),
80            0x0A => Some(PciCapability::DebugPort(address)),
81            0x0B => Some(PciCapability::CompactPCICentralResourceControl(address)),
82            0x0C => Some(PciCapability::PciHotPlugControl(address)),
83            0x0D => Some(PciCapability::BridgeSubsystemVendorId(address)),
84            0x0E => Some(PciCapability::AGP3(address)),
85            0x10 => Some(PciCapability::PciExpress(address)),
86            0x11 => Some(PciCapability::MsiX(MsixCapability::new(address, extension, access))),
87            _ => Some(PciCapability::Unknown { address, id }),
88        }
89    }
90
91    pub fn address(&self) -> PciCapabilityAddress {
92        match *self {
93            PciCapability::PowerManagement(address) => address,
94            PciCapability::AcceleratedGraphicsPort(address) => address,
95            PciCapability::VitalProductData(address) => address,
96            PciCapability::SlotIdentification(address) => address,
97            PciCapability::Msi(msi_cap) => msi_cap.address,
98            PciCapability::CompactPCIHotswap(address) => address,
99            PciCapability::PciX(address) => address,
100            PciCapability::HyperTransport(address) => address,
101            PciCapability::Vendor(address) => address,
102            PciCapability::DebugPort(address) => address,
103            PciCapability::CompactPCICentralResourceControl(address) => address,
104            PciCapability::PciHotPlugControl(address) => address,
105            PciCapability::BridgeSubsystemVendorId(address) => address,
106            PciCapability::AGP3(address) => address,
107            PciCapability::PciExpress(address) => address,
108            PciCapability::MsiX(msix_cap) => msix_cap.address,
109            PciCapability::Unknown { address, id: _ } => address,
110        }
111    }
112}
113
114pub struct CapabilityIterator<T: ConfigRegionAccess> {
115    address: PciAddress,
116    offset: u16,
117    access: T,
118}
119
120impl<T: ConfigRegionAccess> CapabilityIterator<T> {
121    pub(crate) fn new(address: PciAddress, offset: u16, access: T) -> CapabilityIterator<T> {
122        CapabilityIterator { address, offset, access }
123    }
124}
125
126impl<T: ConfigRegionAccess> Iterator for CapabilityIterator<T> {
127    type Item = PciCapability;
128
129    fn next(&mut self) -> Option<Self::Item> {
130        loop {
131            if self.offset == 0 {
132                return None;
133            }
134            let data = unsafe { self.access.read(self.address, self.offset) };
135            let next_ptr = data.get_bits(8..16);
136            let id = data.get_bits(0..8);
137            let extension = data.get_bits(16..32) as u16;
138            let cap = PciCapability::parse(
139                id as u8,
140                PciCapabilityAddress { address: self.address, offset: self.offset },
141                extension,
142                &self.access,
143            );
144            self.offset = next_ptr as u16;
145            if let Some(cap) = cap {
146                return Some(cap);
147            }
148        }
149    }
150}