xref: /aosp_15_r20/external/crosvm/devices/src/pci/pcie/pci_bridge.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
5 use std::cmp::max;
6 use std::cmp::min;
7 use std::sync::Arc;
8 
9 use base::warn;
10 use base::AsRawDescriptors;
11 use base::RawDescriptor;
12 use base::Tube;
13 use resources::Alloc;
14 use resources::AllocOptions;
15 use resources::SystemAllocator;
16 use sync::Mutex;
17 
18 use crate::pci::msi::MsiCap;
19 use crate::pci::msi::MsiConfig;
20 use crate::pci::pci_configuration::PciBridgeSubclass;
21 use crate::pci::pcie::pcie_device::PcieDevice;
22 use crate::pci::BarRange;
23 use crate::pci::PciAddress;
24 use crate::pci::PciBarConfiguration;
25 use crate::pci::PciBarIndex;
26 use crate::pci::PciBus;
27 use crate::pci::PciClassCode;
28 use crate::pci::PciConfiguration;
29 use crate::pci::PciDevice;
30 use crate::pci::PciDeviceError;
31 use crate::pci::PciHeaderType;
32 use crate::pci::PCI_VENDOR_ID_INTEL;
33 use crate::IrqLevelEvent;
34 use crate::PciInterruptPin;
35 use crate::Suspendable;
36 
37 pub const BR_BUS_NUMBER_REG: usize = 0x6;
38 pub const BR_BUS_SUBORDINATE_OFFSET: usize = 0x2;
39 pub const BR_MEM_REG: usize = 0x8;
40 // bit[15:4] is memory base[31:20] and alignment to 1MB
41 pub const BR_MEM_BASE_MASK: u32 = 0xFFF0;
42 pub const BR_MEM_BASE_SHIFT: u32 = 16;
43 // bit[31:20] is memory limit[31:20] and alignment to 1MB
44 pub const BR_MEM_LIMIT_MASK: u32 = 0xFFF0_0000;
45 pub const BR_PREF_MEM_LOW_REG: usize = 0x9;
46 // bit[0] and bit[16] is 64bit memory flag
47 pub const BR_PREF_MEM_64BIT: u32 = 0x001_0001;
48 pub const BR_PREF_MEM_BASE_HIGH_REG: usize = 0xa;
49 pub const BR_PREF_MEM_LIMIT_HIGH_REG: usize = 0xb;
50 pub const BR_WINDOW_ALIGNMENT: u64 = 0x10_0000;
51 pub const BR_WINDOW_MASK: u64 = !(BR_WINDOW_ALIGNMENT - 1);
52 // Kernel allocate at least 2MB mmio for each bridge memory window
53 pub const BR_MEM_MINIMUM: u64 = 0x20_0000;
54 
55 /// Holds the bus range for a pci bridge
56 ///
57 /// * primary - primary bus number
58 /// * secondary - secondary bus number
59 /// * subordinate - subordinate bus number
60 #[derive(Debug, Copy, Clone)]
61 pub struct PciBridgeBusRange {
62     pub primary: u8,
63     pub secondary: u8,
64     pub subordinate: u8,
65 }
66 
67 pub struct PciBridge {
68     device: Arc<Mutex<dyn PcieDevice>>,
69     config: PciConfiguration,
70     pci_address: Option<PciAddress>,
71     pci_bus: Arc<Mutex<PciBus>>,
72     bus_range: PciBridgeBusRange,
73     msi_config: Arc<Mutex<MsiConfig>>,
74     interrupt_evt: Option<IrqLevelEvent>,
75 }
76 
77 impl PciBridge {
new(device: Arc<Mutex<dyn PcieDevice>>, msi_device_tube: Tube) -> Self78     pub fn new(device: Arc<Mutex<dyn PcieDevice>>, msi_device_tube: Tube) -> Self {
79         let device_id = device.lock().get_device_id();
80         let msi_config = Arc::new(Mutex::new(MsiConfig::new(
81             true,
82             false,
83             msi_device_tube,
84             (PCI_VENDOR_ID_INTEL as u32) | (device_id as u32) << 16,
85             device.lock().debug_label(),
86         )));
87 
88         let mut config = PciConfiguration::new(
89             PCI_VENDOR_ID_INTEL,
90             device_id,
91             PciClassCode::BridgeDevice,
92             &PciBridgeSubclass::PciToPciBridge,
93             None,
94             PciHeaderType::Bridge,
95             0,
96             0,
97             0,
98         );
99         let msi_cap = MsiCap::new(true, false);
100         config
101             .add_capability(&msi_cap, Some(Box::new(msi_config.clone())))
102             .map_err(PciDeviceError::CapabilitiesSetup)
103             .unwrap();
104         let bus_range = device
105             .lock()
106             .get_bus_range()
107             .expect("PciBridge's backend device must implement get_bus_range()");
108 
109         let data = [
110             bus_range.primary,
111             bus_range.secondary,
112             bus_range.subordinate,
113             0,
114         ];
115         config.write_reg(BR_BUS_NUMBER_REG, 0, &data[..]);
116         let pci_bus = Arc::new(Mutex::new(PciBus::new(
117             bus_range.secondary,
118             bus_range.primary,
119             device.lock().hotplug_implemented(),
120         )));
121 
122         PciBridge {
123             device,
124             config,
125             pci_address: None,
126             pci_bus,
127             bus_range,
128             msi_config,
129             interrupt_evt: None,
130         }
131     }
132 
write_bridge_window( &mut self, window_base: u32, window_size: u32, pref_window_base: u64, pref_window_size: u64, )133     fn write_bridge_window(
134         &mut self,
135         window_base: u32,
136         window_size: u32,
137         pref_window_base: u64,
138         pref_window_size: u64,
139     ) {
140         // both window_base and window_size should be aligned to 1M
141         if window_base & (BR_WINDOW_ALIGNMENT as u32 - 1) == 0
142             && window_size != 0
143             && window_size & (BR_WINDOW_ALIGNMENT as u32 - 1) == 0
144         {
145             // the top of memory will be one less than a 1MB boundary
146             let limit = window_base + window_size - BR_WINDOW_ALIGNMENT as u32;
147             let value = (window_base >> BR_MEM_BASE_SHIFT) | limit;
148             self.write_config_register(BR_MEM_REG, 0, &value.to_le_bytes());
149         }
150 
151         // both pref_window_base and pref_window_size should be aligned to 1M
152         if pref_window_base & (BR_WINDOW_ALIGNMENT - 1) == 0
153             && pref_window_size != 0
154             && pref_window_size & (BR_WINDOW_ALIGNMENT - 1) == 0
155         {
156             // the top of memory will be one less than a 1MB boundary
157             let limit = pref_window_base + pref_window_size - BR_WINDOW_ALIGNMENT;
158             let low_value = ((pref_window_base as u32) >> BR_MEM_BASE_SHIFT)
159                 | (limit as u32)
160                 | BR_PREF_MEM_64BIT;
161             self.write_config_register(BR_PREF_MEM_LOW_REG, 0, &low_value.to_le_bytes());
162             let high_base_value = (pref_window_base >> 32) as u32;
163             self.write_config_register(
164                 BR_PREF_MEM_BASE_HIGH_REG,
165                 0,
166                 &high_base_value.to_le_bytes(),
167             );
168             let high_top_value = (limit >> 32) as u32;
169             self.write_config_register(
170                 BR_PREF_MEM_LIMIT_HIGH_REG,
171                 0,
172                 &high_top_value.to_le_bytes(),
173             );
174         }
175     }
176 
get_secondary_num(&self) -> u8177     pub fn get_secondary_num(&self) -> u8 {
178         self.bus_range.secondary
179     }
180 
get_subordinate_num(&self) -> u8181     pub fn get_subordinate_num(&self) -> u8 {
182         self.bus_range.subordinate
183     }
184 }
185 
finalize_window( resources: &mut SystemAllocator, prefetchable: bool, alloc: Alloc, mut base: u64, mut size: u64, ) -> std::result::Result<(u64, u64), PciDeviceError>186 fn finalize_window(
187     resources: &mut SystemAllocator,
188     prefetchable: bool,
189     alloc: Alloc,
190     mut base: u64,
191     mut size: u64,
192 ) -> std::result::Result<(u64, u64), PciDeviceError> {
193     if size == 0 {
194         // Allocate at least 2MB bridge winodw
195         size = BR_MEM_MINIMUM;
196     }
197     // if base isn't set, allocate a new one
198     if base == u64::MAX {
199         // align size to 1MB
200         if size & (BR_WINDOW_ALIGNMENT - 1) != 0 {
201             size = (size + BR_WINDOW_ALIGNMENT - 1) & BR_WINDOW_MASK;
202         }
203         match resources.allocate_mmio(
204             size,
205             alloc,
206             "pci_bridge_window".to_string(),
207             AllocOptions::new()
208                 .prefetchable(prefetchable)
209                 .align(BR_WINDOW_ALIGNMENT),
210         ) {
211             Ok(addr) => Ok((addr, size)),
212             Err(e) => Err(PciDeviceError::PciBusWindowAllocationFailure(format!(
213                 "failed to allocate bridge window: {}",
214                 e
215             ))),
216         }
217     } else {
218         // align base to 1MB
219         if base & (BR_WINDOW_ALIGNMENT - 1) != 0 {
220             size += base - (base & BR_WINDOW_MASK);
221             // align size to 1MB
222             if size & (BR_WINDOW_ALIGNMENT - 1) != 0 {
223                 size = (size + BR_WINDOW_ALIGNMENT - 1) & BR_WINDOW_MASK;
224             }
225             base &= BR_WINDOW_MASK;
226         }
227         Ok((base, size))
228     }
229 }
230 
231 impl PciDevice for PciBridge {
debug_label(&self) -> String232     fn debug_label(&self) -> String {
233         self.device.lock().debug_label()
234     }
235 
preferred_address(&self) -> Option<PciAddress>236     fn preferred_address(&self) -> Option<PciAddress> {
237         self.device.lock().preferred_address()
238     }
239 
allocate_address( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<PciAddress, PciDeviceError>240     fn allocate_address(
241         &mut self,
242         resources: &mut SystemAllocator,
243     ) -> std::result::Result<PciAddress, PciDeviceError> {
244         let address = self.device.lock().allocate_address(resources)?;
245         self.pci_address = Some(address);
246         Ok(address)
247     }
248 
keep_rds(&self) -> Vec<RawDescriptor>249     fn keep_rds(&self) -> Vec<RawDescriptor> {
250         let mut rds = Vec::new();
251         if let Some(interrupt_evt) = &self.interrupt_evt {
252             rds.extend(interrupt_evt.as_raw_descriptors());
253         }
254         let descriptor = self.msi_config.lock().get_msi_socket();
255         rds.push(descriptor);
256         rds
257     }
258 
assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32)259     fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
260         self.interrupt_evt = Some(irq_evt);
261         let msi_config_clone = self.msi_config.clone();
262         self.device.lock().clone_interrupt(msi_config_clone);
263         self.config.set_irq(irq_num as u8, pin);
264     }
265 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>266     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
267         self.config.get_bar_configuration(bar_num)
268     }
269 
register_device_capabilities(&mut self) -> std::result::Result<(), PciDeviceError>270     fn register_device_capabilities(&mut self) -> std::result::Result<(), PciDeviceError> {
271         let caps = self.device.lock().get_caps();
272         for (cap, cfg) in caps {
273             self.config
274                 .add_capability(&*cap, cfg)
275                 .map_err(PciDeviceError::CapabilitiesSetup)?;
276         }
277 
278         Ok(())
279     }
280 
read_config_register(&self, reg_idx: usize) -> u32281     fn read_config_register(&self, reg_idx: usize) -> u32 {
282         let mut data: u32 = self.config.read_reg(reg_idx);
283         self.device.lock().read_config(reg_idx, &mut data);
284         data
285     }
286 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])287     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
288         // Suppose kernel won't modify primary/secondary/subordinate bus number,
289         // if it indeed modify, print a warning
290         if reg_idx == BR_BUS_NUMBER_REG {
291             let len = data.len();
292             if offset == 0 && len == 1 && data[0] != self.bus_range.primary {
293                 warn!(
294                     "kernel modify primary bus number: {} -> {}",
295                     self.bus_range.primary, data[0]
296                 );
297             } else if offset == 0 && len == 2 {
298                 if data[0] != self.bus_range.primary {
299                     warn!(
300                         "kernel modify primary bus number: {} -> {}",
301                         self.bus_range.primary, data[0]
302                     );
303                 }
304                 if data[1] != self.bus_range.secondary {
305                     warn!(
306                         "kernel modify secondary bus number: {} -> {}",
307                         self.bus_range.secondary, data[1]
308                     );
309                 }
310             } else if offset == 1 && len == 1 && data[0] != self.bus_range.secondary {
311                 warn!(
312                     "kernel modify secondary bus number: {} -> {}",
313                     self.bus_range.secondary, data[0]
314                 );
315             } else if offset == 2 && len == 1 && data[0] != self.bus_range.subordinate {
316                 warn!(
317                     "kernel modify subordinate bus number: {} -> {}",
318                     self.bus_range.subordinate, data[0]
319                 );
320             }
321         }
322 
323         self.device.lock().write_config(reg_idx, offset, data);
324 
325         if let Some(res) = self.config.write_reg(reg_idx, offset, data) {
326             self.device.lock().handle_cap_write_result(res);
327         }
328     }
329 
read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])330     fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
331 
write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])332     fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
333 
get_removed_children_devices(&self) -> Vec<PciAddress>334     fn get_removed_children_devices(&self) -> Vec<PciAddress> {
335         if !self.device.lock().get_removed_devices().is_empty() {
336             self.pci_bus.lock().get_downstream_devices()
337         } else {
338             Vec::new()
339         }
340     }
341 
get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>>342     fn get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>> {
343         Some(self.pci_bus.clone())
344     }
345 
configure_bridge_window( &mut self, resources: &mut SystemAllocator, bar_ranges: &[BarRange], ) -> std::result::Result<Vec<BarRange>, PciDeviceError>346     fn configure_bridge_window(
347         &mut self,
348         resources: &mut SystemAllocator,
349         bar_ranges: &[BarRange],
350     ) -> std::result::Result<Vec<BarRange>, PciDeviceError> {
351         let address = self
352             .pci_address
353             .expect("allocate_address must be called prior to configure_bridge_window");
354         let mut window_base: u64 = u64::MAX;
355         let mut window_size: u64 = 0;
356         let mut pref_window_base: u64 = u64::MAX;
357         let mut pref_window_size: u64 = 0;
358         let hotplug_implemented = self.device.lock().hotplug_implemented();
359         let hotplugged = self.device.lock().hotplugged();
360 
361         if hotplug_implemented || hotplugged {
362             // If bridge is for children hotplug, get desired bridge window size and reserve
363             // it for guest OS use.
364             // If bridge is hotplugged into the system, get the desired bridge window size
365             // from host.
366             let (win_size, pref_win_size) = self.device.lock().get_bridge_window_size();
367             window_size = win_size;
368             pref_window_size = pref_win_size;
369         } else {
370             // Bridge has children connected, get bridge window size from children
371             let mut window_end: u64 = 0;
372             let mut pref_window_end: u64 = 0;
373 
374             for &BarRange {
375                 addr,
376                 size,
377                 prefetchable,
378             } in bar_ranges.iter()
379             {
380                 if prefetchable {
381                     pref_window_base = min(pref_window_base, addr);
382                     pref_window_end = max(pref_window_end, addr + size);
383                 } else {
384                     window_base = min(window_base, addr);
385                     window_end = max(window_end, addr + size);
386                 }
387             }
388             if window_end > 0 {
389                 window_size = window_end - window_base;
390             }
391             if pref_window_end > 0 {
392                 pref_window_size = pref_window_end - pref_window_base;
393             }
394         }
395 
396         if !hotplugged {
397             // Only static bridge needs to locate their window's position. Hotplugged bridge's
398             // window will be handled by guest kernel.
399             let window = finalize_window(
400                 resources,
401                 false, // prefetchable
402                 Alloc::PciBridgeWindow {
403                     bus: address.bus,
404                     dev: address.dev,
405                     func: address.func,
406                 },
407                 window_base,
408                 window_size,
409             )?;
410             window_base = window.0;
411             window_size = window.1;
412 
413             match finalize_window(
414                 resources,
415                 true, // prefetchable
416                 Alloc::PciBridgePrefetchWindow {
417                     bus: address.bus,
418                     dev: address.dev,
419                     func: address.func,
420                 },
421                 pref_window_base,
422                 pref_window_size,
423             ) {
424                 Ok(pref_window) => {
425                     pref_window_base = pref_window.0;
426                     pref_window_size = pref_window.1;
427                 }
428                 Err(e) => {
429                     warn!("failed to allocate PCI bridge prefetchable window: {}", e);
430                 }
431             }
432         } else {
433             // 0 is Ok here because guest will relocate the bridge window
434             if window_size > 0 {
435                 window_base = 0;
436             }
437             if pref_window_size > 0 {
438                 pref_window_base = 0;
439             }
440         }
441 
442         self.write_bridge_window(
443             window_base as u32,
444             window_size as u32,
445             pref_window_base,
446             pref_window_size,
447         );
448 
449         let mut windows = Vec::new();
450         if window_size > 0 {
451             windows.push(BarRange {
452                 addr: window_base,
453                 size: window_size,
454                 prefetchable: false,
455             })
456         }
457         if pref_window_size > 0 {
458             windows.push(BarRange {
459                 addr: pref_window_base,
460                 size: pref_window_size,
461                 prefetchable: true,
462             })
463         }
464         Ok(windows)
465     }
466 
set_subordinate_bus(&mut self, bus_no: u8)467     fn set_subordinate_bus(&mut self, bus_no: u8) {
468         let bus_reg = self.read_config_register(BR_BUS_NUMBER_REG);
469         // Keep the maxmium bus number here because this bridge could have reserved
470         // subordinate bus number earlier
471         let subordinate_bus = u8::max((bus_reg >> (BR_BUS_SUBORDINATE_OFFSET * 8)) as u8, bus_no);
472         self.write_config_register(
473             BR_BUS_NUMBER_REG,
474             BR_BUS_SUBORDINATE_OFFSET as u64,
475             &[subordinate_bus],
476         );
477     }
478 
destroy_device(&mut self)479     fn destroy_device(&mut self) {
480         self.msi_config.lock().destroy()
481     }
482 }
483 
484 impl Suspendable for PciBridge {}
485