Skip to main content

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}