1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
// SPDX-License-Identifier: MPL-2.0
#![allow(dead_code)]
use alloc::vec::Vec;
use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData};
use super::{
cfg_space::{PciDeviceCommonCfgOffset, Status},
common_device::PciCommonDevice,
PciDeviceLocation,
};
pub mod msix;
pub mod vendor;
#[derive(Debug)]
pub struct Capability {
id: u8,
/// Pointer to the capability.
pos: u16,
/// Next Capability pointer, 0xFC if self is the last one.
next_ptr: u16,
/// The length of this Capability
len: u16,
cap_data: CapabilityData,
}
#[derive(Debug, Clone)]
pub enum CapabilityData {
/// Id:0x01, Power Management
Pm,
/// Id:0x02, Accelerated Graphics Part
Agp,
/// Id:0x03, Vital Product Data
Vpd,
/// Id:0x04, Slot Identification
SlotId,
/// Id:0x05, Message Signalled Interrupts
Msi,
/// Id:0x06, CompactPCI HotSwap
Chswp,
/// Id:0x07, PCI-X
PciX,
/// Id:0x08, HyperTransport
Hp,
/// Id:0x09, Vendor-Specific
Vndr(CapabilityVndrData),
/// Id:0x0A, Debug port
Dbg,
/// Id:0x0B, CompactPCI Central Resource Control
Ccrc,
/// Id:0x0C, PCI Standard Hot-Plug Controller
Shpc,
/// Id:0x0D, Bridge subsystem vendor/device ID
Ssvid,
/// Id:0x0R, AGP Target PCI-PCI bridge
Agp3,
/// Id:0x0F, Secure Device
Secdev,
/// Id:0x10, PCI Express
Exp,
/// Id:0x11, MSI-X
Msix(CapabilityMsixData),
/// Id:0x12, SATA Data/Index Conf
Sata,
/// Id:0x13, PCI Advanced Features
Af,
/// Id:0x14, Enhanced Allocation
Ea,
/// Id:?, Unknown
Unknown(u8),
}
impl Capability {
/// 0xFC, the top of the capability position.
const CAPABILITY_TOP: u16 = 0xFC;
pub fn capability_data(&self) -> &CapabilityData {
&self.cap_data
}
/// get the capabilities of one device
pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> {
if !dev.status().contains(Status::CAPABILITIES_LIST) {
return Vec::new();
}
let mut capabilities = Vec::new();
let mut cap_ptr =
dev.location()
.read8(PciDeviceCommonCfgOffset::CapabilitiesPointer as u16) as u16
& PciDeviceLocation::BIT32_ALIGN_MASK;
let mut cap_ptr_vec = Vec::new();
// read all cap_ptr so that it is easy for us to get the length.
while cap_ptr > 0 {
cap_ptr_vec.push(cap_ptr);
cap_ptr =
dev.location().read8(cap_ptr + 1) as u16 & PciDeviceLocation::BIT32_ALIGN_MASK;
}
cap_ptr_vec.sort();
// Push here so that we can calculate the length of the last capability.
cap_ptr_vec.push(Self::CAPABILITY_TOP);
let length = cap_ptr_vec.len();
for i in 0..length - 1 {
let cap_ptr = cap_ptr_vec[i];
let next_ptr = cap_ptr_vec[i + 1];
let cap_type = dev.location().read8(cap_ptr);
let data = match cap_type {
0x01 => CapabilityData::Pm,
0x02 => CapabilityData::Agp,
0x03 => CapabilityData::Vpd,
0x04 => CapabilityData::SlotId,
0x05 => CapabilityData::Msi,
0x06 => CapabilityData::Chswp,
0x07 => CapabilityData::PciX,
0x08 => CapabilityData::Hp,
0x09 => {
CapabilityData::Vndr(CapabilityVndrData::new(dev, cap_ptr, next_ptr - cap_ptr))
}
0x0A => CapabilityData::Dbg,
0x0B => CapabilityData::Ccrc,
0x0C => CapabilityData::Shpc,
0x0D => CapabilityData::Ssvid,
0x0E => CapabilityData::Agp3,
0x0F => CapabilityData::Secdev,
0x10 => CapabilityData::Exp,
0x11 => CapabilityData::Msix(CapabilityMsixData::new(dev, cap_ptr)),
0x12 => CapabilityData::Sata,
0x13 => CapabilityData::Af,
0x14 => CapabilityData::Ea,
_ => CapabilityData::Unknown(cap_type),
};
capabilities.push(Self {
id: cap_type,
pos: cap_ptr,
next_ptr,
len: next_ptr - cap_ptr,
cap_data: data,
});
}
capabilities
}
}