devices/pci/pcie/
pci_bridge.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::cmp::max;
6use std::cmp::min;
7use std::sync::Arc;
8
9use base::warn;
10use base::AsRawDescriptors;
11use base::RawDescriptor;
12use base::Tube;
13use resources::Alloc;
14use resources::AllocOptions;
15use resources::SystemAllocator;
16use sync::Mutex;
17
18use crate::pci::msi::MsiCap;
19use crate::pci::msi::MsiConfig;
20use crate::pci::pci_configuration::PciBridgeSubclass;
21use crate::pci::pcie::pcie_device::PcieDevice;
22use crate::pci::BarRange;
23use crate::pci::PciAddress;
24use crate::pci::PciBarConfiguration;
25use crate::pci::PciBarIndex;
26use crate::pci::PciBus;
27use crate::pci::PciClassCode;
28use crate::pci::PciConfiguration;
29use crate::pci::PciDevice;
30use crate::pci::PciDeviceError;
31use crate::pci::PciHeaderType;
32use crate::pci::PCI_VENDOR_ID_INTEL;
33use crate::IrqLevelEvent;
34use crate::PciInterruptPin;
35use crate::Suspendable;
36
37pub const BR_BUS_NUMBER_REG: usize = 0x6;
38pub const BR_BUS_SUBORDINATE_OFFSET: usize = 0x2;
39pub const BR_MEM_REG: usize = 0x8;
40// bit[15:4] is memory base[31:20] and alignment to 1MB
41pub const BR_MEM_BASE_MASK: u32 = 0xFFF0;
42pub const BR_MEM_BASE_SHIFT: u32 = 16;
43// bit[31:20] is memory limit[31:20] and alignment to 1MB
44pub const BR_MEM_LIMIT_MASK: u32 = 0xFFF0_0000;
45pub const BR_PREF_MEM_LOW_REG: usize = 0x9;
46// bit[0] and bit[16] is 64bit memory flag
47pub const BR_PREF_MEM_64BIT: u32 = 0x001_0001;
48pub const BR_PREF_MEM_BASE_HIGH_REG: usize = 0xa;
49pub const BR_PREF_MEM_LIMIT_HIGH_REG: usize = 0xb;
50pub const BR_WINDOW_ALIGNMENT: u64 = 0x10_0000;
51pub const BR_WINDOW_MASK: u64 = !(BR_WINDOW_ALIGNMENT - 1);
52// Kernel allocate at least 2MB mmio for each bridge memory window
53pub 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)]
61pub struct PciBridgeBusRange {
62    pub primary: u8,
63    pub secondary: u8,
64    pub subordinate: u8,
65}
66
67pub 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
77impl PciBridge {
78    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
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
177    pub fn get_secondary_num(&self) -> u8 {
178        self.bus_range.secondary
179    }
180
181    pub fn get_subordinate_num(&self) -> u8 {
182        self.bus_range.subordinate
183    }
184}
185
186fn 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: {e}"
214            ))),
215        }
216    } else {
217        // align base to 1MB
218        if base & (BR_WINDOW_ALIGNMENT - 1) != 0 {
219            size += base - (base & BR_WINDOW_MASK);
220            // align size to 1MB
221            if size & (BR_WINDOW_ALIGNMENT - 1) != 0 {
222                size = (size + BR_WINDOW_ALIGNMENT - 1) & BR_WINDOW_MASK;
223            }
224            base &= BR_WINDOW_MASK;
225        }
226        Ok((base, size))
227    }
228}
229
230impl PciDevice for PciBridge {
231    fn debug_label(&self) -> String {
232        self.device.lock().debug_label()
233    }
234
235    fn preferred_address(&self) -> Option<PciAddress> {
236        self.device.lock().preferred_address()
237    }
238
239    fn allocate_address(
240        &mut self,
241        resources: &mut SystemAllocator,
242    ) -> std::result::Result<PciAddress, PciDeviceError> {
243        let address = self.device.lock().allocate_address(resources)?;
244        self.pci_address = Some(address);
245        self.msi_config.lock().set_pci_address(address);
246        Ok(address)
247    }
248
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
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
266    fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
267        self.config.get_bar_configuration(bar_num)
268    }
269
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
281    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
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
330    fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
331
332    fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
333
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
342    fn get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>> {
343        Some(self.pci_bus.clone())
344    }
345
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
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
479    fn destroy_device(&mut self) {
480        self.msi_config.lock().destroy()
481    }
482}
483
484impl Suspendable for PciBridge {}