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_NON_VOLATILE_MEMORY = 0x08,
121
122            // Network Controller (Class code: 0x02)
123            // Other values: 0x01 - 0x08, 0x80
124            NETWORK_CONTROLLER_ETHERNET = 0x00,
125
126            // Bridge (Class code: 0x06)
127            // Other values: 0x02 - 0x0A
128            BRIDGE_HOST = 0x00,
129            BRIDGE_ISA = 0x01,
130            BRIDGE_PCI_TO_PCI = 0x04,
131            BRIDGE_OTHER = 0x80,
132
133            // Base System Peripheral (Class code: 0x08)
134            // Other values: 0x00 - 0x06
135            BASE_SYSTEM_PERIPHERAL_OTHER = 0x80,
136        }
137    }
138
139    impl From<u8> for Subclass {
140        fn from(c: u8) -> Self {
141            Self(c)
142        }
143    }
144
145    impl From<Subclass> for u8 {
146        fn from(c: Subclass) -> Self {
147            c.0
148        }
149    }
150
151    open_enum::open_enum! {
152        /// ProgrammingInterface (aka, program interface byte) identifies the PCI device's
153        /// register-level programming interface.
154        ///
155        /// Values pulled from <https://wiki.osdev.org/PCI#Class_Codes>.
156        #[derive(Inspect)]
157        #[inspect(transparent(hex))]
158        pub enum ProgrammingInterface: u8{
159            // TODO: As more values are used, add them here.
160
161            NONE = 0x00,
162
163            // Non-Volatile Memory Controller (Class code:0x01, Subclass: 0x08)
164            // Other values: 0x01
165            MASS_STORAGE_CONTROLLER_NON_VOLATILE_MEMORY_NVME = 0x02,
166
167            // Ethernet Controller (Class code: 0x02, Subclass: 0x00)
168            NETWORK_CONTROLLER_ETHERNET_GDMA = 0x00,
169        }
170    }
171
172    impl From<u8> for ProgrammingInterface {
173        fn from(c: u8) -> Self {
174            Self(c)
175        }
176    }
177
178    impl From<ProgrammingInterface> for u8 {
179        fn from(c: ProgrammingInterface) -> Self {
180            c.0
181        }
182    }
183}
184
185/// Configuration Space
186///
187/// Sources: PCI 2.3 Spec - Chapter 6
188#[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
189pub mod cfg_space {
190    use bitfield_struct::bitfield;
191    use inspect::Inspect;
192    use zerocopy::FromBytes;
193    use zerocopy::Immutable;
194    use zerocopy::IntoBytes;
195    use zerocopy::KnownLayout;
196
197    open_enum::open_enum! {
198        /// Common configuration space header registers shared between Type 0 and Type 1 headers.
199        ///
200        /// These registers appear at the same offsets in both header types and have the same
201        /// meaning and format.
202        ///
203        /// | Offset | Bits 31-24     | Bits 23-16  | Bits 15-8   | Bits 7-0             |
204        /// |--------|----------------|-------------|-------------|----------------------|
205        /// | 0x0    | Device ID      |             | Vendor ID   |                      |
206        /// | 0x4    | Status         |             | Command     |                      |
207        /// | 0x8    | Class code     |             |             | Revision ID          |
208        /// | 0x34   | Reserved       |             |             | Capabilities Pointer |
209        pub enum CommonHeader: u16 {
210            DEVICE_VENDOR       = 0x00,
211            STATUS_COMMAND      = 0x04,
212            CLASS_REVISION      = 0x08,
213            RESERVED_CAP_PTR    = 0x34,
214        }
215    }
216
217    /// Size of the common header portion shared by all PCI header types.
218    pub const COMMON_HEADER_SIZE: u16 = 0x10;
219
220    open_enum::open_enum! {
221        /// Offsets into the type 00h configuration space header.
222        ///
223        /// Table pulled from <https://wiki.osdev.org/PCI>
224        ///
225        /// | Offset | Bits 31-24                 | Bits 23-16  | Bits 15-8           | Bits 7-0             |
226        /// |--------|----------------------------|-------------|---------------------|--------------------- |
227        /// | 0x0    | Device ID                  |             | Vendor ID           |                      |
228        /// | 0x4    | Status                     |             | Command             |                      |
229        /// | 0x8    | Class code                 |             |                     | Revision ID          |
230        /// | 0xC    | BIST                       | Header type | Latency Timer       | Cache Line Size      |
231        /// | 0x10   | Base address #0 (BAR0)     |             |                     |                      |
232        /// | 0x14   | Base address #1 (BAR1)     |             |                     |                      |
233        /// | 0x18   | Base address #2 (BAR2)     |             |                     |                      |
234        /// | 0x1C   | Base address #3 (BAR3)     |             |                     |                      |
235        /// | 0x20   | Base address #4 (BAR4)     |             |                     |                      |
236        /// | 0x24   | Base address #5 (BAR5)     |             |                     |                      |
237        /// | 0x28   | Cardbus CIS Pointer        |             |                     |                      |
238        /// | 0x2C   | Subsystem ID               |             | Subsystem Vendor ID |                      |
239        /// | 0x30   | Expansion ROM base address |             |                     |                      |
240        /// | 0x34   | Reserved                   |             |                     | Capabilities Pointer |
241        /// | 0x38   | Reserved                   |             |                     |                      |
242        /// | 0x3C   | Max latency                | Min Grant   | Interrupt PIN       | Interrupt Line       |
243        pub enum HeaderType00: u16 {
244            DEVICE_VENDOR      = 0x00,
245            STATUS_COMMAND     = 0x04,
246            CLASS_REVISION     = 0x08,
247            BIST_HEADER        = 0x0C,
248            BAR0               = 0x10,
249            BAR1               = 0x14,
250            BAR2               = 0x18,
251            BAR3               = 0x1C,
252            BAR4               = 0x20,
253            BAR5               = 0x24,
254            CARDBUS_CIS_PTR    = 0x28,
255            SUBSYSTEM_ID       = 0x2C,
256            EXPANSION_ROM_BASE = 0x30,
257            RESERVED_CAP_PTR   = 0x34,
258            RESERVED           = 0x38,
259            LATENCY_INTERRUPT  = 0x3C,
260        }
261    }
262
263    pub const HEADER_TYPE_00_SIZE: u16 = 0x40;
264
265    open_enum::open_enum! {
266        /// Offsets into the type 01h configuration space header.
267        ///
268        /// Table pulled from <https://wiki.osdev.org/PCI>
269        ///
270        /// | Offset | Bits 31-24                       | Bits 23-16             | Bits 15-8                | Bits 7-0             |
271        /// |--------|----------------------------------|------------------------|--------------------------|--------------------- |
272        /// | 0x0    | Device ID                        |                        | Vendor ID                |                      |
273        /// | 0x4    | Status                           |                        | Command                  |                      |
274        /// | 0x8    | Class code                       |                        |                          | Revision ID          |
275        /// | 0xC    | BIST                             | Header Type            | Latency Timer            | Cache Line Size      |
276        /// | 0x10   | Base address #0 (BAR0)           |                        |                          |                      |
277        /// | 0x14   | Base address #1 (BAR1)           |                        |                          |                      |
278        /// | 0x18   | Secondary Latency Timer          | Subordinate Bus Number | Secondary Bus Number     | Primary Bus Number   |
279        /// | 0x1C   | Secondary Status                 |                        | I/O Limit                | I/O Base             |
280        /// | 0x20   | Memory Limit                     |                        | Memory Base              |                      |
281        /// | 0x24   | Prefetchable Memory Limit        |                        | Prefetchable Memory Base |                      |
282        /// | 0x28   | Prefetchable Base Upper 32 Bits  |                        |                          |                      |
283        /// | 0x2C   | Prefetchable Limit Upper 32 Bits |                        |                          |                      |
284        /// | 0x30   | I/O Limit Upper 16 Bits          |                        | I/O Base Upper 16 Bits   |                      |
285        /// | 0x34   | Reserved                         |                        |                          | Capabilities Pointer |
286        /// | 0x38   | Expansion ROM Base Address       |                        |                          |                      |
287        /// | 0x3C   | Bridge Control                   |                        | Interrupt PIN            | Interrupt Line       |
288        pub enum HeaderType01: u16 {
289            DEVICE_VENDOR         = 0x00,
290            STATUS_COMMAND        = 0x04,
291            CLASS_REVISION        = 0x08,
292            BIST_HEADER           = 0x0C,
293            BAR0                  = 0x10,
294            BAR1                  = 0x14,
295            LATENCY_BUS_NUMBERS   = 0x18,
296            SEC_STATUS_IO_RANGE   = 0x1C,
297            MEMORY_RANGE          = 0x20,
298            PREFETCH_RANGE        = 0x24,
299            PREFETCH_BASE_UPPER   = 0x28,
300            PREFETCH_LIMIT_UPPER  = 0x2C,
301            IO_RANGE_UPPER        = 0x30,
302            RESERVED_CAP_PTR      = 0x34,
303            EXPANSION_ROM_BASE    = 0x38,
304            BRDIGE_CTRL_INTERRUPT = 0x3C,
305        }
306    }
307
308    pub const HEADER_TYPE_01_SIZE: u16 = 0x40;
309
310    /// BAR in-band encoding bits.
311    ///
312    /// The low bits of the BAR are not actually part of the address.
313    /// Instead, they are used to in-band encode various bits of
314    /// metadata about the BAR, and are masked off when determining the
315    /// actual address.
316    #[bitfield(u32)]
317    pub struct BarEncodingBits {
318        pub use_pio: bool,
319
320        _reserved: bool,
321
322        /// False indicates 32 bit.
323        /// Only used in MMIO
324        pub type_64_bit: bool,
325        pub prefetchable: bool,
326
327        #[bits(28)]
328        _reserved2: u32,
329    }
330
331    /// Command Register
332    #[derive(Inspect)]
333    #[bitfield(u16)]
334    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
335    pub struct Command {
336        pub pio_enabled: bool,
337        pub mmio_enabled: bool,
338        pub bus_master: bool,
339        pub special_cycles: bool,
340        pub enable_memory_write_invalidate: bool,
341        pub vga_palette_snoop: bool,
342        pub parity_error_response: bool,
343        /// must be 0
344        #[bits(1)]
345        _reserved: u16,
346        pub enable_serr: bool,
347        pub enable_fast_b2b: bool,
348        pub intx_disable: bool,
349        #[bits(5)]
350        _reserved2: u16,
351    }
352
353    /// Status Register
354    #[bitfield(u16)]
355    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
356    pub struct Status {
357        #[bits(3)]
358        _reserved: u16,
359        pub interrupt_status: bool,
360        pub capabilities_list: bool,
361        pub capable_mhz_66: bool,
362        _reserved2: bool,
363        pub capable_fast_b2b: bool,
364        pub err_master_parity: bool,
365
366        #[bits(2)]
367        pub devsel: DevSel,
368
369        pub abort_target_signaled: bool,
370        pub abort_target_received: bool,
371        pub abort_master_received: bool,
372        pub err_signaled: bool,
373        pub err_detected_parity: bool,
374    }
375
376    #[derive(Debug)]
377    #[repr(u16)]
378    pub enum DevSel {
379        Fast = 0b00,
380        Medium = 0b01,
381        Slow = 0b10,
382    }
383
384    impl DevSel {
385        const fn from_bits(bits: u16) -> Self {
386            match bits {
387                0b00 => DevSel::Fast,
388                0b01 => DevSel::Medium,
389                0b10 => DevSel::Slow,
390                _ => unreachable!(),
391            }
392        }
393
394        const fn into_bits(self) -> u16 {
395            self as u16
396        }
397    }
398}
399
400/// Capabilities
401pub mod caps {
402    open_enum::open_enum! {
403        /// Capability IDs
404        ///
405        /// Sources: PCI 2.3 Spec - Appendix H
406        ///
407        /// NOTE: this is a non-exhaustive list, so don't be afraid to add new
408        /// variants on an as-needed basis!
409        pub enum CapabilityId: u8 {
410            #![expect(missing_docs)] // self explanatory variants
411            MSI             = 0x05,
412            VENDOR_SPECIFIC = 0x09,
413            PCI_EXPRESS     = 0x10,
414            MSIX            = 0x11,
415        }
416    }
417
418    /// MSI
419    #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
420    pub mod msi {
421        open_enum::open_enum! {
422            /// Offsets into the MSI Capability Header
423            ///
424            /// Based on PCI Local Bus Specification Rev 3.0, Section 6.8.1
425            ///
426            /// | Offset    | Bits 31-24    | Bits 23-16    | Bits 15-8     | Bits 7-0              |
427            /// |-----------|---------------|---------------|---------------|-----------------------|
428            /// | Cap + 0x0 | Message Control               | Next Pointer  | Capability ID (0x05)  |
429            /// | Cap + 0x4 | Message Address (32-bit or lower 32-bit of 64-bit)                    |
430            /// | Cap + 0x8 | Message Address Upper 32-bit (64-bit capable only)                    |
431            /// | Cap + 0xC | Message Data  |               |               |                       |
432            /// | Cap + 0x10| Mask Bits (Per-vector masking capable only)                           |
433            /// | Cap + 0x14| Pending Bits (Per-vector masking capable only)                        |
434            pub enum MsiCapabilityHeader: u16 {
435                CONTROL_CAPS = 0x00,
436                MSG_ADDR_LO  = 0x04,
437                MSG_ADDR_HI  = 0x08,
438                MSG_DATA_32  = 0x08,  // For 32-bit address capable
439                MSG_DATA_64  = 0x0C,  // For 64-bit address capable
440                MASK_BITS    = 0x10,  // 64-bit + per-vector masking
441                PENDING_BITS = 0x14,  // 64-bit + per-vector masking
442            }
443        }
444    }
445
446    /// MSI-X
447    #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
448    pub mod msix {
449        open_enum::open_enum! {
450            /// Offsets into the MSI-X Capability Header
451            ///
452            /// Table pulled from <https://wiki.osdev.org/PCI>
453            ///
454            /// | Offset    | Bits 31-24         | Bits 23-16 | Bits 15-8    | Bits 7-3             | Bits 2-0 |
455            /// |-----------|--------------------|------------|--------------|----------------------|----------|
456            /// | Cap + 0x0 | Message Control    |            | Next Pointer | Capability ID (0x11) |          |
457            /// | Cap + 0x4 | Table Offset       |            |              |                      | BIR      |
458            /// | Cap + 0x8 | Pending Bit Offset |            |              |                      | BIR      |
459            pub enum MsixCapabilityHeader: u16 {
460                CONTROL_CAPS = 0x00,
461                OFFSET_TABLE = 0x04,
462                OFFSET_PBA   = 0x08,
463            }
464        }
465
466        open_enum::open_enum! {
467            /// Offsets into a single MSI-X Table Entry
468            pub enum MsixTableEntryIdx: u16 {
469                MSG_ADDR_LO = 0x00,
470                MSG_ADDR_HI = 0x04,
471                MSG_DATA    = 0x08,
472                VECTOR_CTL  = 0x0C,
473            }
474        }
475    }
476
477    /// PCI Express
478    #[expect(missing_docs)] // primarily enums/structs with self-explanatory variants
479    pub mod pci_express {
480        use bitfield_struct::bitfield;
481        use inspect::Inspect;
482        use zerocopy::FromBytes;
483        use zerocopy::Immutable;
484        use zerocopy::IntoBytes;
485        use zerocopy::KnownLayout;
486
487        /// PCIe Link Speed encoding values for use in Link Capabilities and other registers.
488        ///
489        /// Values are defined in PCIe Base Specification for the Max Link Speed field
490        /// in Link Capabilities Register and similar fields.
491        #[derive(Debug)]
492        #[repr(u32)]
493        pub enum LinkSpeed {
494            /// 2.5 GT/s link speed
495            Speed2_5GtS = 0b0001,
496            /// 5.0 GT/s link speed
497            Speed5_0GtS = 0b0010,
498            /// 8.0 GT/s link speed
499            Speed8_0GtS = 0b0011,
500            /// 16.0 GT/s link speed
501            Speed16_0GtS = 0b0100,
502            /// 32.0 GT/s link speed
503            Speed32_0GtS = 0b0101,
504            /// 64.0 GT/s link speed
505            Speed64_0GtS = 0b0110,
506            // All other encodings are reserved
507        }
508
509        impl LinkSpeed {
510            pub const fn from_bits(bits: u32) -> Self {
511                match bits {
512                    0b0001 => LinkSpeed::Speed2_5GtS,
513                    0b0010 => LinkSpeed::Speed5_0GtS,
514                    0b0011 => LinkSpeed::Speed8_0GtS,
515                    0b0100 => LinkSpeed::Speed16_0GtS,
516                    0b0101 => LinkSpeed::Speed32_0GtS,
517                    0b0110 => LinkSpeed::Speed64_0GtS,
518                    _ => unreachable!(),
519                }
520            }
521
522            pub const fn into_bits(self) -> u32 {
523                self as u32
524            }
525        }
526
527        /// PCIe Supported Link Speeds Vector encoding values for use in Link Capabilities 2 register.
528        ///
529        /// Values are defined in PCIe Base Specification for the Supported Link Speeds Vector field
530        /// in Link Capabilities 2 Register. Each bit represents support for a specific generation.
531        #[derive(Debug)]
532        #[repr(u32)]
533        pub enum SupportedLinkSpeedsVector {
534            /// Support up to Gen 1 (2.5 GT/s)
535            UpToGen1 = 0b0000001,
536            /// Support up to Gen 2 (5.0 GT/s)
537            UpToGen2 = 0b0000011,
538            /// Support up to Gen 3 (8.0 GT/s)
539            UpToGen3 = 0b0000111,
540            /// Support up to Gen 4 (16.0 GT/s)
541            UpToGen4 = 0b0001111,
542            /// Support up to Gen 5 (32.0 GT/s)
543            UpToGen5 = 0b0011111,
544            /// Support up to Gen 6 (64.0 GT/s)
545            UpToGen6 = 0b0111111,
546            // All other encodings are reserved
547        }
548
549        impl SupportedLinkSpeedsVector {
550            pub const fn from_bits(bits: u32) -> Self {
551                match bits {
552                    0b0000001 => SupportedLinkSpeedsVector::UpToGen1,
553                    0b0000011 => SupportedLinkSpeedsVector::UpToGen2,
554                    0b0000111 => SupportedLinkSpeedsVector::UpToGen3,
555                    0b0001111 => SupportedLinkSpeedsVector::UpToGen4,
556                    0b0011111 => SupportedLinkSpeedsVector::UpToGen5,
557                    0b0111111 => SupportedLinkSpeedsVector::UpToGen6,
558                    _ => unreachable!(),
559                }
560            }
561
562            pub const fn into_bits(self) -> u32 {
563                self as u32
564            }
565        }
566
567        /// PCIe Link Width encoding values for use in Link Capabilities and other registers.
568        ///
569        /// Values are defined in PCIe Base Specification for the Max Link Width field
570        /// in Link Capabilities Register and similar fields.
571        #[derive(Debug)]
572        #[repr(u32)]
573        pub enum LinkWidth {
574            /// x1 link width
575            X1 = 0b000001,
576            /// x2 link width
577            X2 = 0b000010,
578            /// x4 link width
579            X4 = 0b000100,
580            /// x8 link width
581            X8 = 0b001000,
582            /// x16 link width
583            X16 = 0b010000,
584            // All other encodings are reserved
585        }
586
587        impl LinkWidth {
588            pub const fn from_bits(bits: u32) -> Self {
589                match bits {
590                    0b000001 => LinkWidth::X1,
591                    0b000010 => LinkWidth::X2,
592                    0b000100 => LinkWidth::X4,
593                    0b001000 => LinkWidth::X8,
594                    0b010000 => LinkWidth::X16,
595                    _ => unreachable!(),
596                }
597            }
598
599            pub const fn into_bits(self) -> u32 {
600                self as u32
601            }
602        }
603
604        open_enum::open_enum! {
605            /// Offsets into the PCI Express Capability Header
606            ///
607            /// Table pulled from PCI Express Base Specification Rev. 3.0
608            ///
609            /// | Offset    | Bits 31-24       | Bits 23-16       | Bits 15-8        | Bits 7-0             |
610            /// |-----------|------------------|----------------- |------------------|----------------------|
611            /// | Cap + 0x0 | PCI Express Capabilities Register   | Next Pointer     | Capability ID (0x10) |
612            /// | Cap + 0x4 | Device Capabilities Register                                                  |
613            /// | Cap + 0x8 | Device Status    | Device Control                                             |
614            /// | Cap + 0xC | Link Capabilities Register                                                    |
615            /// | Cap + 0x10| Link Status      | Link Control                                               |
616            /// | Cap + 0x14| Slot Capabilities Register                                                    |
617            /// | Cap + 0x18| Slot Status      | Slot Control                                               |
618            /// | Cap + 0x1C| Root Capabilities| Root Control                                               |
619            /// | Cap + 0x20| Root Status Register                                                          |
620            /// | Cap + 0x24| Device Capabilities 2 Register                                                |
621            /// | Cap + 0x28| Device Status 2  | Device Control 2                                           |
622            /// | Cap + 0x2C| Link Capabilities 2 Register                                                  |
623            /// | Cap + 0x30| Link Status 2    | Link Control 2                                             |
624            /// | Cap + 0x34| Slot Capabilities 2 Register                                                  |
625            /// | Cap + 0x38| Slot Status 2    | Slot Control 2                                             |
626            pub enum PciExpressCapabilityHeader: u16 {
627                PCIE_CAPS           = 0x00,
628                DEVICE_CAPS         = 0x04,
629                DEVICE_CTL_STS      = 0x08,
630                LINK_CAPS           = 0x0C,
631                LINK_CTL_STS        = 0x10,
632                SLOT_CAPS           = 0x14,
633                SLOT_CTL_STS        = 0x18,
634                ROOT_CTL_CAPS       = 0x1C,
635                ROOT_STS            = 0x20,
636                DEVICE_CAPS_2       = 0x24,
637                DEVICE_CTL_STS_2    = 0x28,
638                LINK_CAPS_2         = 0x2C,
639                LINK_CTL_STS_2      = 0x30,
640                SLOT_CAPS_2         = 0x34,
641                SLOT_CTL_STS_2      = 0x38,
642            }
643        }
644
645        /// PCI Express Capabilities Register
646        #[bitfield(u16)]
647        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
648        pub struct PciExpressCapabilities {
649            #[bits(4)]
650            pub capability_version: u16,
651            #[bits(4)]
652            pub device_port_type: DevicePortType,
653            pub slot_implemented: bool,
654            #[bits(5)]
655            pub interrupt_message_number: u16,
656            pub _undefined: bool,
657            pub flit_mode_supported: bool,
658        }
659
660        #[derive(Debug)]
661        #[repr(u16)]
662        pub enum DevicePortType {
663            Endpoint = 0b0000,
664            RootPort = 0b0100,
665            UpstreamSwitchPort = 0b0101,
666            DownstreamSwitchPort = 0b0110,
667        }
668
669        impl DevicePortType {
670            const fn from_bits(bits: u16) -> Self {
671                match bits {
672                    0b0000 => DevicePortType::Endpoint,
673                    0b0100 => DevicePortType::RootPort,
674                    0b0101 => DevicePortType::UpstreamSwitchPort,
675                    0b0110 => DevicePortType::DownstreamSwitchPort,
676                    _ => unreachable!(),
677                }
678            }
679
680            const fn into_bits(self) -> u16 {
681                self as u16
682            }
683        }
684
685        /// Device Capabilities Register (From the 6.4 spec)
686        #[bitfield(u32)]
687        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
688        pub struct DeviceCapabilities {
689            #[bits(3)]
690            pub max_payload_size: u32,
691            #[bits(2)]
692            pub phantom_functions: u32,
693            pub ext_tag_field: bool,
694            #[bits(3)]
695            pub endpoint_l0s_latency: u32,
696            #[bits(3)]
697            pub endpoint_l1_latency: u32,
698            #[bits(3)]
699            _reserved1: u32,
700            pub role_based_error: bool,
701            pub err_cor_subclass_capable: bool,
702            pub rx_mps_fixed: bool,
703            #[bits(8)]
704            pub captured_slot_power_limit: u32,
705            #[bits(2)]
706            pub captured_slot_power_scale: u32,
707            pub function_level_reset: bool,
708            pub mixed_mps_supported: bool,
709            pub tee_io_supported: bool,
710            _reserved3: bool,
711        }
712
713        /// Device Control Register
714        #[bitfield(u16)]
715        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
716        pub struct DeviceControl {
717            pub correctable_error_reporting_enable: bool,
718            pub non_fatal_error_reporting_enable: bool,
719            pub fatal_error_reporting_enable: bool,
720            pub unsupported_request_reporting_enable: bool,
721            pub enable_relaxed_ordering: bool,
722            #[bits(3)]
723            pub max_payload_size: u16,
724            pub extended_tag_enable: bool,
725            pub phantom_functions_enable: bool,
726            pub aux_power_pm_enable: bool,
727            pub enable_no_snoop: bool,
728            #[bits(3)]
729            pub max_read_request_size: u16,
730            pub initiate_function_level_reset: bool,
731        }
732
733        /// Device Status Register
734        #[bitfield(u16)]
735        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
736        pub struct DeviceStatus {
737            pub correctable_error_detected: bool,
738            pub non_fatal_error_detected: bool,
739            pub fatal_error_detected: bool,
740            pub unsupported_request_detected: bool,
741            pub aux_power_detected: bool,
742            pub transactions_pending: bool,
743            #[bits(10)]
744            _reserved: u16,
745        }
746
747        /// Link Capabilities Register
748        #[bitfield(u32)]
749        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
750        pub struct LinkCapabilities {
751            #[bits(4)]
752            pub max_link_speed: u32,
753            #[bits(6)]
754            pub max_link_width: u32,
755            #[bits(2)]
756            pub aspm_support: u32,
757            #[bits(3)]
758            pub l0s_exit_latency: u32,
759            #[bits(3)]
760            pub l1_exit_latency: u32,
761            pub clock_power_management: bool,
762            pub surprise_down_error_reporting: bool,
763            pub data_link_layer_link_active_reporting: bool,
764            pub link_bandwidth_notification_capability: bool,
765            pub aspm_optionality_compliance: bool,
766            #[bits(1)]
767            _reserved: u32,
768            #[bits(8)]
769            pub port_number: u32,
770        }
771
772        /// Link Control Register
773        #[bitfield(u16)]
774        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
775        pub struct LinkControl {
776            #[bits(2)]
777            pub aspm_control: u16,
778            pub ptm_propagation_delay_adaptation_interpretation_b: bool,
779            #[bits(1)]
780            pub read_completion_boundary: u16,
781            pub link_disable: bool,
782            pub retrain_link: bool,
783            pub common_clock_configuration: bool,
784            pub extended_synch: bool,
785            pub enable_clock_power_management: bool,
786            pub hardware_autonomous_width_disable: bool,
787            pub link_bandwidth_management_interrupt_enable: bool,
788            pub link_autonomous_bandwidth_interrupt_enable: bool,
789            #[bits(1)]
790            pub sris_clocking: u16,
791            pub flit_mode_disable: bool,
792            #[bits(2)]
793            pub drs_signaling_control: u16,
794        }
795
796        /// Link Status Register
797        #[bitfield(u16)]
798        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
799        pub struct LinkStatus {
800            #[bits(4)]
801            pub current_link_speed: u16,
802            #[bits(6)]
803            pub negotiated_link_width: u16,
804            #[bits(1)]
805            _reserved: u16,
806            pub link_training: bool,
807            pub slot_clock_configuration: bool,
808            pub data_link_layer_link_active: bool,
809            pub link_bandwidth_management_status: bool,
810            pub link_autonomous_bandwidth_status: bool,
811        }
812
813        /// Slot Capabilities Register
814        #[bitfield(u32)]
815        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
816        pub struct SlotCapabilities {
817            pub attention_button_present: bool,
818            pub power_controller_present: bool,
819            pub mrl_sensor_present: bool,
820            pub attention_indicator_present: bool,
821            pub power_indicator_present: bool,
822            pub hot_plug_surprise: bool,
823            pub hot_plug_capable: bool,
824            #[bits(8)]
825            pub slot_power_limit_value: u32,
826            #[bits(2)]
827            pub slot_power_limit_scale: u32,
828            pub electromechanical_interlock_present: bool,
829            pub no_command_completed_support: bool,
830            #[bits(13)]
831            pub physical_slot_number: u32,
832        }
833
834        /// Slot Control Register
835        #[bitfield(u16)]
836        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
837        pub struct SlotControl {
838            pub attention_button_pressed_enable: bool,
839            pub power_fault_detected_enable: bool,
840            pub mrl_sensor_changed_enable: bool,
841            pub presence_detect_changed_enable: bool,
842            pub command_completed_interrupt_enable: bool,
843            pub hot_plug_interrupt_enable: bool,
844            #[bits(2)]
845            pub attention_indicator_control: u16,
846            #[bits(2)]
847            pub power_indicator_control: u16,
848            pub power_controller_control: bool,
849            pub electromechanical_interlock_control: bool,
850            pub data_link_layer_state_changed_enable: bool,
851            pub auto_slot_power_limit_enable: bool,
852            pub in_band_pd_disable: bool,
853            #[bits(1)]
854            _reserved: u16,
855        }
856
857        /// Slot Status Register
858        #[bitfield(u16)]
859        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
860        pub struct SlotStatus {
861            pub attention_button_pressed: bool,
862            pub power_fault_detected: bool,
863            pub mrl_sensor_changed: bool,
864            pub presence_detect_changed: bool,
865            pub command_completed: bool,
866            #[bits(1)]
867            pub mrl_sensor_state: u16,
868            #[bits(1)]
869            pub presence_detect_state: u16,
870            #[bits(1)]
871            pub electromechanical_interlock_status: u16,
872            pub data_link_layer_state_changed: bool,
873            #[bits(7)]
874            _reserved: u16,
875        }
876
877        /// Root Control Register
878        #[bitfield(u16)]
879        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
880        pub struct RootControl {
881            pub system_error_on_correctable_error_enable: bool,
882            pub system_error_on_non_fatal_error_enable: bool,
883            pub system_error_on_fatal_error_enable: bool,
884            pub pme_interrupt_enable: bool,
885            pub crs_software_visibility_enable: bool,
886            pub no_nfm_subtree_below_this_root_port: bool,
887            #[bits(10)]
888            _reserved: u16,
889        }
890
891        /// Root Capabilities Register
892        #[bitfield(u16)]
893        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
894        pub struct RootCapabilities {
895            pub crs_software_visibility: bool,
896            #[bits(15)]
897            _reserved: u16,
898        }
899
900        /// Root Status Register
901        #[bitfield(u32)]
902        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
903        pub struct RootStatus {
904            #[bits(16)]
905            pub pme_requester_id: u32,
906            pub pme_status: bool,
907            pub pme_pending: bool,
908            #[bits(14)]
909            _reserved: u32,
910        }
911
912        /// Device Capabilities 2 Register
913        #[bitfield(u32)]
914        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
915        pub struct DeviceCapabilities2 {
916            #[bits(4)]
917            pub completion_timeout_ranges_supported: u32,
918            pub completion_timeout_disable_supported: bool,
919            pub ari_forwarding_supported: bool,
920            pub atomic_op_routing_supported: bool,
921            pub atomic_op_32_bit_completer_supported: bool,
922            pub atomic_op_64_bit_completer_supported: bool,
923            pub cas_128_bit_completer_supported: bool,
924            pub no_ro_enabled_pr_pr_passing: bool,
925            pub ltr_mechanism_supported: bool,
926            #[bits(2)]
927            pub tph_completer_supported: u32,
928            #[bits(2)]
929            _reserved: u32,
930            pub ten_bit_tag_completer_supported: bool,
931            pub ten_bit_tag_requester_supported: bool,
932            #[bits(2)]
933            pub obff_supported: u32,
934            pub extended_fmt_field_supported: bool,
935            pub end_end_tlp_prefix_supported: bool,
936            #[bits(2)]
937            pub max_end_end_tlp_prefixes: u32,
938            #[bits(2)]
939            pub emergency_power_reduction_supported: u32,
940            pub emergency_power_reduction_init_required: bool,
941            #[bits(1)]
942            _reserved: u32,
943            pub dmwr_completer_supported: bool,
944            #[bits(2)]
945            pub dmwr_lengths_supported: u32,
946            pub frs_supported: bool,
947        }
948
949        /// Device Control 2 Register
950        #[bitfield(u16)]
951        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
952        pub struct DeviceControl2 {
953            #[bits(4)]
954            pub completion_timeout_value: u16,
955            pub completion_timeout_disable: bool,
956            pub ari_forwarding_enable: bool,
957            pub atomic_op_requester_enable: bool,
958            pub atomic_op_egress_blocking: bool,
959            pub ido_request_enable: bool,
960            pub ido_completion_enable: bool,
961            pub ltr_mechanism_enable: bool,
962            pub emergency_power_reduction_request: bool,
963            pub ten_bit_tag_requester_enable: bool,
964            #[bits(2)]
965            pub obff_enable: u16,
966            pub end_end_tlp_prefix_blocking: bool,
967        }
968
969        /// Device Status 2 Register
970        #[bitfield(u16)]
971        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
972        pub struct DeviceStatus2 {
973            #[bits(16)]
974            _reserved: u16,
975        }
976
977        /// Link Capabilities 2 Register
978        #[bitfield(u32)]
979        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
980        pub struct LinkCapabilities2 {
981            #[bits(1)]
982            _reserved: u32,
983            #[bits(7)]
984            pub supported_link_speeds_vector: u32,
985            pub crosslink_supported: bool,
986            #[bits(7)]
987            pub lower_skp_os_generation_supported_speeds_vector: u32,
988            #[bits(7)]
989            pub lower_skp_os_reception_supported_speeds_vector: u32,
990            pub retimer_presence_detect_supported: bool,
991            pub two_retimers_presence_detect_supported: bool,
992            #[bits(6)]
993            _reserved: u32,
994            pub drs_supported: bool,
995        }
996
997        /// Link Control 2 Register
998        #[bitfield(u16)]
999        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1000        pub struct LinkControl2 {
1001            #[bits(4)]
1002            pub target_link_speed: u16,
1003            pub enter_compliance: bool,
1004            pub hardware_autonomous_speed_disable: bool,
1005            #[bits(1)]
1006            pub selectable_de_emphasis: u16,
1007            #[bits(3)]
1008            pub transmit_margin: u16,
1009            pub enter_modified_compliance: bool,
1010            pub compliance_sos: bool,
1011            #[bits(4)]
1012            pub compliance_preset_de_emphasis: u16,
1013        }
1014
1015        /// Link Status 2 Register
1016        #[bitfield(u16)]
1017        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1018        pub struct LinkStatus2 {
1019            #[bits(1)]
1020            pub current_de_emphasis_level: u16,
1021            pub equalization_8gts_complete: bool,
1022            pub equalization_8gts_phase_1_successful: bool,
1023            pub equalization_8gts_phase_2_successful: bool,
1024            pub equalization_8gts_phase_3_successful: bool,
1025            pub link_equalization_request_8gts: bool,
1026            pub retimer_presence_detected: bool,
1027            pub two_retimers_presence_detected: bool,
1028            #[bits(2)]
1029            pub crosslink_resolution: u16,
1030            pub flit_mode_status: bool,
1031            #[bits(1)]
1032            _reserved: u16,
1033            #[bits(3)]
1034            pub downstream_component_presence: u16,
1035            pub drs_message_received: bool,
1036        }
1037
1038        /// Slot Capabilities 2 Register
1039        #[bitfield(u32)]
1040        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1041        pub struct SlotCapabilities2 {
1042            pub in_band_pd_disable_supported: bool,
1043            #[bits(31)]
1044            _reserved: u32,
1045        }
1046
1047        /// Slot Control 2 Register
1048        #[bitfield(u16)]
1049        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1050        pub struct SlotControl2 {
1051            #[bits(16)]
1052            _reserved: u16,
1053        }
1054
1055        /// Slot Status 2 Register
1056        #[bitfield(u16)]
1057        #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
1058        pub struct SlotStatus2 {
1059            #[bits(16)]
1060            _reserved: u16,
1061        }
1062    }
1063}