pci_driver/config/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/* ---------------------------------------------------------------------------------------------- */
4
5pub mod caps;
6pub mod ext_caps;
7
8use std::io;
9
10use crate::config::caps::PciCapabilities;
11use crate::config::ext_caps::PciExtendedCapabilities;
12use crate::regions::structured::{PciRegisterRo, PciRegisterRw};
13use crate::{pci_bit_field, pci_struct};
14
15/* ---------------------------------------------------------------------------------------------- */
16
17pci_struct! {
18    /// This lets you interact with the config space (conventional or extended) of a PCI device.
19    ///
20    /// This doesn't have a definite length because we want to preserve the `PciSubregion` over the
21    /// whole of config space.
22    pub struct PciConfig<'a> {
23        vendor_id           @ 0x00 : PciRegisterRo<'a, u16>,
24        device_id           @ 0x02 : PciRegisterRo<'a, u16>,
25        command             @ 0x04 : PciCommand<'a>,
26        status              @ 0x06 : PciStatus<'a>,
27        revision_id         @ 0x08 : PciRegisterRo<'a, u8>,
28        class_code          @ 0x09 : PciClassCode<'a>,
29        cache_line_size     @ 0x0c : PciRegisterRw<'a, u8>,
30        latency_timer       @ 0x0d : PciRegisterRo<'a, u8>,
31        header_type         @ 0x0e : PciHeaderType<'a>,
32        bist                @ 0x0f : PciBist<'a>,
33        cardbus_cis_pointer @ 0x28 : PciRegisterRo<'a, u32>,
34        subsystem_vendor_id @ 0x2c : PciRegisterRo<'a, u16>,
35        subsystem_id        @ 0x2e : PciRegisterRo<'a, u16>,
36        interrupt_line      @ 0x3c : PciRegisterRw<'a, u8>,
37        interrupt_pin       @ 0x3d : PciRegisterRo<'a, u8>,
38        min_gnt             @ 0x3e : PciRegisterRo<'a, u8>,
39        max_lat             @ 0x3f : PciRegisterRo<'a, u8>,
40    }
41}
42
43impl<'a> PciConfig<'a> {
44    /// Returns a thing that lets you access the PCI Capabilities.
45    ///
46    /// Calling this will (re)scan all Capabilities, which is why it can fail.
47    pub fn capabilities(&self) -> io::Result<PciCapabilities<'a>> {
48        PciCapabilities::backed_by(*self)
49    }
50
51    /// Returns a thing that lets you access the PCI Extended Capabilities.
52    ///
53    /// Calling this will (re)scan all Extended Capabilities, which is why it can fail.
54    pub fn extended_capabilities(&self) -> io::Result<PciExtendedCapabilities<'a>> {
55        PciExtendedCapabilities::backed_by(*self)
56    }
57}
58
59// 7.5.1.1.3 Command Register
60
61pci_bit_field! {
62    pub struct PciCommand<'a> : RW u16 {
63        io_space_enable                       @      0 : RW,
64        memory_space_enable                   @      1 : RW,
65        bus_master_enable                     @      2 : RW,
66        special_cycle_enable                  @      3 : RO,
67        memory_write_and_invalidate           @      4 : RO,
68        vga_palette_snoop                     @      5 : RO,
69        parity_error_response                 @      6 : RW,
70        idsel_stepping_wait_cycle_control     @      7 : RO,
71        serr_enable                           @      8 : RW,
72        fast_back_to_back_transactions_enable @      9 : RO,
73        interrupt_disable                     @     10 : RW1C,
74        __                                    @ 11--15 : RsvdP,
75    }
76}
77
78// 7.5.1.1.4 Status Register
79
80pci_bit_field! {
81    pub struct PciStatus<'a> : RW u16 {
82        immediate_readiness                    @     0 : RO,
83        __                                     @  1--2 : RsvdZ,
84        interrupt_status                       @     3 : RO,
85        capabilities_list                      @     4 : RO,
86        mhz_66_capable                         @     5 : RO,
87        __                                     @     6 : RsvdZ,
88        fast_back_to_back_transactions_capable @     7 : RO,
89        master_data_parity_error               @     8 : RW1C,
90        devsel_timing                          @ 9--10 : RO u8,
91        signaled_target_abort                  @    11 : RW1C,
92        received_target_abort                  @    12 : RW1C,
93        received_master_abort                  @    13 : RW1C,
94        signaled_system_error                  @    14 : RW1C,
95        detected_parity_error                  @    15 : RW1C,
96    }
97}
98
99// 7.5.1.1.6 Class Code Register
100
101pci_struct! {
102    pub struct PciClassCode<'a> : 0x03 {
103        base_class_code       @ 0x00 : PciRegisterRo<'a, u8>,
104        sub_class_code        @ 0x01 : PciRegisterRo<'a, u8>,
105        programming_interface @ 0x02 : PciRegisterRo<'a, u8>,
106    }
107}
108
109// 7.5.1.1.9 Header Type Register
110
111pci_bit_field! {
112    pub struct PciHeaderType<'a> : RO u8 {
113        header_layout         @ 0--6 : RO u8,
114        multi_function_device @    7 : RO,
115    }
116}
117
118// 7.5.1.1.10 BIST Register
119
120pci_bit_field! {
121    pub struct PciBist<'a> : RW u8 {
122        completion_code @ 0--3 : RO u8,
123        __              @ 4--5 : RsvdP,
124        start_bist      @    6 : RW,
125        bist_capable    @    7 : RO,
126    }
127}
128
129/* ---------------------------------------------------------------------------------------------- */
130
131#[cfg(test)]
132mod tests {
133    use crate::backends::mock::MockPciDevice;
134    use crate::config::caps::Capability;
135    use crate::config::ext_caps::ExtendedCapability;
136    use crate::device::PciDevice;
137
138    #[test]
139    fn test_lifetimes() {
140        let device: &dyn PciDevice = &MockPciDevice;
141
142        let value_1 = device.config().command().io_space_enable();
143        let value_2 = device
144            .config()
145            .capabilities()
146            .unwrap()
147            .iter()
148            .next()
149            .unwrap()
150            .header()
151            .capability_id();
152
153        value_1.read().unwrap();
154        value_2.read().unwrap();
155        value_1.read().unwrap();
156    }
157
158    #[test]
159    fn test_capabilities() {
160        let device: &dyn PciDevice = &MockPciDevice;
161
162        let cap_ids: Vec<_> = device
163            .config()
164            .capabilities()
165            .unwrap()
166            .iter()
167            .map(|cap| cap.header().capability_id().read().unwrap())
168            .collect();
169
170        assert_eq!(cap_ids, vec![0x01, 0x05, 0x10, 0x11]);
171    }
172
173    #[test]
174    fn test_extended_capabilities() {
175        let device: &dyn PciDevice = &MockPciDevice;
176
177        let ext_cap_ids: Vec<_> = device
178            .config()
179            .extended_capabilities()
180            .unwrap()
181            .iter()
182            .map(|cap| cap.header().capability_id().read().unwrap())
183            .collect();
184
185        assert_eq!(
186            ext_cap_ids,
187            vec![0x0001, 0x0003, 0x0004, 0x0019, 0x0018, 0x001e]
188        );
189    }
190}
191
192/* ---------------------------------------------------------------------------------------------- */