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 ADVANCED_FEATURES = 0x13,
447 }
448 }
449
450 open_enum::open_enum! {
451
452 /// PCIe Extended Capability IDs (offsets 0x100+ in config space).
453 ///
454 /// Sources: PCI Express Base Specification
455 ///
456 /// NOTE: this is a non-exhaustive list, so don't be afraid to add new
457 /// variants on an as-needed basis!
458 pub enum ExtendedCapabilityId: u16 {
459 #![expect(missing_docs)] // self explanatory variants
460 ACS = 0x0D,
461 ARI = 0x0E,
462 SRIOV = 0x10,
463 REBAR = 0x15,
464 PASID = 0x1B,
465 DVSEC = 0x23,
466 SIOV = 0x38,
467 }
468 }
469
470 /// Starting offset of the PCIe extended capability region in config space.
471 pub const EXT_CAP_START: u16 = 0x100;
472 /// Ending offset (exclusive) of the PCIe extended capability region in config space.
473 pub const EXT_CAP_END: u16 = 0x1000;
474 /// Ending offset (exclusive) of the common config header region.
475 pub const COMMON_HEADER_END: u16 = 0x40;
476
477 /// Conventional PCI Advanced Features capability.
478 #[expect(missing_docs)]
479 pub mod advanced_features {
480 use bitfield_struct::bitfield;
481
482 open_enum::open_enum! {
483 pub enum CapabilityRegister: u16 {
484 HEADER = 0x00,
485 CONTROL_STATUS = 0x04,
486 }
487 }
488
489 #[bitfield(u32)]
490 pub struct Header {
491 #[bits(8)]
492 pub capability_id: u8,
493 #[bits(8)]
494 pub next_pointer: u8,
495 #[bits(8)]
496 pub length: u8,
497 #[bits(8)]
498 pub capabilities: u8,
499 }
500
501 #[bitfield(u8)]
502 pub struct Capabilities {
503 pub transactions_pending: bool,
504 pub function_level_reset: bool,
505 #[bits(6)]
506 _reserved: u8,
507 }
508
509 #[bitfield(u8)]
510 pub struct Control {
511 pub initiate_function_level_reset: bool,
512 #[bits(7)]
513 _reserved: u8,
514 }
515 }
516
517 /// MSI
518 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
519 pub mod msi {
520 open_enum::open_enum! {
521 /// Offsets into the MSI Capability Header
522 ///
523 /// Based on PCI Local Bus Specification Rev 3.0, Section 6.8.1
524 ///
525 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
526 /// |-----------|---------------|---------------|---------------|-----------------------|
527 /// | Cap + 0x0 | Message Control | Next Pointer | Capability ID (0x05) |
528 /// | Cap + 0x4 | Message Address (32-bit or lower 32-bit of 64-bit) |
529 /// | Cap + 0x8 | Message Address Upper 32-bit (64-bit capable only) |
530 /// | Cap + 0xC | Message Data | | | |
531 /// | Cap + 0x10| Mask Bits (Per-vector masking capable only) |
532 /// | Cap + 0x14| Pending Bits (Per-vector masking capable only) |
533 pub enum MsiCapabilityHeader: u16 {
534 CONTROL_CAPS = 0x00,
535 MSG_ADDR_LO = 0x04,
536 MSG_ADDR_HI = 0x08,
537 MSG_DATA_32 = 0x08, // For 32-bit address capable
538 MSG_DATA_64 = 0x0C, // For 64-bit address capable
539 MASK_BITS = 0x10, // 64-bit + per-vector masking
540 PENDING_BITS = 0x14, // 64-bit + per-vector masking
541 }
542 }
543 }
544
545 /// MSI-X
546 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
547 pub mod msix {
548 open_enum::open_enum! {
549 /// Offsets into the MSI-X Capability Header
550 ///
551 /// Table pulled from <https://wiki.osdev.org/PCI>
552 ///
553 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-3 | Bits 2-0 |
554 /// |-----------|--------------------|------------|--------------|----------------------|----------|
555 /// | Cap + 0x0 | Message Control | | Next Pointer | Capability ID (0x11) | |
556 /// | Cap + 0x4 | Table Offset | | | | BIR |
557 /// | Cap + 0x8 | Pending Bit Offset | | | | BIR |
558 pub enum MsixCapabilityHeader: u16 {
559 CONTROL_CAPS = 0x00,
560 OFFSET_TABLE = 0x04,
561 OFFSET_PBA = 0x08,
562 }
563 }
564
565 open_enum::open_enum! {
566 /// Offsets into a single MSI-X Table Entry
567 pub enum MsixTableEntryIdx: u64 {
568 MSG_ADDR_LO = 0x00,
569 MSG_ADDR_HI = 0x04,
570 MSG_DATA = 0x08,
571 VECTOR_CTL = 0x0C,
572 }
573 }
574 }
575
576 /// PCI Express
577 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
578 pub mod pci_express {
579 use bitfield_struct::bitfield;
580 use inspect::Inspect;
581 use zerocopy::FromBytes;
582 use zerocopy::Immutable;
583 use zerocopy::IntoBytes;
584 use zerocopy::KnownLayout;
585
586 open_enum::open_enum! {
587 /// PCIe Link Speed encoding values for use in Link Capabilities and other registers.
588 ///
589 /// Values are defined in PCIe Base Specification for the Max Link Speed field
590 /// in Link Capabilities Register and similar fields.
591 #[derive(Inspect)]
592 #[inspect(debug)]
593 pub enum LinkSpeed: u32 {
594 #![allow(non_upper_case_globals)]
595 /// 2.5 GT/s link speed
596 Speed2_5GtS = 0b0001,
597 /// 5.0 GT/s link speed
598 Speed5_0GtS = 0b0010,
599 /// 8.0 GT/s link speed
600 Speed8_0GtS = 0b0011,
601 /// 16.0 GT/s link speed
602 Speed16_0GtS = 0b0100,
603 /// 32.0 GT/s link speed
604 Speed32_0GtS = 0b0101,
605 /// 64.0 GT/s link speed
606 Speed64_0GtS = 0b0110,
607 }
608 }
609
610 impl LinkSpeed {
611 pub const fn from_bits(bits: u32) -> Self {
612 Self(bits)
613 }
614
615 pub const fn into_bits(self) -> u32 {
616 self.0
617 }
618 }
619
620 open_enum::open_enum! {
621 /// PCIe Supported Link Speeds Vector encoding values for use in Link Capabilities 2 register.
622 ///
623 /// Values are defined in PCIe Base Specification for the Supported Link Speeds Vector field
624 /// in Link Capabilities 2 Register. Each bit represents support for a specific generation.
625 #[derive(Inspect)]
626 #[inspect(debug)]
627 pub enum SupportedLinkSpeedsVector: u32 {
628 #![allow(non_upper_case_globals)]
629 /// Support up to Gen 1 (2.5 GT/s)
630 UpToGen1 = 0b0000001,
631 /// Support up to Gen 2 (5.0 GT/s)
632 UpToGen2 = 0b0000011,
633 /// Support up to Gen 3 (8.0 GT/s)
634 UpToGen3 = 0b0000111,
635 /// Support up to Gen 4 (16.0 GT/s)
636 UpToGen4 = 0b0001111,
637 /// Support up to Gen 5 (32.0 GT/s)
638 UpToGen5 = 0b0011111,
639 /// Support up to Gen 6 (64.0 GT/s)
640 UpToGen6 = 0b0111111,
641 }
642 }
643
644 impl SupportedLinkSpeedsVector {
645 pub const fn from_bits(bits: u32) -> Self {
646 Self(bits)
647 }
648
649 pub const fn into_bits(self) -> u32 {
650 self.0
651 }
652 }
653
654 /// PCIe max TLP prefix values for use in Device Capabilities 2.
655 ///
656 /// Values are defined in PCIe Base Specification for the Max End-End TLP Prefixes
657 /// field in Device Capabilities 2 Register and similar fields.
658 #[derive(Copy, Clone, Debug)]
659 #[repr(u32)]
660 pub enum MaxEndEndTlpPrefixes {
661 /// 1 End-End TLP Prefix / OHC-E1
662 One = 0b01,
663 /// 2 End-End TLP Prefixes / OHC-E2
664 Two = 0b10,
665 /// 3 End-End TLP Prefixes / OHC-E4
666 Three = 0b11,
667 /// 4 End-End TLP Prefixes / OHC-E4
668 Four = 0b00,
669 }
670
671 impl MaxEndEndTlpPrefixes {
672 pub(crate) const fn from_bits(bits: u32) -> Self {
673 match bits {
674 0b01 => MaxEndEndTlpPrefixes::One,
675 0b10 => MaxEndEndTlpPrefixes::Two,
676 0b11 => MaxEndEndTlpPrefixes::Three,
677 0b00 => MaxEndEndTlpPrefixes::Four,
678 _ => unreachable!(),
679 }
680 }
681
682 pub const fn into_bits(self) -> u32 {
683 self as u32
684 }
685 }
686
687 open_enum::open_enum! {
688 /// PCIe Link Width encoding values for use in Link Capabilities and other registers.
689 ///
690 /// Values are defined in PCIe Base Specification for the Max Link Width field
691 /// in Link Capabilities Register and similar fields.
692 #[derive(Inspect)]
693 #[inspect(debug)]
694 pub enum LinkWidth: u32 {
695 /// x1 link width
696 X1 = 0b000001,
697 /// x2 link width
698 X2 = 0b000010,
699 /// x4 link width
700 X4 = 0b000100,
701 /// x8 link width
702 X8 = 0b001000,
703 /// x16 link width
704 X16 = 0b010000,
705 }
706 }
707
708 impl LinkWidth {
709 pub const fn from_bits(bits: u32) -> Self {
710 Self(bits)
711 }
712
713 pub const fn into_bits(self) -> u32 {
714 self.0
715 }
716 }
717
718 open_enum::open_enum! {
719 /// Offsets into the PCI Express Capability Header
720 ///
721 /// Table pulled from PCI Express Base Specification Rev. 3.0
722 ///
723 /// | Offset | Bits 31-24 | Bits 23-16 | Bits 15-8 | Bits 7-0 |
724 /// |-----------|------------------|----------------- |------------------|----------------------|
725 /// | Cap + 0x0 | PCI Express Capabilities Register | Next Pointer | Capability ID (0x10) |
726 /// | Cap + 0x4 | Device Capabilities Register |
727 /// | Cap + 0x8 | Device Status | Device Control |
728 /// | Cap + 0xC | Link Capabilities Register |
729 /// | Cap + 0x10| Link Status | Link Control |
730 /// | Cap + 0x14| Slot Capabilities Register |
731 /// | Cap + 0x18| Slot Status | Slot Control |
732 /// | Cap + 0x1C| Root Capabilities| Root Control |
733 /// | Cap + 0x20| Root Status Register |
734 /// | Cap + 0x24| Device Capabilities 2 Register |
735 /// | Cap + 0x28| Device Status 2 | Device Control 2 |
736 /// | Cap + 0x2C| Link Capabilities 2 Register |
737 /// | Cap + 0x30| Link Status 2 | Link Control 2 |
738 /// | Cap + 0x34| Slot Capabilities 2 Register |
739 /// | Cap + 0x38| Slot Status 2 | Slot Control 2 |
740 pub enum PciExpressCapabilityHeader: u16 {
741 PCIE_CAPS = 0x00,
742 DEVICE_CAPS = 0x04,
743 DEVICE_CTL_STS = 0x08,
744 LINK_CAPS = 0x0C,
745 LINK_CTL_STS = 0x10,
746 SLOT_CAPS = 0x14,
747 SLOT_CTL_STS = 0x18,
748 ROOT_CTL_CAPS = 0x1C,
749 ROOT_STS = 0x20,
750 DEVICE_CAPS_2 = 0x24,
751 DEVICE_CTL_STS_2 = 0x28,
752 LINK_CAPS_2 = 0x2C,
753 LINK_CTL_STS_2 = 0x30,
754 SLOT_CAPS_2 = 0x34,
755 SLOT_CTL_STS_2 = 0x38,
756 }
757 }
758
759 /// PCI Express Capabilities Register
760 #[bitfield(u16)]
761 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
762 pub struct PciExpressCapabilities {
763 #[bits(4)]
764 pub capability_version: u16,
765 #[bits(4)]
766 pub device_port_type: DevicePortType,
767 pub slot_implemented: bool,
768 #[bits(5)]
769 pub interrupt_message_number: u16,
770 pub _undefined: bool,
771 pub flit_mode_supported: bool,
772 }
773
774 open_enum::open_enum! {
775 #[derive(Inspect)]
776 #[inspect(debug)]
777 pub enum DevicePortType: u16 {
778 #![allow(non_upper_case_globals)]
779 Endpoint = 0b0000,
780 RootPort = 0b0100,
781 UpstreamSwitchPort = 0b0101,
782 DownstreamSwitchPort = 0b0110,
783 }
784 }
785
786 impl DevicePortType {
787 const fn from_bits(bits: u16) -> Self {
788 Self(bits)
789 }
790
791 const fn into_bits(self) -> u16 {
792 self.0
793 }
794 }
795
796 /// Device Capabilities Register (From the 6.4 spec)
797 #[bitfield(u32)]
798 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
799 pub struct DeviceCapabilities {
800 #[bits(3)]
801 pub max_payload_size: u32,
802 #[bits(2)]
803 pub phantom_functions: u32,
804 pub ext_tag_field: bool,
805 #[bits(3)]
806 pub endpoint_l0s_latency: u32,
807 #[bits(3)]
808 pub endpoint_l1_latency: u32,
809 #[bits(3)]
810 _reserved1: u32,
811 pub role_based_error: bool,
812 pub err_cor_subclass_capable: bool,
813 pub rx_mps_fixed: bool,
814 #[bits(8)]
815 pub captured_slot_power_limit: u32,
816 #[bits(2)]
817 pub captured_slot_power_scale: u32,
818 pub function_level_reset: bool,
819 pub mixed_mps_supported: bool,
820 pub tee_io_supported: bool,
821 _reserved3: bool,
822 }
823
824 /// Device Control Register
825 #[bitfield(u16)]
826 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
827 pub struct DeviceControl {
828 pub correctable_error_reporting_enable: bool,
829 pub non_fatal_error_reporting_enable: bool,
830 pub fatal_error_reporting_enable: bool,
831 pub unsupported_request_reporting_enable: bool,
832 pub enable_relaxed_ordering: bool,
833 #[bits(3)]
834 pub max_payload_size: u16,
835 pub extended_tag_enable: bool,
836 pub phantom_functions_enable: bool,
837 pub aux_power_pm_enable: bool,
838 pub enable_no_snoop: bool,
839 #[bits(3)]
840 pub max_read_request_size: u16,
841 pub initiate_function_level_reset: bool,
842 }
843
844 /// Device Status Register
845 #[bitfield(u16)]
846 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
847 pub struct DeviceStatus {
848 pub correctable_error_detected: bool,
849 pub non_fatal_error_detected: bool,
850 pub fatal_error_detected: bool,
851 pub unsupported_request_detected: bool,
852 pub aux_power_detected: bool,
853 pub transactions_pending: bool,
854 #[bits(10)]
855 _reserved: u16,
856 }
857
858 /// Link Capabilities Register
859 #[bitfield(u32)]
860 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
861 pub struct LinkCapabilities {
862 #[bits(4)]
863 pub max_link_speed: LinkSpeed,
864 #[bits(6)]
865 pub max_link_width: LinkWidth,
866 #[bits(2)]
867 pub aspm_support: u32,
868 #[bits(3)]
869 pub l0s_exit_latency: u32,
870 #[bits(3)]
871 pub l1_exit_latency: u32,
872 pub clock_power_management: bool,
873 pub surprise_down_error_reporting: bool,
874 pub data_link_layer_link_active_reporting: bool,
875 pub link_bandwidth_notification_capability: bool,
876 pub aspm_optionality_compliance: bool,
877 #[bits(1)]
878 _reserved: u32,
879 #[bits(8)]
880 pub port_number: u32,
881 }
882
883 /// Link Control Register
884 #[bitfield(u16)]
885 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
886 pub struct LinkControl {
887 #[bits(2)]
888 pub aspm_control: u16,
889 pub ptm_propagation_delay_adaptation_interpretation_b: bool,
890 #[bits(1)]
891 pub read_completion_boundary: u16,
892 pub link_disable: bool,
893 pub retrain_link: bool,
894 pub common_clock_configuration: bool,
895 pub extended_synch: bool,
896 pub enable_clock_power_management: bool,
897 pub hardware_autonomous_width_disable: bool,
898 pub link_bandwidth_management_interrupt_enable: bool,
899 pub link_autonomous_bandwidth_interrupt_enable: bool,
900 #[bits(1)]
901 pub sris_clocking: u16,
902 pub flit_mode_disable: bool,
903 #[bits(2)]
904 pub drs_signaling_control: u16,
905 }
906
907 /// Link Status Register
908 #[bitfield(u16)]
909 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
910 pub struct LinkStatus {
911 #[bits(4)]
912 pub current_link_speed: LinkSpeed,
913 #[bits(6)]
914 pub negotiated_link_width: LinkWidth,
915 #[bits(1)]
916 _reserved: u16,
917 pub link_training: bool,
918 pub slot_clock_configuration: bool,
919 pub data_link_layer_link_active: bool,
920 pub link_bandwidth_management_status: bool,
921 pub link_autonomous_bandwidth_status: bool,
922 }
923
924 /// Slot Capabilities Register
925 #[bitfield(u32)]
926 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
927 pub struct SlotCapabilities {
928 pub attention_button_present: bool,
929 pub power_controller_present: bool,
930 pub mrl_sensor_present: bool,
931 pub attention_indicator_present: bool,
932 pub power_indicator_present: bool,
933 pub hot_plug_surprise: bool,
934 pub hot_plug_capable: bool,
935 #[bits(8)]
936 pub slot_power_limit_value: u32,
937 #[bits(2)]
938 pub slot_power_limit_scale: u32,
939 pub electromechanical_interlock_present: bool,
940 pub no_command_completed_support: bool,
941 #[bits(13)]
942 pub physical_slot_number: u32,
943 }
944
945 /// Slot Control Register
946 #[bitfield(u16)]
947 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
948 pub struct SlotControl {
949 pub attention_button_pressed_enable: bool,
950 pub power_fault_detected_enable: bool,
951 pub mrl_sensor_changed_enable: bool,
952 pub presence_detect_changed_enable: bool,
953 pub command_completed_interrupt_enable: bool,
954 pub hot_plug_interrupt_enable: bool,
955 #[bits(2)]
956 pub attention_indicator_control: u16,
957 #[bits(2)]
958 pub power_indicator_control: u16,
959 pub power_controller_control: bool,
960 pub electromechanical_interlock_control: bool,
961 pub data_link_layer_state_changed_enable: bool,
962 pub auto_slot_power_limit_enable: bool,
963 pub in_band_pd_disable: bool,
964 #[bits(1)]
965 _reserved: u16,
966 }
967
968 /// Slot Status Register
969 #[bitfield(u16)]
970 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
971 pub struct SlotStatus {
972 pub attention_button_pressed: bool,
973 pub power_fault_detected: bool,
974 pub mrl_sensor_changed: bool,
975 pub presence_detect_changed: bool,
976 pub command_completed: bool,
977 #[bits(1)]
978 pub mrl_sensor_state: u16,
979 #[bits(1)]
980 pub presence_detect_state: u16,
981 #[bits(1)]
982 pub electromechanical_interlock_status: u16,
983 pub data_link_layer_state_changed: bool,
984 #[bits(7)]
985 _reserved: u16,
986 }
987
988 /// Root Control Register
989 #[bitfield(u16)]
990 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
991 pub struct RootControl {
992 pub system_error_on_correctable_error_enable: bool,
993 pub system_error_on_non_fatal_error_enable: bool,
994 pub system_error_on_fatal_error_enable: bool,
995 pub pme_interrupt_enable: bool,
996 pub crs_software_visibility_enable: bool,
997 pub no_nfm_subtree_below_this_root_port: bool,
998 #[bits(10)]
999 _reserved: u16,
1000 }
1001
1002 /// Root Capabilities Register
1003 #[bitfield(u16)]
1004 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1005 pub struct RootCapabilities {
1006 pub crs_software_visibility: bool,
1007 #[bits(15)]
1008 _reserved: u16,
1009 }
1010
1011 /// Root Status Register
1012 #[bitfield(u32)]
1013 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1014 pub struct RootStatus {
1015 #[bits(16)]
1016 pub pme_requester_id: u32,
1017 pub pme_status: bool,
1018 pub pme_pending: bool,
1019 #[bits(14)]
1020 _reserved: u32,
1021 }
1022
1023 /// Device Capabilities 2 Register
1024 #[bitfield(u32)]
1025 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1026 pub struct DeviceCapabilities2 {
1027 #[bits(4)]
1028 pub completion_timeout_ranges_supported: u32,
1029 pub completion_timeout_disable_supported: bool,
1030 pub ari_forwarding_supported: bool,
1031 pub atomic_op_routing_supported: bool,
1032 pub atomic_op_32_bit_completer_supported: bool,
1033 pub atomic_op_64_bit_completer_supported: bool,
1034 pub cas_128_bit_completer_supported: bool,
1035 pub no_ro_enabled_pr_pr_passing: bool,
1036 pub ltr_mechanism_supported: bool,
1037 #[bits(2)]
1038 pub tph_completer_supported: u32,
1039 #[bits(2)]
1040 _reserved: u32,
1041 pub ten_bit_tag_completer_supported: bool,
1042 pub ten_bit_tag_requester_supported: bool,
1043 #[bits(2)]
1044 pub obff_supported: u32,
1045 pub extended_fmt_field_supported: bool,
1046 pub end_end_tlp_prefix_supported: bool,
1047 #[bits(2)]
1048 pub max_end_end_tlp_prefixes: MaxEndEndTlpPrefixes,
1049 #[bits(2)]
1050 pub emergency_power_reduction_supported: u32,
1051 pub emergency_power_reduction_init_required: bool,
1052 #[bits(1)]
1053 _reserved: u32,
1054 pub dmwr_completer_supported: bool,
1055 #[bits(2)]
1056 pub dmwr_lengths_supported: u32,
1057 pub frs_supported: bool,
1058 }
1059
1060 /// Device Control 2 Register
1061 #[bitfield(u16)]
1062 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1063 pub struct DeviceControl2 {
1064 #[bits(4)]
1065 pub completion_timeout_value: u16,
1066 pub completion_timeout_disable: bool,
1067 pub ari_forwarding_enable: bool,
1068 pub atomic_op_requester_enable: bool,
1069 pub atomic_op_egress_blocking: bool,
1070 pub ido_request_enable: bool,
1071 pub ido_completion_enable: bool,
1072 pub ltr_mechanism_enable: bool,
1073 pub emergency_power_reduction_request: bool,
1074 pub ten_bit_tag_requester_enable: bool,
1075 #[bits(2)]
1076 pub obff_enable: u16,
1077 pub end_end_tlp_prefix_blocking: bool,
1078 }
1079
1080 /// Device Status 2 Register
1081 #[bitfield(u16)]
1082 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1083 pub struct DeviceStatus2 {
1084 #[bits(16)]
1085 _reserved: u16,
1086 }
1087
1088 /// Link Capabilities 2 Register
1089 #[bitfield(u32)]
1090 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1091 pub struct LinkCapabilities2 {
1092 #[bits(1)]
1093 _reserved: u32,
1094 #[bits(7)]
1095 pub supported_link_speeds_vector: SupportedLinkSpeedsVector,
1096 pub crosslink_supported: bool,
1097 #[bits(7)]
1098 pub lower_skp_os_generation_supported_speeds_vector: u32,
1099 #[bits(7)]
1100 pub lower_skp_os_reception_supported_speeds_vector: u32,
1101 pub retimer_presence_detect_supported: bool,
1102 pub two_retimers_presence_detect_supported: bool,
1103 #[bits(6)]
1104 _reserved: u32,
1105 pub drs_supported: bool,
1106 }
1107
1108 /// Link Control 2 Register
1109 #[bitfield(u16)]
1110 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1111 pub struct LinkControl2 {
1112 #[bits(4)]
1113 pub target_link_speed: LinkSpeed,
1114 pub enter_compliance: bool,
1115 pub hardware_autonomous_speed_disable: bool,
1116 #[bits(1)]
1117 pub selectable_de_emphasis: u16,
1118 #[bits(3)]
1119 pub transmit_margin: u16,
1120 pub enter_modified_compliance: bool,
1121 pub compliance_sos: bool,
1122 #[bits(4)]
1123 pub compliance_preset_de_emphasis: u16,
1124 }
1125
1126 /// Link Status 2 Register
1127 #[bitfield(u16)]
1128 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1129 pub struct LinkStatus2 {
1130 #[bits(1)]
1131 pub current_de_emphasis_level: u16,
1132 pub equalization_8gts_complete: bool,
1133 pub equalization_8gts_phase_1_successful: bool,
1134 pub equalization_8gts_phase_2_successful: bool,
1135 pub equalization_8gts_phase_3_successful: bool,
1136 pub link_equalization_request_8gts: bool,
1137 pub retimer_presence_detected: bool,
1138 pub two_retimers_presence_detected: bool,
1139 #[bits(2)]
1140 pub crosslink_resolution: u16,
1141 pub flit_mode_status: bool,
1142 #[bits(1)]
1143 _reserved: u16,
1144 #[bits(3)]
1145 pub downstream_component_presence: u16,
1146 pub drs_message_received: bool,
1147 }
1148
1149 /// Slot Capabilities 2 Register
1150 #[bitfield(u32)]
1151 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1152 pub struct SlotCapabilities2 {
1153 pub in_band_pd_disable_supported: bool,
1154 #[bits(31)]
1155 _reserved: u32,
1156 }
1157
1158 /// Slot Control 2 Register
1159 #[bitfield(u16)]
1160 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1161 pub struct SlotControl2 {
1162 #[bits(16)]
1163 _reserved: u16,
1164 }
1165
1166 /// Slot Status 2 Register
1167 #[bitfield(u16)]
1168 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1169 pub struct SlotStatus2 {
1170 #[bits(16)]
1171 _reserved: u16,
1172 }
1173 }
1174
1175 /// Access Control Services (ACS) extended capability
1176 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1177 pub mod acs {
1178 use bitfield_struct::bitfield;
1179 use inspect::Inspect;
1180 use zerocopy::FromBytes;
1181 use zerocopy::Immutable;
1182 use zerocopy::IntoBytes;
1183 use zerocopy::KnownLayout;
1184
1185 /// Default ACS capability mask: SV, TB, RR, CR, UF, DT (no egress control vector).
1186 pub const DEFAULT_ACS_CAP_MASK: u16 = 0x005f;
1187
1188 open_enum::open_enum! {
1189 /// Offsets into the ACS Extended Capability structure.
1190 ///
1191 /// | Offset | Bits 31-16 | Bits 15-0 |
1192 /// |-----------|---------------------------|-------------------------|
1193 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1194 /// | Ext + 0x4 | ACS Control Register | ACS Capability Register |
1195 /// | Ext + 0x8 | Egress Control Vector (DWORD 0, if required) |
1196 /// | Ext + 0xC | Egress Control Vector (additional DWORDs, optional) |
1197 pub enum AcsExtendedCapabilityHeader: u16 {
1198 HEADER = 0x00,
1199 CAPS_CONTROL = 0x04,
1200 EGRESS_CONTROL_VECTOR = 0x08,
1201 }
1202 }
1203
1204 /// Access Control Services Capability register.
1205 #[bitfield(u16)]
1206 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1207 pub struct AcsCapabilities {
1208 pub source_validation: bool,
1209 pub translation_blocking: bool,
1210 pub p2p_request_redirect: bool,
1211 pub p2p_completion_redirect: bool,
1212 pub upstream_forwarding: bool,
1213 pub p2p_egress_control: bool,
1214 pub direct_translated_p2p: bool,
1215 #[bits(9)]
1216 _reserved: u16,
1217 }
1218
1219 /// Access Control Services Control register.
1220 #[bitfield(u16)]
1221 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1222 pub struct AcsControl {
1223 pub source_validation_enable: bool,
1224 pub translation_blocking_enable: bool,
1225 pub p2p_request_redirect_enable: bool,
1226 pub p2p_completion_redirect_enable: bool,
1227 pub upstream_forwarding_enable: bool,
1228 pub p2p_egress_control_enable: bool,
1229 pub direct_translated_p2p_enable: bool,
1230 #[bits(9)]
1231 _reserved: u16,
1232 }
1233 }
1234
1235 /// Designated Vendor-Specific Extended Capability (DVSEC)
1236 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1237 pub mod dvsec {
1238 use bitfield_struct::bitfield;
1239 use inspect::Inspect;
1240 use zerocopy::FromBytes;
1241 use zerocopy::Immutable;
1242 use zerocopy::IntoBytes;
1243 use zerocopy::KnownLayout;
1244
1245 open_enum::open_enum! {
1246 /// Offsets into the DVSEC Extended Capability structure.
1247 ///
1248 /// | Offset | Bits 31-16 | Bits 15-0 |
1249 /// |-----------|--------------------------|-------------------------|
1250 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1251 /// | Ext + 0x4 | DVSEC Length + Revision | DVSEC Vendor ID |
1252 /// | Ext + 0x8 | Reserved | DVSEC ID |
1253 pub enum DvsecExtendedCapabilityHeader: u16 {
1254 HEADER = 0x00,
1255 DVSEC_HEADER1 = 0x04,
1256 DVSEC_HEADER2 = 0x08,
1257 }
1258 }
1259
1260 /// DVSEC Header 1 register.
1261 ///
1262 /// Software should qualify the DVSEC Vendor ID before interpreting the
1263 /// DVSEC Revision field.
1264 ///
1265 /// | Bits 31-20 | Bits 19-16 | Bits 15-0 |
1266 /// |--------------|-----------------|------------------|
1267 /// | DVSEC Length | DVSEC Revision | DVSEC Vendor ID |
1268 #[bitfield(u32)]
1269 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1270 pub struct DvsecHeader1 {
1271 pub dvsec_vendor_id: u16,
1272 #[bits(4)]
1273 pub dvsec_revision: u8,
1274 #[bits(12)]
1275 pub dvsec_length: u16,
1276 }
1277
1278 /// DVSEC Header 2 register.
1279 ///
1280 /// Software should qualify the DVSEC Vendor ID before interpreting the
1281 /// DVSEC ID field.
1282 ///
1283 /// | Bits 15-0 |
1284 /// |-----------|
1285 /// | DVSEC ID |
1286 #[bitfield(u16)]
1287 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1288 pub struct DvsecHeader2 {
1289 pub dvsec_id: u16,
1290 }
1291 }
1292
1293 /// SR-IOV Extended Capability
1294 ///
1295 /// Source: PCI Express Base Specification, "Single Root I/O Virtualization"
1296 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1297 pub mod sriov {
1298 open_enum::open_enum! {
1299 /// Offsets into the SR-IOV Extended Capability structure.
1300 ///
1301 /// | Offset | Bits 31-16 | Bits 15-0 |
1302 /// |-----------|-------------------------|-------------------------|
1303 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1304 /// | Ext + 0x4 | SR-IOV Capabilities |
1305 /// | Ext + 0x8 | SR-IOV Status | SR-IOV Control |
1306 /// | Ext + 0xC | Total VFs | Initial VFs |
1307 /// | Ext + 0x10| Function Dep Link | Num VFs |
1308 /// | Ext + 0x14| VF Stride | First VF Offset |
1309 /// | Ext + 0x18| VF Device ID | Reserved |
1310 /// | Ext + 0x1C| Supported Page Sizes |
1311 /// | Ext + 0x20| System Page Size |
1312 /// | Ext + 0x24| VF BAR0 |
1313 /// | Ext + 0x28| VF BAR1 |
1314 /// | Ext + 0x2C| VF BAR2 |
1315 /// | Ext + 0x30| VF BAR3 |
1316 /// | Ext + 0x34| VF BAR4 |
1317 /// | Ext + 0x38| VF BAR5 |
1318 /// | Ext + 0x3C| VF Migration State Array Offset |
1319 pub enum SriovExtendedCapabilityHeader: u16 {
1320 HEADER = 0x00,
1321 CAPS = 0x04,
1322 /// SR-IOV Control (bits 15:0) and SR-IOV Status (bits 31:16).
1323 CONTROL_STATUS = 0x08,
1324 INITIAL_TOTAL_VFS = 0x0C,
1325 VF_OFFSET_STRIDE = 0x14,
1326 VF_BAR0 = 0x24,
1327 }
1328 }
1329
1330 /// ARI Capable Hierarchy bit within the 16-bit SR-IOV Control register
1331 /// (at [`SriovExtendedCapabilityHeader::CONTROL_STATUS`]).
1332 ///
1333 /// Source: PCI Express Base Specification §9.4.3.3.5. Present only in
1334 /// the lowest-numbered PF of a device; Read Only Zero in other PFs.
1335 /// When Set, it hints that ARI has been enabled in the Root Port or
1336 /// Switch Downstream Port immediately above the device, allowing VFs to
1337 /// be assigned Function Numbers greater than 7 to conserve Bus Numbers.
1338 pub const SRIOV_CONTROL_ARI_CAPABLE_HIERARCHY: u16 = 1 << 4;
1339 }
1340
1341 /// Source: PCI Express Base Specification §7.8.8, "ARI Extended Capability"
1342 #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
1343 pub mod ari {
1344 open_enum::open_enum! {
1345 /// Offsets into the ARI Extended Capability structure.
1346 ///
1347 /// | Offset | Bits 31-16 | Bits 15-0 |
1348 /// |-----------|-------------------------|-------------------------|
1349 /// | Ext + 0x0 | Next Cap Ptr + Version | Extended Capability ID |
1350 /// | Ext + 0x4 | ARI Control | ARI Capability |
1351 ///
1352 /// The ARI Capability register (bits 15:0 at Ext + 0x4) holds the
1353 /// Next Function Number in bits 15:8; see
1354 /// [`ARI_CAPABILITY_NEXT_FUNCTION_SHIFT`].
1355 pub enum AriExtendedCapabilityHeader: u16 {
1356 HEADER = 0x00,
1357 CAPABILITY_CONTROL = 0x04,
1358 }
1359 }
1360
1361 /// Bit shift of the Next Function Number field within the ARI
1362 /// Capability register (bits 15:8 of the 16-bit register at
1363 /// [`AriExtendedCapabilityHeader::CAPABILITY_CONTROL`]).
1364 ///
1365 /// Source: PCI Express Base Specification §7.8.8.2. Function 0 is the
1366 /// head of a linked list of Function Numbers; a value of 0 terminates
1367 /// the list. Function Numbers may be sparse and non-sequential.
1368 pub const ARI_CAPABILITY_NEXT_FUNCTION_SHIFT: u32 = 8;
1369 }
1370}