pci_core/spec.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Types and constants specified by the PCI spec.
5//!
6//! This module MUST NOT contain any vendor-specific constants!
7
8pub mod hwid {
9 //! Hardware ID types and constants
10
11 #![expect(missing_docs)] // constants/fields are self-explanatory
12
13 use core::fmt;
14 use inspect::Inspect;
15
16 /// A collection of hard-coded hardware IDs specific to a particular PCI
17 /// device, as reflected in their corresponding PCI configuration space
18 /// registers.
19 ///
20 /// See PCI 2.3 Spec - 6.2.1 for details on each of these fields.
21 #[derive(Debug, Copy, Clone, Inspect)]
22 pub struct HardwareIds {
23 #[inspect(hex)]
24 pub vendor_id: u16,
25 #[inspect(hex)]
26 pub device_id: u16,
27 #[inspect(hex)]
28 pub revision_id: u8,
29 pub prog_if: ProgrammingInterface,
30 pub sub_class: Subclass,
31 pub base_class: ClassCode,
32 // TODO: this struct should be re-jigged when adding support for other
33 // header types (e.g: type 1)
34 #[inspect(hex)]
35 pub type0_sub_vendor_id: u16,
36 #[inspect(hex)]
37 pub type0_sub_system_id: u16,
38 }
39
40 open_enum::open_enum! {
41 /// ClassCode identifies the PCI device's type.
42 ///
43 /// Values pulled from <https://wiki.osdev.org/PCI#Class_Codes>.
44 #[derive(Inspect)]
45 #[inspect(display)]
46 pub enum ClassCode: u8 {
47 UNCLASSIFIED = 0x00,
48 MASS_STORAGE_CONTROLLER = 0x01,
49 NETWORK_CONTROLLER = 0x02,
50 DISPLAY_CONTROLLER = 0x03,
51 MULTIMEDIA_CONTROLLER = 0x04,
52 MEMORY_CONTROLLER = 0x05,
53 BRIDGE = 0x06,
54 SIMPLE_COMMUNICATION_CONTROLLER = 0x07,
55 BASE_SYSTEM_PERIPHERAL = 0x08,
56 INPUT_DEVICE_CONTROLLER = 0x09,
57 DOCKING_STATION = 0x0A,
58 PROCESSOR = 0x0B,
59 SERIAL_BUS_CONTROLLER = 0x0C,
60 WIRELESS_CONTROLLER = 0x0D,
61 INTELLIGENT_CONTROLLER = 0x0E,
62 SATELLITE_COMMUNICATION_CONTROLLER = 0x0F,
63 ENCRYPTION_CONTROLLER = 0x10,
64 SIGNAL_PROCESSING_CONTROLLER = 0x11,
65 PROCESSING_ACCELERATOR = 0x12,
66 NONESSENTIAL_INSTRUMENTATION = 0x13,
67 // 0x14 - 0x3F: Reserved
68 CO_PROCESSOR = 0x40,
69 // 0x41 - 0xFE: Reserved
70 /// Vendor specific
71 UNASSIGNED = 0xFF,
72 }
73 }
74
75 impl ClassCode {
76 pub fn is_reserved(&self) -> bool {
77 let c = &self.0;
78 (0x14..=0x3f).contains(c) || (0x41..=0xfe).contains(c)
79 }
80 }
81
82 impl fmt::Display for ClassCode {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 if self.is_reserved() {
85 return write!(f, "RESERVED({:#04x})", self.0);
86 }
87 fmt::Debug::fmt(self, f)
88 }
89 }
90
91 impl From<u8> for ClassCode {
92 fn from(c: u8) -> Self {
93 Self(c)
94 }
95 }
96
97 impl From<ClassCode> for u8 {
98 fn from(c: ClassCode) -> Self {
99 c.0
100 }
101 }
102
103 // Most subclass/programming interface values aren't used, and don't have names that can easily be made into variable
104 // identifiers (eg, "ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering").
105 //
106 // Therefore, only add values as needed.
107
108 open_enum::open_enum! {
109 /// SubclassCode identifies the PCI device's function.
110 ///
111 /// Values pulled from <https://wiki.osdev.org/PCI#Class_Codes>.
112 #[derive(Inspect)]
113 #[inspect(transparent(hex))]
114 pub enum Subclass: u8 {
115 // TODO: As more values are used, add them here.
116
117 NONE = 0x00,
118
119 // Mass Storage Controller (Class code: 0x01)
120 MASS_STORAGE_CONTROLLER_SCSI = 0x00,
121 MASS_STORAGE_CONTROLLER_NON_VOLATILE_MEMORY = 0x08,
122
123 // Network Controller (Class code: 0x02)
124 // Other values: 0x01 - 0x08, 0x80
125 NETWORK_CONTROLLER_ETHERNET = 0x00,
126
127 // Simple Communication Controller (Class code: 0x07)
128 // Other values: 0x00 - 0x07
129 SIMPLE_COMMUNICATION_CONTROLLER_OTHER = 0x80,
130
131 // Bridge (Class code: 0x06)
132 // Other values: 0x02 - 0x0A
133 BRIDGE_HOST = 0x00,
134 BRIDGE_ISA = 0x01,
135 BRIDGE_PCI_TO_PCI = 0x04,
136 BRIDGE_OTHER = 0x80,
137
138 // Base System Peripheral (Class code: 0x08)
139 // Other values: 0x00 - 0x06
140 BASE_SYSTEM_PERIPHERAL_OTHER = 0x80,
141 }
142 }
143
144 impl From<u8> for Subclass {
145 fn from(c: u8) -> Self {
146 Self(c)
147 }
148 }
149
150 impl From<Subclass> for u8 {
151 fn from(c: Subclass) -> Self {
152 c.0
153 }
154 }
155
156 open_enum::open_enum! {
157 /// ProgrammingInterface (aka, program interface byte) identifies the PCI device's
158 /// register-level programming interface.
159 ///
160 /// Values pulled from <https://wiki.osdev.org/PCI#Class_Codes>.
161 #[derive(Inspect)]
162 #[inspect(transparent(hex))]
163 pub enum ProgrammingInterface: u8{
164 // TODO: As more values are used, add them here.
165
166 NONE = 0x00,
167
168 // Non-Volatile Memory Controller (Class code:0x01, Subclass: 0x08)
169 // Other values: 0x01
170 MASS_STORAGE_CONTROLLER_NON_VOLATILE_MEMORY_NVME = 0x02,
171
172 // Ethernet Controller (Class code: 0x02, Subclass: 0x00)
173 NETWORK_CONTROLLER_ETHERNET_GDMA = 0x00,
174 }
175 }
176
177 impl From<u8> for ProgrammingInterface {
178 fn from(c: u8) -> Self {
179 Self(c)
180 }
181 }
182
183 impl From<ProgrammingInterface> for u8 {
184 fn from(c: ProgrammingInterface) -> Self {
185 c.0
186 }
187 }
188}
189
190/// Configuration Space
191///
192/// Sources: PCI 2.3 Spec - Chapter 6
193#[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
194pub mod cfg_space {
195 use bitfield_struct::bitfield;
196 use inspect::Inspect;
197 use zerocopy::FromBytes;
198 use zerocopy::Immutable;
199 use zerocopy::IntoBytes;
200 use zerocopy::KnownLayout;
201
202 open_enum::open_enum! {
203 /// Common configuration space header registers shared between Type 0 and Type 1 headers.
204 ///
205 /// These registers appear at the same offsets in both header types and have the same
206 /// meaning and format.
207 ///
208 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
209 /// |--------|----------------|-------------|-------------|----------------------|
210 /// | 0x0 | Device ID | | Vendor ID | |
211 /// | 0x4 | Status | | Command | |
212 /// | 0x8 | Class code | | | Revision ID |
213 /// | 0x34 | Reserved | | | Capabilities Pointer |
214 pub enum CommonHeader: u16 {
215 DEVICE_VENDOR = 0x00,
216 STATUS_COMMAND = 0x04,
217 CLASS_REVISION = 0x08,
218 RESERVED_CAP_PTR = 0x34,
219 }
220 }
221
222 /// Size of the common header portion shared by all PCI header types.
223 pub const COMMON_HEADER_SIZE: u16 = 0x10;
224
225 open_enum::open_enum! {
226 /// Offsets into the type 00h configuration space header.
227 ///
228 /// Table pulled from <https://wiki.osdev.org/PCI>
229 ///
230 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
231 /// |--------|----------------------------|-------------|---------------------|--------------------- |
232 /// | 0x0 | Device ID | | Vendor ID | |
233 /// | 0x4 | Status | | Command | |
234 /// | 0x8 | Class code | | | Revision ID |
235 /// | 0xC | BIST | Header type | Latency Timer | Cache Line Size |
236 /// | 0x10 | Base address #0 (BAR0) | | | |
237 /// | 0x14 | Base address #1 (BAR1) | | | |
238 /// | 0x18 | Base address #2 (BAR2) | | | |
239 /// | 0x1C | Base address #3 (BAR3) | | | |
240 /// | 0x20 | Base address #4 (BAR4) | | | |
241 /// | 0x24 | Base address #5 (BAR5) | | | |
242 /// | 0x28 | Cardbus CIS Pointer | | | |
243 /// | 0x2C | Subsystem ID | | Subsystem Vendor ID | |
244 /// | 0x30 | Expansion ROM base address | | | |
245 /// | 0x34 | Reserved | | | Capabilities Pointer |
246 /// | 0x38 | Reserved | | | |
247 /// | 0x3C | Max latency | Min Grant | Interrupt PIN | Interrupt Line |
248 pub enum HeaderType00: u16 {
249 DEVICE_VENDOR = 0x00,
250 STATUS_COMMAND = 0x04,
251 CLASS_REVISION = 0x08,
252 BIST_HEADER = 0x0C,
253 BAR0 = 0x10,
254 BAR1 = 0x14,
255 BAR2 = 0x18,
256 BAR3 = 0x1C,
257 BAR4 = 0x20,
258 BAR5 = 0x24,
259 CARDBUS_CIS_PTR = 0x28,
260 SUBSYSTEM_ID = 0x2C,
261 EXPANSION_ROM_BASE = 0x30,
262 RESERVED_CAP_PTR = 0x34,
263 RESERVED = 0x38,
264 LATENCY_INTERRUPT = 0x3C,
265 }
266 }
267
268 pub const HEADER_TYPE_00_SIZE: u16 = 0x40;
269
270 /// The BIST / Header Type / Latency Timer / Cache Line Size DWORD
271 /// at config space offset 0x0C.
272 ///
273 /// | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
274 /// |------------|-------------|-----------------|------------------|
275 /// | BIST | Header Type | Latency Timer | Cache Line Size |
276 #[bitfield(u32)]
277 pub struct BistHeader {
278 pub cache_line_size: u8,
279 pub latency_timer: u8,
280 /// Header layout type (0 = standard, 1 = PCI-to-PCI bridge).
281 #[bits(7)]
282 pub header_type: u8,
283 /// When set, the device is part of a multi-function package.
284 pub multi_function: bool,
285 pub bist: u8,
286 }
287
288 open_enum::open_enum! {
289 /// Offsets into the type 01h configuration space header.
290 ///
291 /// Table pulled from <https://wiki.osdev.org/PCI>
292 ///
293 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
294 /// |--------|----------------------------------|------------------------|--------------------------|--------------------- |
295 /// | 0x0 | Device ID | | Vendor ID | |
296 /// | 0x4 | Status | | Command | |
297 /// | 0x8 | Class code | | | Revision ID |
298 /// | 0xC | BIST | Header Type | Latency Timer | Cache Line Size |
299 /// | 0x10 | Base address #0 (BAR0) | | | |
300 /// | 0x14 | Base address #1 (BAR1) | | | |
301 /// | 0x18 | Secondary Latency Timer | Subordinate Bus Number | Secondary Bus Number | Primary Bus Number |
302 /// | 0x1C | Secondary Status | | I/O Limit | I/O Base |
303 /// | 0x20 | Memory Limit | | Memory Base | |
304 /// | 0x24 | Prefetchable Memory Limit | | Prefetchable Memory Base | |
305 /// | 0x28 | Prefetchable Base Upper 32 Bits | | | |
306 /// | 0x2C | Prefetchable Limit Upper 32 Bits | | | |
307 /// | 0x30 | I/O Limit Upper 16 Bits | | I/O Base Upper 16 Bits | |
308 /// | 0x34 | Reserved | | | Capabilities Pointer |
309 /// | 0x38 | Expansion ROM Base Address | | | |
310 /// | 0x3C | Bridge Control | | Interrupt PIN | Interrupt Line |
311 pub enum HeaderType01: u16 {
312 DEVICE_VENDOR = 0x00,
313 STATUS_COMMAND = 0x04,
314 CLASS_REVISION = 0x08,
315 BIST_HEADER = 0x0C,
316 BAR0 = 0x10,
317 BAR1 = 0x14,
318 LATENCY_BUS_NUMBERS = 0x18,
319 SEC_STATUS_IO_RANGE = 0x1C,
320 MEMORY_RANGE = 0x20,
321 PREFETCH_RANGE = 0x24,
322 PREFETCH_BASE_UPPER = 0x28,
323 PREFETCH_LIMIT_UPPER = 0x2C,
324 IO_RANGE_UPPER = 0x30,
325 RESERVED_CAP_PTR = 0x34,
326 EXPANSION_ROM_BASE = 0x38,
327 BRDIGE_CTRL_INTERRUPT = 0x3C,
328 }
329 }
330
331 pub const HEADER_TYPE_01_SIZE: u16 = 0x40;
332
333 /// The low 4 bits of the memory base/limit registers are reserved.
334 pub const MEMORY_BASE_LIMIT_ADDRESS_MASK: u16 = 0xFFF0;
335
336 /// The low bit of the prefetchable memory base/limit registers indicates
337 /// whether the range is 64-bit or 32-bit.
338 pub const PREFETCH_MEMORY_BASE_LIMIT_64BIT: u16 = 0x1;
339
340 /// BAR in-band encoding bits.
341 ///
342 /// The low bits of the BAR are not actually part of the address.
343 /// Instead, they are used to in-band encode various bits of
344 /// metadata about the BAR, and are masked off when determining the
345 /// actual address.
346 #[bitfield(u32)]
347 pub struct BarEncodingBits {
348 pub use_pio: bool,
349
350 _reserved: bool,
351
352 /// False indicates 32 bit.
353 /// Only used in MMIO
354 pub type_64_bit: bool,
355 pub prefetchable: bool,
356
357 #[bits(28)]
358 _reserved2: u32,
359 }
360
361 /// Command Register
362 #[derive(Inspect)]
363 #[bitfield(u16)]
364 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
365 pub struct Command {
366 pub pio_enabled: bool,
367 pub mmio_enabled: bool,
368 pub bus_master: bool,
369 pub special_cycles: bool,
370 pub enable_memory_write_invalidate: bool,
371 pub vga_palette_snoop: bool,
372 pub parity_error_response: bool,
373 /// must be 0
374 #[bits(1)]
375 _reserved: u16,
376 pub enable_serr: bool,
377 pub enable_fast_b2b: bool,
378 pub intx_disable: bool,
379 #[bits(5)]
380 _reserved2: u16,
381 }
382
383 /// Status Register
384 #[bitfield(u16)]
385 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
386 pub struct Status {
387 #[bits(3)]
388 _reserved: u16,
389 pub interrupt_status: bool,
390 pub capabilities_list: bool,
391 pub capable_mhz_66: bool,
392 _reserved2: bool,
393 pub capable_fast_b2b: bool,
394 pub err_master_parity: bool,
395
396 #[bits(2)]
397 pub devsel: DevSel,
398
399 pub abort_target_signaled: bool,
400 pub abort_target_received: bool,
401 pub abort_master_received: bool,
402 pub err_signaled: bool,
403 pub err_detected_parity: bool,
404 }
405
406 #[derive(Debug)]
407 #[repr(u16)]
408 pub enum DevSel {
409 Fast = 0b00,
410 Medium = 0b01,
411 Slow = 0b10,
412 }
413
414 impl DevSel {
415 const fn from_bits(bits: u16) -> Self {
416 match bits {
417 0b00 => DevSel::Fast,
418 0b01 => DevSel::Medium,
419 0b10 => DevSel::Slow,
420 _ => unreachable!(),
421 }
422 }
423
424 const fn into_bits(self) -> u16 {
425 self as u16
426 }
427 }
428}
429
430/// Capabilities
431pub mod caps {
432 open_enum::open_enum! {
433 /// Capability IDs
434 ///
435 /// Sources: PCI 2.3 Spec - Appendix H
436 ///
437 /// NOTE: this is a non-exhaustive list, so don't be afraid to add new
438 /// variants on an as-needed basis!
439 pub enum CapabilityId: u8 {
440 #![expect(missing_docs)] // self explanatory variants
441 POWER_MANAGEMENT = 0x01,
442 MSI = 0x05,
443 VENDOR_SPECIFIC = 0x09,
444 PCI_EXPRESS = 0x10,
445 MSIX = 0x11,
446 }
447 }
448
449 open_enum::open_enum! {
450
451 /// PCIe Extended Capability IDs (offsets 0x100+ in config space).
452 ///
453 /// Sources: PCI Express Base Specification
454 ///
455 /// NOTE: this is a non-exhaustive list, so don't be afraid to add new
456 /// variants on an as-needed basis!
457 pub enum ExtendedCapabilityId: u16 {
458 #![expect(missing_docs)] // self explanatory variants
459 ACS = 0x0D,
460 ARI = 0x0E,
461 SRIOV = 0x10,
462 REBAR = 0x15,
463 DVSEC = 0x23,
464 SIOV = 0x38,
465 }
466 }
467
468 /// Starting offset of the PCIe extended capability region in config space.
469 pub const EXT_CAP_START: u16 = 0x100;
470 /// Ending offset (exclusive) of the PCIe extended capability region in config space.
471 pub const EXT_CAP_END: u16 = 0x1000;
472 /// Ending offset (exclusive) of the common config header region.
473 pub const COMMON_HEADER_END: u16 = 0x40;
474
475 /// MSI
476 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
477 pub mod msi {
478 open_enum::open_enum! {
479 /// Offsets into the MSI Capability Header
480 ///
481 /// Based on PCI Local Bus Specification Rev 3.0, Section 6.8.1
482 ///
483 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
484 /// |-----------|---------------|---------------|---------------|-----------------------|
485 /// | Cap + 0x0 | Message Control | Next Pointer | Capability ID (0x05) |
486 /// | Cap + 0x4 | Message Address (32-bit or lower 32-bit of 64-bit) |
487 /// | Cap + 0x8 | Message Address Upper 32-bit (64-bit capable only) |
488 /// | Cap + 0xC | Message Data | | | |
489 /// | Cap + 0x10| Mask Bits (Per-vector masking capable only) |
490 /// | Cap + 0x14| Pending Bits (Per-vector masking capable only) |
491 pub enum MsiCapabilityHeader: u16 {
492 CONTROL_CAPS = 0x00,
493 MSG_ADDR_LO = 0x04,
494 MSG_ADDR_HI = 0x08,
495 MSG_DATA_32 = 0x08, // For 32-bit address capable
496 MSG_DATA_64 = 0x0C, // For 64-bit address capable
497 MASK_BITS = 0x10, // 64-bit + per-vector masking
498 PENDING_BITS = 0x14, // 64-bit + per-vector masking
499 }
500 }
501 }
502
503 /// MSI-X
504 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
505 pub mod msix {
506 open_enum::open_enum! {
507 /// Offsets into the MSI-X Capability Header
508 ///
509 /// Table pulled from <https://wiki.osdev.org/PCI>
510 ///
511 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-3 | Bits 2-0 |
512 /// |-----------|--------------------|------------|--------------|----------------------|----------|
513 /// | Cap + 0x0 | Message Control | | Next Pointer | Capability ID (0x11) | |
514 /// | Cap + 0x4 | Table Offset | | | | BIR |
515 /// | Cap + 0x8 | Pending Bit Offset | | | | BIR |
516 pub enum MsixCapabilityHeader: u16 {
517 CONTROL_CAPS = 0x00,
518 OFFSET_TABLE = 0x04,
519 OFFSET_PBA = 0x08,
520 }
521 }
522
523 open_enum::open_enum! {
524 /// Offsets into a single MSI-X Table Entry
525 pub enum MsixTableEntryIdx: u64 {
526 MSG_ADDR_LO = 0x00,
527 MSG_ADDR_HI = 0x04,
528 MSG_DATA = 0x08,
529 VECTOR_CTL = 0x0C,
530 }
531 }
532 }
533
534 /// PCI Express
535 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
536 pub mod pci_express {
537 use bitfield_struct::bitfield;
538 use inspect::Inspect;
539 use zerocopy::FromBytes;
540 use zerocopy::Immutable;
541 use zerocopy::IntoBytes;
542 use zerocopy::KnownLayout;
543
544 open_enum::open_enum! {
545 /// PCIe Link Speed encoding values for use in Link Capabilities and other registers.
546 ///
547 /// Values are defined in PCIe Base Specification for the Max Link Speed field
548 /// in Link Capabilities Register and similar fields.
549 #[derive(Inspect)]
550 #[inspect(debug)]
551 pub enum LinkSpeed: u32 {
552 #![allow(non_upper_case_globals)]
553 /// 2.5 GT/s link speed
554 Speed2_5GtS = 0b0001,
555 /// 5.0 GT/s link speed
556 Speed5_0GtS = 0b0010,
557 /// 8.0 GT/s link speed
558 Speed8_0GtS = 0b0011,
559 /// 16.0 GT/s link speed
560 Speed16_0GtS = 0b0100,
561 /// 32.0 GT/s link speed
562 Speed32_0GtS = 0b0101,
563 /// 64.0 GT/s link speed
564 Speed64_0GtS = 0b0110,
565 }
566 }
567
568 impl LinkSpeed {
569 pub const fn from_bits(bits: u32) -> Self {
570 Self(bits)
571 }
572
573 pub const fn into_bits(self) -> u32 {
574 self.0
575 }
576 }
577
578 open_enum::open_enum! {
579 /// PCIe Supported Link Speeds Vector encoding values for use in Link Capabilities 2 register.
580 ///
581 /// Values are defined in PCIe Base Specification for the Supported Link Speeds Vector field
582 /// in Link Capabilities 2 Register. Each bit represents support for a specific generation.
583 #[derive(Inspect)]
584 #[inspect(debug)]
585 pub enum SupportedLinkSpeedsVector: u32 {
586 #![allow(non_upper_case_globals)]
587 /// Support up to Gen 1 (2.5 GT/s)
588 UpToGen1 = 0b0000001,
589 /// Support up to Gen 2 (5.0 GT/s)
590 UpToGen2 = 0b0000011,
591 /// Support up to Gen 3 (8.0 GT/s)
592 UpToGen3 = 0b0000111,
593 /// Support up to Gen 4 (16.0 GT/s)
594 UpToGen4 = 0b0001111,
595 /// Support up to Gen 5 (32.0 GT/s)
596 UpToGen5 = 0b0011111,
597 /// Support up to Gen 6 (64.0 GT/s)
598 UpToGen6 = 0b0111111,
599 }
600 }
601
602 impl SupportedLinkSpeedsVector {
603 pub const fn from_bits(bits: u32) -> Self {
604 Self(bits)
605 }
606
607 pub const fn into_bits(self) -> u32 {
608 self.0
609 }
610 }
611
612 /// PCIe max TLP prefix values for use in Device Capabilities 2.
613 ///
614 /// Values are defined in PCIe Base Specification for the Max End-End TLP Prefixes
615 /// field in Device Capabilities 2 Register and similar fields.
616 #[derive(Copy, Clone, Debug)]
617 #[repr(u32)]
618 pub enum MaxEndEndTlpPrefixes {
619 /// 1 End-End TLP Prefix / OHC-E1
620 One = 0b01,
621 /// 2 End-End TLP Prefixes / OHC-E2
622 Two = 0b10,
623 /// 3 End-End TLP Prefixes / OHC-E4
624 Three = 0b11,
625 /// 4 End-End TLP Prefixes / OHC-E4
626 Four = 0b00,
627 }
628
629 impl MaxEndEndTlpPrefixes {
630 pub(crate) const fn from_bits(bits: u32) -> Self {
631 match bits {
632 0b01 => MaxEndEndTlpPrefixes::One,
633 0b10 => MaxEndEndTlpPrefixes::Two,
634 0b11 => MaxEndEndTlpPrefixes::Three,
635 0b00 => MaxEndEndTlpPrefixes::Four,
636 _ => unreachable!(),
637 }
638 }
639
640 pub const fn into_bits(self) -> u32 {
641 self as u32
642 }
643 }
644
645 open_enum::open_enum! {
646 /// PCIe Link Width encoding values for use in Link Capabilities and other registers.
647 ///
648 /// Values are defined in PCIe Base Specification for the Max Link Width field
649 /// in Link Capabilities Register and similar fields.
650 #[derive(Inspect)]
651 #[inspect(debug)]
652 pub enum LinkWidth: u32 {
653 /// x1 link width
654 X1 = 0b000001,
655 /// x2 link width
656 X2 = 0b000010,
657 /// x4 link width
658 X4 = 0b000100,
659 /// x8 link width
660 X8 = 0b001000,
661 /// x16 link width
662 X16 = 0b010000,
663 }
664 }
665
666 impl LinkWidth {
667 pub const fn from_bits(bits: u32) -> Self {
668 Self(bits)
669 }
670
671 pub const fn into_bits(self) -> u32 {
672 self.0
673 }
674 }
675
676 open_enum::open_enum! {
677 /// Offsets into the PCI Express Capability Header
678 ///
679 /// Table pulled from PCI Express Base Specification Rev. 3.0
680 ///
681 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
682 /// |-----------|------------------|----------------- |------------------|----------------------|
683 /// | Cap + 0x0 | PCI Express Capabilities Register | Next Pointer | Capability ID (0x10) |
684 /// | Cap + 0x4 | Device Capabilities Register |
685 /// | Cap + 0x8 | Device Status | Device Control |
686 /// | Cap + 0xC | Link Capabilities Register |
687 /// | Cap + 0x10| Link Status | Link Control |
688 /// | Cap + 0x14| Slot Capabilities Register |
689 /// | Cap + 0x18| Slot Status | Slot Control |
690 /// | Cap + 0x1C| Root Capabilities| Root Control |
691 /// | Cap + 0x20| Root Status Register |
692 /// | Cap + 0x24| Device Capabilities 2 Register |
693 /// | Cap + 0x28| Device Status 2 | Device Control 2 |
694 /// | Cap + 0x2C| Link Capabilities 2 Register |
695 /// | Cap + 0x30| Link Status 2 | Link Control 2 |
696 /// | Cap + 0x34| Slot Capabilities 2 Register |
697 /// | Cap + 0x38| Slot Status 2 | Slot Control 2 |
698 pub enum PciExpressCapabilityHeader: u16 {
699 PCIE_CAPS = 0x00,
700 DEVICE_CAPS = 0x04,
701 DEVICE_CTL_STS = 0x08,
702 LINK_CAPS = 0x0C,
703 LINK_CTL_STS = 0x10,
704 SLOT_CAPS = 0x14,
705 SLOT_CTL_STS = 0x18,
706 ROOT_CTL_CAPS = 0x1C,
707 ROOT_STS = 0x20,
708 DEVICE_CAPS_2 = 0x24,
709 DEVICE_CTL_STS_2 = 0x28,
710 LINK_CAPS_2 = 0x2C,
711 LINK_CTL_STS_2 = 0x30,
712 SLOT_CAPS_2 = 0x34,
713 SLOT_CTL_STS_2 = 0x38,
714 }
715 }
716
717 /// PCI Express Capabilities Register
718 #[bitfield(u16)]
719 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
720 pub struct PciExpressCapabilities {
721 #[bits(4)]
722 pub capability_version: u16,
723 #[bits(4)]
724 pub device_port_type: DevicePortType,
725 pub slot_implemented: bool,
726 #[bits(5)]
727 pub interrupt_message_number: u16,
728 pub _undefined: bool,
729 pub flit_mode_supported: bool,
730 }
731
732 open_enum::open_enum! {
733 #[derive(Inspect)]
734 #[inspect(debug)]
735 pub enum DevicePortType: u16 {
736 #![allow(non_upper_case_globals)]
737 Endpoint = 0b0000,
738 RootPort = 0b0100,
739 UpstreamSwitchPort = 0b0101,
740 DownstreamSwitchPort = 0b0110,
741 }
742 }
743
744 impl DevicePortType {
745 const fn from_bits(bits: u16) -> Self {
746 Self(bits)
747 }
748
749 const fn into_bits(self) -> u16 {
750 self.0
751 }
752 }
753
754 /// Device Capabilities Register (From the 6.4 spec)
755 #[bitfield(u32)]
756 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
757 pub struct DeviceCapabilities {
758 #[bits(3)]
759 pub max_payload_size: u32,
760 #[bits(2)]
761 pub phantom_functions: u32,
762 pub ext_tag_field: bool,
763 #[bits(3)]
764 pub endpoint_l0s_latency: u32,
765 #[bits(3)]
766 pub endpoint_l1_latency: u32,
767 #[bits(3)]
768 _reserved1: u32,
769 pub role_based_error: bool,
770 pub err_cor_subclass_capable: bool,
771 pub rx_mps_fixed: bool,
772 #[bits(8)]
773 pub captured_slot_power_limit: u32,
774 #[bits(2)]
775 pub captured_slot_power_scale: u32,
776 pub function_level_reset: bool,
777 pub mixed_mps_supported: bool,
778 pub tee_io_supported: bool,
779 _reserved3: bool,
780 }
781
782 /// Device Control Register
783 #[bitfield(u16)]
784 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
785 pub struct DeviceControl {
786 pub correctable_error_reporting_enable: bool,
787 pub non_fatal_error_reporting_enable: bool,
788 pub fatal_error_reporting_enable: bool,
789 pub unsupported_request_reporting_enable: bool,
790 pub enable_relaxed_ordering: bool,
791 #[bits(3)]
792 pub max_payload_size: u16,
793 pub extended_tag_enable: bool,
794 pub phantom_functions_enable: bool,
795 pub aux_power_pm_enable: bool,
796 pub enable_no_snoop: bool,
797 #[bits(3)]
798 pub max_read_request_size: u16,
799 pub initiate_function_level_reset: bool,
800 }
801
802 /// Device Status Register
803 #[bitfield(u16)]
804 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
805 pub struct DeviceStatus {
806 pub correctable_error_detected: bool,
807 pub non_fatal_error_detected: bool,
808 pub fatal_error_detected: bool,
809 pub unsupported_request_detected: bool,
810 pub aux_power_detected: bool,
811 pub transactions_pending: bool,
812 #[bits(10)]
813 _reserved: u16,
814 }
815
816 /// Link Capabilities Register
817 #[bitfield(u32)]
818 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
819 pub struct LinkCapabilities {
820 #[bits(4)]
821 pub max_link_speed: LinkSpeed,
822 #[bits(6)]
823 pub max_link_width: LinkWidth,
824 #[bits(2)]
825 pub aspm_support: u32,
826 #[bits(3)]
827 pub l0s_exit_latency: u32,
828 #[bits(3)]
829 pub l1_exit_latency: u32,
830 pub clock_power_management: bool,
831 pub surprise_down_error_reporting: bool,
832 pub data_link_layer_link_active_reporting: bool,
833 pub link_bandwidth_notification_capability: bool,
834 pub aspm_optionality_compliance: bool,
835 #[bits(1)]
836 _reserved: u32,
837 #[bits(8)]
838 pub port_number: u32,
839 }
840
841 /// Link Control Register
842 #[bitfield(u16)]
843 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
844 pub struct LinkControl {
845 #[bits(2)]
846 pub aspm_control: u16,
847 pub ptm_propagation_delay_adaptation_interpretation_b: bool,
848 #[bits(1)]
849 pub read_completion_boundary: u16,
850 pub link_disable: bool,
851 pub retrain_link: bool,
852 pub common_clock_configuration: bool,
853 pub extended_synch: bool,
854 pub enable_clock_power_management: bool,
855 pub hardware_autonomous_width_disable: bool,
856 pub link_bandwidth_management_interrupt_enable: bool,
857 pub link_autonomous_bandwidth_interrupt_enable: bool,
858 #[bits(1)]
859 pub sris_clocking: u16,
860 pub flit_mode_disable: bool,
861 #[bits(2)]
862 pub drs_signaling_control: u16,
863 }
864
865 /// Link Status Register
866 #[bitfield(u16)]
867 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
868 pub struct LinkStatus {
869 #[bits(4)]
870 pub current_link_speed: LinkSpeed,
871 #[bits(6)]
872 pub negotiated_link_width: LinkWidth,
873 #[bits(1)]
874 _reserved: u16,
875 pub link_training: bool,
876 pub slot_clock_configuration: bool,
877 pub data_link_layer_link_active: bool,
878 pub link_bandwidth_management_status: bool,
879 pub link_autonomous_bandwidth_status: bool,
880 }
881
882 /// Slot Capabilities Register
883 #[bitfield(u32)]
884 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
885 pub struct SlotCapabilities {
886 pub attention_button_present: bool,
887 pub power_controller_present: bool,
888 pub mrl_sensor_present: bool,
889 pub attention_indicator_present: bool,
890 pub power_indicator_present: bool,
891 pub hot_plug_surprise: bool,
892 pub hot_plug_capable: bool,
893 #[bits(8)]
894 pub slot_power_limit_value: u32,
895 #[bits(2)]
896 pub slot_power_limit_scale: u32,
897 pub electromechanical_interlock_present: bool,
898 pub no_command_completed_support: bool,
899 #[bits(13)]
900 pub physical_slot_number: u32,
901 }
902
903 /// Slot Control Register
904 #[bitfield(u16)]
905 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
906 pub struct SlotControl {
907 pub attention_button_pressed_enable: bool,
908 pub power_fault_detected_enable: bool,
909 pub mrl_sensor_changed_enable: bool,
910 pub presence_detect_changed_enable: bool,
911 pub command_completed_interrupt_enable: bool,
912 pub hot_plug_interrupt_enable: bool,
913 #[bits(2)]
914 pub attention_indicator_control: u16,
915 #[bits(2)]
916 pub power_indicator_control: u16,
917 pub power_controller_control: bool,
918 pub electromechanical_interlock_control: bool,
919 pub data_link_layer_state_changed_enable: bool,
920 pub auto_slot_power_limit_enable: bool,
921 pub in_band_pd_disable: bool,
922 #[bits(1)]
923 _reserved: u16,
924 }
925
926 /// Slot Status Register
927 #[bitfield(u16)]
928 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
929 pub struct SlotStatus {
930 pub attention_button_pressed: bool,
931 pub power_fault_detected: bool,
932 pub mrl_sensor_changed: bool,
933 pub presence_detect_changed: bool,
934 pub command_completed: bool,
935 #[bits(1)]
936 pub mrl_sensor_state: u16,
937 #[bits(1)]
938 pub presence_detect_state: u16,
939 #[bits(1)]
940 pub electromechanical_interlock_status: u16,
941 pub data_link_layer_state_changed: bool,
942 #[bits(7)]
943 _reserved: u16,
944 }
945
946 /// Root Control Register
947 #[bitfield(u16)]
948 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
949 pub struct RootControl {
950 pub system_error_on_correctable_error_enable: bool,
951 pub system_error_on_non_fatal_error_enable: bool,
952 pub system_error_on_fatal_error_enable: bool,
953 pub pme_interrupt_enable: bool,
954 pub crs_software_visibility_enable: bool,
955 pub no_nfm_subtree_below_this_root_port: bool,
956 #[bits(10)]
957 _reserved: u16,
958 }
959
960 /// Root Capabilities Register
961 #[bitfield(u16)]
962 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
963 pub struct RootCapabilities {
964 pub crs_software_visibility: bool,
965 #[bits(15)]
966 _reserved: u16,
967 }
968
969 /// Root Status Register
970 #[bitfield(u32)]
971 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
972 pub struct RootStatus {
973 #[bits(16)]
974 pub pme_requester_id: u32,
975 pub pme_status: bool,
976 pub pme_pending: bool,
977 #[bits(14)]
978 _reserved: u32,
979 }
980
981 /// Device Capabilities 2 Register
982 #[bitfield(u32)]
983 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
984 pub struct DeviceCapabilities2 {
985 #[bits(4)]
986 pub completion_timeout_ranges_supported: u32,
987 pub completion_timeout_disable_supported: bool,
988 pub ari_forwarding_supported: bool,
989 pub atomic_op_routing_supported: bool,
990 pub atomic_op_32_bit_completer_supported: bool,
991 pub atomic_op_64_bit_completer_supported: bool,
992 pub cas_128_bit_completer_supported: bool,
993 pub no_ro_enabled_pr_pr_passing: bool,
994 pub ltr_mechanism_supported: bool,
995 #[bits(2)]
996 pub tph_completer_supported: u32,
997 #[bits(2)]
998 _reserved: u32,
999 pub ten_bit_tag_completer_supported: bool,
1000 pub ten_bit_tag_requester_supported: bool,
1001 #[bits(2)]
1002 pub obff_supported: u32,
1003 pub extended_fmt_field_supported: bool,
1004 pub end_end_tlp_prefix_supported: bool,
1005 #[bits(2)]
1006 pub max_end_end_tlp_prefixes: MaxEndEndTlpPrefixes,
1007 #[bits(2)]
1008 pub emergency_power_reduction_supported: u32,
1009 pub emergency_power_reduction_init_required: bool,
1010 #[bits(1)]
1011 _reserved: u32,
1012 pub dmwr_completer_supported: bool,
1013 #[bits(2)]
1014 pub dmwr_lengths_supported: u32,
1015 pub frs_supported: bool,
1016 }
1017
1018 /// Device Control 2 Register
1019 #[bitfield(u16)]
1020 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1021 pub struct DeviceControl2 {
1022 #[bits(4)]
1023 pub completion_timeout_value: u16,
1024 pub completion_timeout_disable: bool,
1025 pub ari_forwarding_enable: bool,
1026 pub atomic_op_requester_enable: bool,
1027 pub atomic_op_egress_blocking: bool,
1028 pub ido_request_enable: bool,
1029 pub ido_completion_enable: bool,
1030 pub ltr_mechanism_enable: bool,
1031 pub emergency_power_reduction_request: bool,
1032 pub ten_bit_tag_requester_enable: bool,
1033 #[bits(2)]
1034 pub obff_enable: u16,
1035 pub end_end_tlp_prefix_blocking: bool,
1036 }
1037
1038 /// Device Status 2 Register
1039 #[bitfield(u16)]
1040 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1041 pub struct DeviceStatus2 {
1042 #[bits(16)]
1043 _reserved: u16,
1044 }
1045
1046 /// Link Capabilities 2 Register
1047 #[bitfield(u32)]
1048 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1049 pub struct LinkCapabilities2 {
1050 #[bits(1)]
1051 _reserved: u32,
1052 #[bits(7)]
1053 pub supported_link_speeds_vector: SupportedLinkSpeedsVector,
1054 pub crosslink_supported: bool,
1055 #[bits(7)]
1056 pub lower_skp_os_generation_supported_speeds_vector: u32,
1057 #[bits(7)]
1058 pub lower_skp_os_reception_supported_speeds_vector: u32,
1059 pub retimer_presence_detect_supported: bool,
1060 pub two_retimers_presence_detect_supported: bool,
1061 #[bits(6)]
1062 _reserved: u32,
1063 pub drs_supported: bool,
1064 }
1065
1066 /// Link Control 2 Register
1067 #[bitfield(u16)]
1068 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1069 pub struct LinkControl2 {
1070 #[bits(4)]
1071 pub target_link_speed: LinkSpeed,
1072 pub enter_compliance: bool,
1073 pub hardware_autonomous_speed_disable: bool,
1074 #[bits(1)]
1075 pub selectable_de_emphasis: u16,
1076 #[bits(3)]
1077 pub transmit_margin: u16,
1078 pub enter_modified_compliance: bool,
1079 pub compliance_sos: bool,
1080 #[bits(4)]
1081 pub compliance_preset_de_emphasis: u16,
1082 }
1083
1084 /// Link Status 2 Register
1085 #[bitfield(u16)]
1086 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1087 pub struct LinkStatus2 {
1088 #[bits(1)]
1089 pub current_de_emphasis_level: u16,
1090 pub equalization_8gts_complete: bool,
1091 pub equalization_8gts_phase_1_successful: bool,
1092 pub equalization_8gts_phase_2_successful: bool,
1093 pub equalization_8gts_phase_3_successful: bool,
1094 pub link_equalization_request_8gts: bool,
1095 pub retimer_presence_detected: bool,
1096 pub two_retimers_presence_detected: bool,
1097 #[bits(2)]
1098 pub crosslink_resolution: u16,
1099 pub flit_mode_status: bool,
1100 #[bits(1)]
1101 _reserved: u16,
1102 #[bits(3)]
1103 pub downstream_component_presence: u16,
1104 pub drs_message_received: bool,
1105 }
1106
1107 /// Slot Capabilities 2 Register
1108 #[bitfield(u32)]
1109 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1110 pub struct SlotCapabilities2 {
1111 pub in_band_pd_disable_supported: bool,
1112 #[bits(31)]
1113 _reserved: u32,
1114 }
1115
1116 /// Slot Control 2 Register
1117 #[bitfield(u16)]
1118 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1119 pub struct SlotControl2 {
1120 #[bits(16)]
1121 _reserved: u16,
1122 }
1123
1124 /// Slot Status 2 Register
1125 #[bitfield(u16)]
1126 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1127 pub struct SlotStatus2 {
1128 #[bits(16)]
1129 _reserved: u16,
1130 }
1131 }
1132
1133 /// Access Control Services (ACS) extended capability
1134 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1135 pub mod acs {
1136 use bitfield_struct::bitfield;
1137 use inspect::Inspect;
1138 use zerocopy::FromBytes;
1139 use zerocopy::Immutable;
1140 use zerocopy::IntoBytes;
1141 use zerocopy::KnownLayout;
1142
1143 /// Default ACS capability mask: SV, TB, RR, CR, UF, DT (no egress control vector).
1144 pub const DEFAULT_ACS_CAP_MASK: u16 = 0x005f;
1145
1146 open_enum::open_enum! {
1147 /// Offsets into the ACS Extended Capability structure.
1148 ///
1149 /// | Offset | Bits 31-16 | Bits 15-0 |
1150 /// |-----------|---------------------------|-------------------------|
1151 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1152 /// | Ext + 0x4 | ACS Control Register | ACS Capability Register |
1153 /// | Ext + 0x8 | Egress Control Vector (DWORD 0, if required) |
1154 /// | Ext + 0xC | Egress Control Vector (additional DWORDs, optional) |
1155 pub enum AcsExtendedCapabilityHeader: u16 {
1156 HEADER = 0x00,
1157 CAPS_CONTROL = 0x04,
1158 EGRESS_CONTROL_VECTOR = 0x08,
1159 }
1160 }
1161
1162 /// Access Control Services Capability register.
1163 #[bitfield(u16)]
1164 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1165 pub struct AcsCapabilities {
1166 pub source_validation: bool,
1167 pub translation_blocking: bool,
1168 pub p2p_request_redirect: bool,
1169 pub p2p_completion_redirect: bool,
1170 pub upstream_forwarding: bool,
1171 pub p2p_egress_control: bool,
1172 pub direct_translated_p2p: bool,
1173 #[bits(9)]
1174 _reserved: u16,
1175 }
1176
1177 /// Access Control Services Control register.
1178 #[bitfield(u16)]
1179 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1180 pub struct AcsControl {
1181 pub source_validation_enable: bool,
1182 pub translation_blocking_enable: bool,
1183 pub p2p_request_redirect_enable: bool,
1184 pub p2p_completion_redirect_enable: bool,
1185 pub upstream_forwarding_enable: bool,
1186 pub p2p_egress_control_enable: bool,
1187 pub direct_translated_p2p_enable: bool,
1188 #[bits(9)]
1189 _reserved: u16,
1190 }
1191 }
1192
1193 /// Designated Vendor-Specific Extended Capability (DVSEC)
1194 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1195 pub mod dvsec {
1196 use bitfield_struct::bitfield;
1197 use inspect::Inspect;
1198 use zerocopy::FromBytes;
1199 use zerocopy::Immutable;
1200 use zerocopy::IntoBytes;
1201 use zerocopy::KnownLayout;
1202
1203 open_enum::open_enum! {
1204 /// Offsets into the DVSEC Extended Capability structure.
1205 ///
1206 /// | Offset | Bits 31-16 | Bits 15-0 |
1207 /// |-----------|--------------------------|-------------------------|
1208 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1209 /// | Ext + 0x4 | DVSEC Length + Revision | DVSEC Vendor ID |
1210 /// | Ext + 0x8 | Reserved | DVSEC ID |
1211 pub enum DvsecExtendedCapabilityHeader: u16 {
1212 HEADER = 0x00,
1213 DVSEC_HEADER1 = 0x04,
1214 DVSEC_HEADER2 = 0x08,
1215 }
1216 }
1217
1218 /// DVSEC Header 1 register.
1219 ///
1220 /// Software should qualify the DVSEC Vendor ID before interpreting the
1221 /// DVSEC Revision field.
1222 ///
1223 /// | Bits 31-20 | Bits 19-16 | Bits 15-0 |
1224 /// |--------------|-----------------|------------------|
1225 /// | DVSEC Length | DVSEC Revision | DVSEC Vendor ID |
1226 #[bitfield(u32)]
1227 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1228 pub struct DvsecHeader1 {
1229 pub dvsec_vendor_id: u16,
1230 #[bits(4)]
1231 pub dvsec_revision: u8,
1232 #[bits(12)]
1233 pub dvsec_length: u16,
1234 }
1235
1236 /// DVSEC Header 2 register.
1237 ///
1238 /// Software should qualify the DVSEC Vendor ID before interpreting the
1239 /// DVSEC ID field.
1240 ///
1241 /// | Bits 15-0 |
1242 /// |-----------|
1243 /// | DVSEC ID |
1244 #[bitfield(u16)]
1245 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1246 pub struct DvsecHeader2 {
1247 pub dvsec_id: u16,
1248 }
1249 }
1250
1251 /// SR-IOV Extended Capability
1252 ///
1253 /// Source: PCI Express Base Specification, "Single Root I/O Virtualization"
1254 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1255 pub mod sriov {
1256 open_enum::open_enum! {
1257 /// Offsets into the SR-IOV Extended Capability structure.
1258 ///
1259 /// | Offset | Bits 31-16 | Bits 15-0 |
1260 /// |-----------|-------------------------|-------------------------|
1261 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1262 /// | Ext + 0x4 | SR-IOV Capabilities |
1263 /// | Ext + 0x8 | SR-IOV Status | SR-IOV Control |
1264 /// | Ext + 0xC | Total VFs | Initial VFs |
1265 /// | Ext + 0x10| Function Dep Link | Num VFs |
1266 /// | Ext + 0x14| VF Stride | First VF Offset |
1267 /// | Ext + 0x18| VF Device ID | Reserved |
1268 /// | Ext + 0x1C| Supported Page Sizes |
1269 /// | Ext + 0x20| System Page Size |
1270 /// | Ext + 0x24| VF BAR0 |
1271 /// | Ext + 0x28| VF BAR1 |
1272 /// | Ext + 0x2C| VF BAR2 |
1273 /// | Ext + 0x30| VF BAR3 |
1274 /// | Ext + 0x34| VF BAR4 |
1275 /// | Ext + 0x38| VF BAR5 |
1276 /// | Ext + 0x3C| VF Migration State Array Offset |
1277 pub enum SriovExtendedCapabilityHeader: u16 {
1278 HEADER = 0x00,
1279 CAPS = 0x04,
1280 /// SR-IOV Control (bits 15:0) and SR-IOV Status (bits 31:16).
1281 CONTROL_STATUS = 0x08,
1282 INITIAL_TOTAL_VFS = 0x0C,
1283 VF_OFFSET_STRIDE = 0x14,
1284 VF_BAR0 = 0x24,
1285 }
1286 }
1287
1288 /// ARI Capable Hierarchy bit within the 16-bit SR-IOV Control register
1289 /// (at [`SriovExtendedCapabilityHeader::CONTROL_STATUS`]).
1290 ///
1291 /// Source: PCI Express Base Specification §9.4.3.3.5. Present only in
1292 /// the lowest-numbered PF of a device; Read Only Zero in other PFs.
1293 /// When Set, it hints that ARI has been enabled in the Root Port or
1294 /// Switch Downstream Port immediately above the device, allowing VFs to
1295 /// be assigned Function Numbers greater than 7 to conserve Bus Numbers.
1296 pub const SRIOV_CONTROL_ARI_CAPABLE_HIERARCHY: u16 = 1 << 4;
1297 }
1298
1299 /// Source: PCI Express Base Specification §7.8.8, "ARI Extended Capability"
1300 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1301 pub mod ari {
1302 open_enum::open_enum! {
1303 /// Offsets into the ARI Extended Capability structure.
1304 ///
1305 /// | Offset | Bits 31-16 | Bits 15-0 |
1306 /// |-----------|-------------------------|-------------------------|
1307 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1308 /// | Ext + 0x4 | ARI Control | ARI Capability |
1309 ///
1310 /// The ARI Capability register (bits 15:0 at Ext + 0x4) holds the
1311 /// Next Function Number in bits 15:8; see
1312 /// [`ARI_CAPABILITY_NEXT_FUNCTION_SHIFT`].
1313 pub enum AriExtendedCapabilityHeader: u16 {
1314 HEADER = 0x00,
1315 CAPABILITY_CONTROL = 0x04,
1316 }
1317 }
1318
1319 /// Bit shift of the Next Function Number field within the ARI
1320 /// Capability register (bits 15:8 of the 16-bit register at
1321 /// [`AriExtendedCapabilityHeader::CAPABILITY_CONTROL`]).
1322 ///
1323 /// Source: PCI Express Base Specification §7.8.8.2. Function 0 is the
1324 /// head of a linked list of Function Numbers; a value of 0 terminates
1325 /// the list. Function Numbers may be sparse and non-sequential.
1326 pub const ARI_CAPABILITY_NEXT_FUNCTION_SHIFT: u32 = 8;
1327 }
1328}