• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium OS 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.
4 use std::sync::Arc;
5 use sync::Mutex;
6 
7 use crate::pci::pci_configuration::PciCapabilityID;
8 use crate::pci::pcie::pci_bridge::PciBridgeBusRange;
9 use crate::pci::pcie::*;
10 use crate::pci::{MsixConfig, PciAddress, PciCapability, PciDeviceError};
11 use data_model::DataInit;
12 use resources::SystemAllocator;
13 
14 pub trait PcieDevice: Send {
get_device_id(&self) -> u1615     fn get_device_id(&self) -> u16;
debug_label(&self) -> String16     fn debug_label(&self) -> String;
allocate_address( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<PciAddress, PciDeviceError>17     fn allocate_address(
18         &mut self,
19         resources: &mut SystemAllocator,
20     ) -> std::result::Result<PciAddress, PciDeviceError>;
read_config(&self, reg_idx: usize, data: &mut u32)21     fn read_config(&self, reg_idx: usize, data: &mut u32);
write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8])22     fn write_config(&mut self, reg_idx: usize, offset: u64, data: &[u8]);
clone_interrupt(&mut self, msix_config: Arc<Mutex<MsixConfig>>)23     fn clone_interrupt(&mut self, msix_config: Arc<Mutex<MsixConfig>>);
get_caps(&self) -> Vec<Box<dyn PciCapability>>24     fn get_caps(&self) -> Vec<Box<dyn PciCapability>>;
set_capability_reg_idx(&mut self, id: PciCapabilityID, reg_idx: usize)25     fn set_capability_reg_idx(&mut self, id: PciCapabilityID, reg_idx: usize);
get_bus_range(&self) -> Option<PciBridgeBusRange>26     fn get_bus_range(&self) -> Option<PciBridgeBusRange> {
27         None
28     }
get_removed_devices(&self) -> Vec<PciAddress>29     fn get_removed_devices(&self) -> Vec<PciAddress>;
30 
31     /// Hotplug capability is implemented on this bridge or not.
32     /// Return true, the children pci devices could be connected through hotplug
33     /// Return false, the children pci devices should be connected statically
hotplug_implemented(&self) -> bool34     fn hotplug_implemented(&self) -> bool;
35 
36     /// Get bridge window size to cover children's mmio size
37     /// (u64, u64) -> (non_prefetchable window size, prefetchable_window_size)
get_bridge_window_size(&self) -> (u64, u64)38     fn get_bridge_window_size(&self) -> (u64, u64);
39 }
40 
41 #[repr(C)]
42 #[derive(Clone, Copy)]
43 pub struct PcieCap {
44     _cap_vndr: u8,
45     _cap_next: u8,
46     pcie_cap: u16,
47     dev_cap: u32,
48     dev_control: u16,
49     dev_status: u16,
50     link_cap: u32,
51     link_control: u16,
52     link_status: u16,
53     slot_cap: u32,
54     slot_control: u16,
55     slot_status: u16,
56     root_control: u16,
57     root_cap: u16,
58     root_status: u32,
59     dev_cap_2: u32,
60     dev_control_2: u16,
61     dev_status_2: u16,
62     link_cap_2: u32,
63     link_control_2: u16,
64     link_status_2: u16,
65     slot_cap_2: u32,
66     slot_control_2: u16,
67     slot_status_2: u16,
68 }
69 // It is safe to implement DataInit; all members are simple numbers and any value is valid.
70 unsafe impl DataInit for PcieCap {}
71 
72 impl PciCapability for PcieCap {
bytes(&self) -> &[u8]73     fn bytes(&self) -> &[u8] {
74         self.as_slice()
75     }
76 
id(&self) -> PciCapabilityID77     fn id(&self) -> PciCapabilityID {
78         PciCapabilityID::PciExpress
79     }
80 
writable_bits(&self) -> Vec<u32>81     fn writable_bits(&self) -> Vec<u32> {
82         vec![
83             0u32,
84             0,
85             0xf_ffff,
86             0,
87             0x3000_0fff,
88             0,
89             0x11f_1fff,
90             0x1f,
91             0,
92             0,
93             0,
94             0,
95             0,
96             0,
97             0,
98         ]
99     }
100 }
101 
102 impl PcieCap {
new(device_type: PcieDevicePortType, slot: bool, irq_num: u16) -> Self103     pub fn new(device_type: PcieDevicePortType, slot: bool, irq_num: u16) -> Self {
104         let mut pcie_cap = PCIE_CAP_VERSION;
105         pcie_cap |= (device_type as u16) << PCIE_TYPE_SHIFT;
106         if slot {
107             pcie_cap |= 1 << PCIE_CAP_SLOT_SHIFT;
108         }
109         pcie_cap |= irq_num << PCIE_CAP_IRQ_NUM_SHIFT;
110 
111         let dev_cap = PCIE_DEVCAP_RBER;
112         let link_cap = (PCIE_LINK_X1 | PCIE_LINK_2_5GT) as u32;
113         let link_status = PCIE_LINK_X1 | PCIE_LINK_2_5GT;
114 
115         let mut slot_cap: u32 = 0;
116         let mut slot_control: u16 = 0;
117         if slot {
118             slot_cap = PCIE_SLTCAP_ABP
119                 | PCIE_SLTCAP_AIP
120                 | PCIE_SLTCAP_PIP
121                 | PCIE_SLTCAP_HPS
122                 | PCIE_SLTCAP_HPC;
123             slot_control = PCIE_SLTCTL_PIC_OFF | PCIE_SLTCTL_AIC_OFF;
124         }
125 
126         PcieCap {
127             _cap_vndr: 0,
128             _cap_next: 0,
129             pcie_cap,
130             dev_cap,
131             dev_control: 0,
132             dev_status: 0,
133             link_cap,
134             link_control: 0,
135             link_status,
136             slot_cap,
137             slot_control,
138             slot_status: 0,
139             root_control: 0,
140             root_cap: 0,
141             root_status: 0,
142             dev_cap_2: 0,
143             dev_control_2: 0,
144             dev_status_2: 0,
145             link_cap_2: 0,
146             link_control_2: 0,
147             link_status_2: 0,
148             slot_cap_2: 0,
149             slot_control_2: 0,
150             slot_status_2: 0,
151         }
152     }
153 }
154 
155 #[repr(C)]
156 #[derive(Clone, Copy)]
157 pub struct PciPmcCap {
158     _cap_vndr: u8,
159     _cap_next: u8,
160     pmc_cap: u16,
161     pmc_control_status: u16,
162     padding: u16,
163 }
164 
165 // It is safe to implement DataInit; all members are simple numbers and any value is valid.
166 unsafe impl DataInit for PciPmcCap {}
167 
168 impl PciCapability for PciPmcCap {
bytes(&self) -> &[u8]169     fn bytes(&self) -> &[u8] {
170         self.as_slice()
171     }
172 
id(&self) -> PciCapabilityID173     fn id(&self) -> PciCapabilityID {
174         PciCapabilityID::PowerManagement
175     }
176 
writable_bits(&self) -> Vec<u32>177     fn writable_bits(&self) -> Vec<u32> {
178         vec![0u32, 0x8103]
179     }
180 }
181 
182 impl PciPmcCap {
new() -> Self183     pub fn new() -> Self {
184         let pmc_cap: u16 = PMC_CAP_PME_SUPPORT_D0
185             | PMC_CAP_PME_SUPPORT_D3_HOT
186             | PMC_CAP_PME_SUPPORT_D3_COLD
187             | PMC_CAP_VERSION;
188         PciPmcCap {
189             _cap_vndr: 0,
190             _cap_next: 0,
191             pmc_cap,
192             pmc_control_status: 0,
193             padding: 0,
194         }
195     }
196 }
197 
198 pub struct PmcConfig {
199     power_control_status: u16,
200 }
201 
202 impl PmcConfig {
new() -> Self203     pub fn new() -> Self {
204         PmcConfig {
205             power_control_status: 0,
206         }
207     }
208 
read(&self, data: &mut u32)209     pub fn read(&self, data: &mut u32) {
210         *data = self.power_control_status as u32;
211     }
212 
write(&mut self, offset: u64, data: &[u8])213     pub fn write(&mut self, offset: u64, data: &[u8]) {
214         if offset > 1 {
215             return;
216         }
217 
218         if offset == 0 {
219             self.power_control_status &= !PMC_POWER_STATE_MASK;
220             self.power_control_status |= data[0] as u16 & PMC_POWER_STATE_MASK;
221         }
222 
223         let write_data = if offset == 0 && (data.len() == 2 || data.len() == 4) {
224             Some((data[1] as u16) << 8)
225         } else if offset == 1 && data.len() == 1 {
226             Some((data[0] as u16) << 8)
227         } else {
228             None
229         };
230 
231         if let Some(write_data) = write_data {
232             if write_data & PMC_PME_STATUS != 0 {
233                 // clear PME_STATUS
234                 self.power_control_status &= !PMC_PME_STATUS;
235             }
236 
237             if write_data & PMC_PME_ENABLE != 0 {
238                 self.power_control_status |= PMC_PME_ENABLE;
239             } else {
240                 self.power_control_status &= !PMC_PME_ENABLE;
241             }
242         }
243     }
244 
245     /// If device is in D3 and PME is enabled, set PME status, then device could
246     /// inject a pme interrupt into guest
should_trigger_pme(&mut self) -> bool247     pub fn should_trigger_pme(&mut self) -> bool {
248         if self.power_control_status & PMC_POWER_STATE_MASK == PMC_POWER_STATE_D3
249             && self.power_control_status & PMC_PME_ENABLE != 0
250         {
251             self.power_control_status |= PMC_PME_STATUS;
252 
253             return true;
254         }
255 
256         false
257     }
258 
259     /// Get device power status
get_power_status(&self) -> PciDevicePower260     pub fn get_power_status(&self) -> PciDevicePower {
261         match self.power_control_status & PMC_POWER_STATE_MASK {
262             PMC_POWER_STATE_D0 => PciDevicePower::D0,
263             PMC_POWER_STATE_D3 => PciDevicePower::D3,
264             _ => PciDevicePower::Unsupported,
265         }
266     }
267 }
268