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
use super::bar::{Bar, IoSpace, MemorySpace};
use super::cap::CapabilityIterator;
use super::{PciAccessor, PciDevice};
use crate::addressing::Pa;
bitflags::bitflags! {
/// Pci device status.
pub struct Status: u16 {
/// This bit will be set to 1 whenever the device detects a parity error, even if parity error handling is disabled.
const DETECTED_PARITY_ERROR = 1 << 15;
/// This bit will be set to 1 whenever the device asserts SERR#.
const SIGNALLED_SYSTEM_ERROR = 1 << 14;
/// This bit will be set to 1, by a master device, whenever its transaction (except for Special Cycle transactions) is terminated with Master-Abort.
const RECEIVED_MASTER_ABORT = 1 << 13;
/// This bit will be set to 1, by a master device, whenever its transaction is terminated with Target-Abort.
const RECEIVED_TARGET_ABORT = 1 << 12;
/// This bit will be set to 1 whenever a target device terminates a transaction with Target-Abort.
const SIGNALLED_TARGET_ABORT = 1 << 11;
/// Read only bits that represent the slowest time that a device will assert DEVSEL# for any bus command except Configuration Space read and writes. Where a value of 0x00 represents fast timing, a value of 0x01 represents medium timing, and a value of 0x02 represents slow timing.
const DEVSEL_TIMING = 1 << 10;
/// This bit is only set when the following conditions are met. The bus agent asserted PERR# on a read or observed an assertion of PERR# on a write, the agent setting the bit acted as the bus master for the operation in which the error occurred, and bit 6 of the Command register (Parity Error Response bit) is set to 1.
const MASTER_DATA_PARITY_ERROR = 1 << 9;
/// If set to 1 the device can accept fast back-to-back transactions that are not from the same agent; otherwise, transactions can only be accepted from the same agent.
const FAST_BACK_TO_BACK_CAPABLE = 1 << 8;
/// If set to 1 the device is capable of running at 66 MHz; otherwise, the device runs at 33 MHz.
const MHZ66_CAPABLE = 1 << 5;
/// If set to 1 the device implements the pointer for a New Capabilities Linked list at offset 0x34; otherwise, the linked list is not available.
const CAPABILITIES_LIST = 1 << 4;
/// Represents the state of the device's INTx# signal. If set to 1 and bit 10 of the Command register (Interrupt Disable bit) is set to 0 the signal will be asserted; otherwise, the signal will be ignored
const INTERRUPT_STATUS = 1 << 3;
}
}
// register offset bits 31-24 bits 23-16 bits 15-8 bits 7-0
// 00 00 Device ID Vendor ID
// 01 04 Status Command
// 02 08 Class code Subclass Prog IF Revision ID
// 03 0C BIST Header type Latency Timer Cache Line Size
// 04 10 Base address #0 (BAR0)
// 05 14 Base address #1 (BAR1)
// 06 18 Base address #2 (BAR2)
// 07 1C Base address #3 (BAR3)
// 08 20 Base address #4 (BAR4)
// 09 24 Base address #5 (BAR5)
// 0A 28 Cardbus CIS Pointer
// 0B 2C Subsystem ID Subsystem Vendor ID
// 0C 30 Expansion ROM base address
// 0D 34 Reserved Capabilities Pointer
// 0E 38 Reserved
// 0F 3C Max latency Min Grant Interrupt PIN Interrupt Line
/// Generic implementation of PciHeaderType.
#[derive(Debug, Clone, Copy)]
pub struct PciHeader<const V: usize> {
pub(crate) pci_device: PciDevice,
pub(crate) function: u8,
}
impl<const V: usize> PciHeader<V> {
#[inline(always)]
pub fn accessor(&self, off: u8) -> PciAccessor {
PciAccessor::new(
self.pci_device.bus,
self.pci_device.device,
self.function,
off,
)
}
}
impl PciHeader<0> {
/// Get status of the device.
#[inline]
pub fn status(&self) -> Status {
Status::from_bits_truncate((self.accessor(0x4).read_u32() >> 16) as u16)
}
/// Get iterator for enumerating the capabilties of device.
#[inline]
pub fn capabilities(&self) -> CapabilityIterator<0> {
CapabilityIterator {
next: if self.status().contains(Status::CAPABILITIES_LIST) {
self.accessor(0x34).read_u8()
} else {
0
},
pci_header: self,
}
}
/// Get BAR of the device.
#[inline]
pub fn bar(&self, index: u8) -> Option<Bar> {
if index > 5 {
return None;
}
let bar_accessor = self.accessor(0x10 + 4 * index);
let bar = bar_accessor.read_u32();
// Resolve length.
bar_accessor.write_u32(u32::MAX);
let bar_length = bar_accessor.read_u32();
bar_accessor.write_u32(bar);
if bar & 1 == 1 {
Some(Bar::IoSpace(IoSpace {
base: bar & !3,
length: !(bar_length & !0b11) + 1,
}))
} else {
let (prefetchable, ty) = (bar & 8 == 8, (bar >> 1) & 3);
let addr = match ty {
0 => (bar & !0xf) as usize,
2 if index <= 4 => {
(((bar & !0xf) as u64)
| ((self.accessor(0x10 + 4 * index + 4).read_u32() as u64) << 32))
as usize
}
// 1 => reserved.
_ => return None,
};
Pa::new(addr).map(|base| {
Bar::MemorySpace(MemorySpace {
base,
length: (!(bar_length & !0b1111) + 1) as usize,
_prefetchable: prefetchable,
})})
}
}
}