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