lspci/
config.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use crate::util::is_set;
5use bitfield::bitfield;
6use std::fmt;
7use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref};
8
9// PCI Local Bus Specification v3.0 section 6.1
10#[repr(C, packed)]
11#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
12pub struct Type00Config {
13    pub vendor_id: u16,
14    pub device_id: u16,
15    pub command: u16,
16    pub status: u16,
17    pub revision_id: u8,
18    pub program_interface: u8,
19    pub sub_class: u8,
20    pub base_class: u8,
21    pub cache_line_size: u8,
22    pub latency_timer: u8,
23    pub header_type: u8,
24    pub bist: u8,
25    pub base_address: [u32; 6],
26    pub cardbus_cis_ptr: u32,
27    pub sub_vendor_id: u16,
28    pub subsystem_id: u16,
29    pub expansion_rom_address: u32,
30    pub capabilities_ptr: u8,
31    pub reserved_0: [u8; 3],
32    pub reserved_1: [u8; 4],
33    pub interrupt_line: u8,
34    pub interrupt_pin: u8,
35    pub min_grant: u8,
36    pub max_latency: u8,
37}
38
39impl Type00Config {
40    pub fn new(config: &[u8]) -> Ref<&[u8], Type00Config> {
41        let (config, _) = Ref::from_prefix(config).unwrap();
42        config
43    }
44}
45
46#[repr(C, packed)]
47#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
48pub struct Type01Config {
49    pub vendor_id: u16,
50    pub device_id: u16,
51    pub command: u16,
52    pub status: u16,
53    pub revision_id: u8,
54    pub program_interface: u8,
55    pub sub_class: u8,
56    pub base_class: u8,
57    pub cache_line_size: u8,
58    pub latency_timer: u8,
59    pub header_type: u8,
60    pub bist: u8,
61    pub base_address: [u32; 2],
62    pub primary_bus_number: u8,
63    pub secondary_bus_number: u8,
64    pub subordinate_bus_number: u8,
65    pub secondary_latency_timer: u8,
66    pub io_base: u8,
67    pub io_limit: u8,
68    pub secondary_status: u16,
69    pub memory_base: u16,
70    pub memory_limit: u16,
71    pub pf_memory_base: u16,
72    pub pf_memory_limit: u16,
73    pub pf_base_upper_32: u32,
74    pub pf_limit_upper_32: u32,
75    pub io_base_upper_16: u16,
76    pub io_limit_upper_16: u16,
77    pub capabilities_ptr: u8,
78    pub reserved_0: [u8; 3],
79    pub expansion_rom_base: u32,
80    pub interrupt_line: u8,
81    pub interrupt_pin: u8,
82    pub bridge_control: u16,
83}
84
85impl Type01Config {
86    pub fn new(config: &[u8]) -> Ref<&[u8], Type01Config> {
87        let (config, _) = Ref::from_prefix(config).unwrap();
88        config
89    }
90}
91
92// PCI Local Bus Specification v3.0 6.2.2.
93// Bit 7 was valid in v2.1 but in v3.0 is hardwired to 0.
94bitfield! {
95    pub struct CommandRegister(u16);
96    pub io_space, _: 0;
97    pub memory_space, _: 1;
98    pub bus_master_en, _: 2;
99    pub special_cycles, _: 3;
100    pub mem_winv_en, _: 4;
101    pub vga_snoop, _: 5;
102    pub parity_error_response, _: 6;
103    // 7 reserved
104    pub serr_en, _: 8;
105    pub fb2b_en, _: 9;
106    pub int_disable, _: 10;
107    // 15:11 reserved
108}
109
110impl fmt::Display for CommandRegister {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        write!(f, "I/O{} Mem{} BusMaster{} SpecCycle{} MemWINV{} VGASnoop{} ParErr{} SERR{} FastB2B{} DisINTx{}",
113        is_set(self.io_space()),
114        is_set(self.memory_space()),
115        is_set(self.bus_master_en()),
116        is_set(self.special_cycles()),
117        is_set(self.mem_winv_en()),
118        is_set(self.vga_snoop()),
119        is_set(self.parity_error_response()),
120        is_set(self.serr_en()),
121        is_set(self.fb2b_en()),
122        is_set(self.int_disable()))
123    }
124}
125
126// PCI Local Bus Specification v3.0 6.2.3.
127// Bit 6 is reserved in v3.0, but was a valid field in v2.1.
128bitfield! {
129    pub struct StatusRegister(u16);
130    // 2:0 reserved
131    pub int_status, _: 3;
132    pub has_cap_list, _: 4;
133    pub supports_66mhz, _: 5;
134    // 6 reserved
135    pub fb2b, _: 7;
136    pub master_data_parity_error, _: 8;
137    pub devsel_timing, _: 10, 9;
138    pub signaled_target_abort, _: 11;
139    pub received_target_abort, _: 12;
140    pub received_master_abort, _: 13;
141    pub signaled_system_error, _: 14;
142    pub detected_parity_error, _: 15;
143}
144
145impl fmt::Display for StatusRegister {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        write!(f, "Cap{} 66Mhz{} FastB2B{} ParErr{} DEVSEL={} >TAbort{} <TAbort{} MAbort{} >SERR{} <PERR{} INTx{}",
148        is_set(self.has_cap_list()),
149        is_set(self.supports_66mhz()),
150        is_set(self.fb2b()),
151        is_set(self.master_data_parity_error()),
152        match self.devsel_timing() {
153            0 => "fast",
154            1 => "medium",
155            2 => "slow",
156            _ => "<3?>",
157        },
158        is_set(self.signaled_target_abort()),
159        is_set(self.received_target_abort()),
160        is_set(self.received_master_abort()),
161        is_set(self.signaled_system_error()),
162        is_set(self.detected_parity_error()),
163        is_set(self.int_status()))
164    }
165}
166
167bitfield! {
168    pub struct SecondaryStatusRegister(u16);
169    // 4:0 reserved
170    pub supports_66mhz, _: 5;
171    // 6 reserved
172    pub fb2b, _: 7;
173    pub master_data_parity_error, _: 8;
174    pub devsel_timing, _: 10, 9;
175    pub signaled_target_abort, _: 11;
176    pub received_target_abort, _: 12;
177    pub received_master_abort, _: 13;
178    pub received_system_error, _: 14;
179    pub detected_parity_error, _: 15;
180}
181
182impl fmt::Display for SecondaryStatusRegister {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(
185            f,
186            "66Mhz{} FastB2B{} ParErr{} DEVSEL={} >TAbort{} <TAbort{} MAbort{} <SERR{} <PERR{}",
187            is_set(self.supports_66mhz()),
188            is_set(self.fb2b()),
189            is_set(self.master_data_parity_error()),
190            match self.devsel_timing() {
191                0 => "fast",
192                1 => "medium",
193                2 => "slow",
194                _ => "<3?>",
195            },
196            is_set(self.signaled_target_abort()),
197            is_set(self.received_target_abort()),
198            is_set(self.received_master_abort()),
199            is_set(self.received_system_error()),
200            is_set(self.detected_parity_error())
201        )
202    }
203}
204
205bitfield! {
206    pub struct BridgeControlRegister(u16);
207    pub parity_error_response_en, _: 0;
208    pub serr_en, _: 1;
209    pub isa_en, _: 2;
210    pub vga_en, _: 3;
211    pub vga_16bit_decode, _: 4;
212    pub master_mode_abort, _: 5;
213    pub secondary_bus_reset, _: 6;
214    pub fb2b_en, _: 7;
215    pub primary_discard_timer, _: 8;
216    pub secondary_discard_timer, _: 9;
217    pub discard_timer_status, _: 10;
218    pub discard_timer_serr_en, _: 11;
219    // 15:12 reserved
220}
221
222impl fmt::Display for BridgeControlRegister {
223    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224        writeln!(
225            f,
226            "Parity{} SERR{} NoISA{} VGA{} VGA16{} MAbort{} >Reset{} FastB2b{}",
227            is_set(self.parity_error_response_en()),
228            is_set(self.serr_en()),
229            is_set(self.isa_en()),
230            is_set(self.vga_en()),
231            is_set(self.vga_16bit_decode()),
232            is_set(self.master_mode_abort()),
233            is_set(self.secondary_bus_reset()),
234            is_set(self.fb2b_en())
235        )?;
236        write!(
237            f,
238            "\t\tPriDiscTmr{} SecDiscTmr{} DiscTmrStat{} DiscTmrSERREn{}",
239            is_set(self.primary_discard_timer()),
240            is_set(self.secondary_discard_timer()),
241            is_set(self.discard_timer_status()),
242            is_set(self.discard_timer_serr_en())
243        )
244    }
245}