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