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