devices/pci/pcie/
pcie_device.rs

1// Copyright 2021 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::sync::Arc;
6
7use resources::SystemAllocator;
8use sync::Mutex;
9use zerocopy::FromBytes;
10use zerocopy::Immutable;
11use zerocopy::IntoBytes;
12use zerocopy::KnownLayout;
13
14use crate::pci::pci_configuration::PciCapConfig;
15use crate::pci::pci_configuration::PciCapConfigWriteResult;
16use crate::pci::pci_configuration::PciCapabilityID;
17use crate::pci::pcie::pci_bridge::PciBridgeBusRange;
18use crate::pci::pcie::*;
19use crate::pci::MsiConfig;
20use crate::pci::PciAddress;
21use crate::pci::PciCapability;
22use crate::pci::PciDeviceError;
23
24pub trait PcieDevice: Send {
25    fn get_device_id(&self) -> u16;
26    fn debug_label(&self) -> String;
27    fn preferred_address(&self) -> Option<PciAddress> {
28        None
29    }
30    fn allocate_address(
31        &mut self,
32        resources: &mut SystemAllocator,
33    ) -> std::result::Result<PciAddress, PciDeviceError>;
34    fn read_config(&self, reg_idx: usize, data: &mut u32);
35    fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]);
36    fn handle_cap_write_result(&mut self, res: Box<dyn PciCapConfigWriteResult>);
37    fn clone_interrupt(&mut self, msi_config: Arc<Mutex<MsiConfig>>);
38    fn get_caps(&self) -> Vec<(Box<dyn PciCapability>, Option<Box<dyn PciCapConfig>>)>;
39    fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
40        None
41    }
42    fn get_removed_devices(&self) -> Vec<PciAddress>;
43
44    /// Hotplug capability is implemented on this bridge or not.
45    /// Return true, the children pci devices could be connected through hotplug
46    /// Return false, the children pci devices should be connected statically
47    fn hotplug_implemented(&self) -> bool;
48
49    /// This function returns true if this pcie device is hotplugged into the system
50    fn hotplugged(&self) -> bool;
51
52    /// Get bridge window size to cover children's mmio size
53    /// (u64, u64) -> (non_prefetchable window size, prefetchable_window_size)
54    fn get_bridge_window_size(&self) -> (u64, u64);
55}
56
57#[repr(C)]
58#[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
59pub struct PcieCap {
60    _cap_vndr: u8,
61    _cap_next: u8,
62    pcie_cap: u16,
63    dev_cap: u32,
64    dev_control: u16,
65    dev_status: u16,
66    link_cap: u32,
67    link_control: u16,
68    link_status: u16,
69    slot_cap: u32,
70    slot_control: u16,
71    slot_status: u16,
72    root_control: u16,
73    root_cap: u16,
74    root_status: u32,
75    dev_cap_2: u32,
76    dev_control_2: u16,
77    dev_status_2: u16,
78    link_cap_2: u32,
79    link_control_2: u16,
80    link_status_2: u16,
81    slot_cap_2: u32,
82    slot_control_2: u16,
83    slot_status_2: u16,
84}
85
86impl PciCapability for PcieCap {
87    fn bytes(&self) -> &[u8] {
88        self.as_bytes()
89    }
90
91    fn id(&self) -> PciCapabilityID {
92        PciCapabilityID::PciExpress
93    }
94
95    fn writable_bits(&self) -> Vec<u32> {
96        vec![
97            0u32,
98            0,
99            0xf_ffff,
100            0,
101            0x3000_0fff,
102            0,
103            0x11f_1fff,
104            0x1f,
105            0,
106            0,
107            0,
108            0,
109            0,
110            0,
111            0,
112        ]
113    }
114}
115
116impl PcieCap {
117    pub fn new(device_type: PcieDevicePortType, slot: bool, irq_num: u16) -> Self {
118        let mut pcie_cap = PCIE_CAP_VERSION;
119        pcie_cap |= (device_type as u16) << PCIE_TYPE_SHIFT;
120        if slot {
121            pcie_cap |= 1 << PCIE_CAP_SLOT_SHIFT;
122        }
123        pcie_cap |= irq_num << PCIE_CAP_IRQ_NUM_SHIFT;
124
125        let dev_cap = PCIE_DEVCAP_RBER;
126        let link_cap = (PCIE_LINK_X1 | PCIE_LINK_2_5GT) as u32;
127        let link_status = PCIE_LINK_X1 | PCIE_LINK_2_5GT;
128
129        let mut slot_cap: u32 = 0;
130        let mut slot_control: u16 = 0;
131        if slot {
132            slot_cap = PCIE_SLTCAP_ABP
133                | PCIE_SLTCAP_AIP
134                | PCIE_SLTCAP_PIP
135                | PCIE_SLTCAP_HPS
136                | PCIE_SLTCAP_HPC;
137            slot_control = PCIE_SLTCTL_PIC_OFF | PCIE_SLTCTL_AIC_OFF;
138        }
139
140        PcieCap {
141            _cap_vndr: 0,
142            _cap_next: 0,
143            pcie_cap,
144            dev_cap,
145            dev_control: 0,
146            dev_status: 0,
147            link_cap,
148            link_control: 0,
149            link_status,
150            slot_cap,
151            slot_control,
152            slot_status: 0,
153            root_control: 0,
154            root_cap: 0,
155            root_status: 0,
156            dev_cap_2: 0,
157            dev_control_2: 0,
158            dev_status_2: 0,
159            link_cap_2: 0,
160            link_control_2: 0,
161            link_status_2: 0,
162            slot_cap_2: 0,
163            slot_control_2: 0,
164            slot_status_2: 0,
165        }
166    }
167}