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