diff options
author | Tomasz Jeznach <tjeznach@chromium.org> | 2020-04-27 18:51:43 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-04-29 17:35:07 +0000 |
commit | d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa (patch) | |
tree | 312695c67cf658951dd28d1bd8ed8d0e1566f52f /devices/src/pci | |
parent | 2d9dde9ee7ac78a9831d1e019e40107b5691f895 (diff) | |
download | crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar.gz crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar.bz2 crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar.lz crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar.xz crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.tar.zst crosvm-d4cc9108cfd6fe996ffe3534e5f5adbbac7dfdfa.zip |
devices: pci: refactor device location address.
Simple refactor of PCI device addressing to use bus:device:function notation, including change allowing sparse alloction of device addresses in PCI topology. BUG=None TEST=build_test && cargo test Change-Id: I9ff02dd6b67b6784eac8c3d348661789fca3f422 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2171037 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Tomasz Jeznach <tjeznach@chromium.org> Commit-Queue: Tomasz Jeznach <tjeznach@chromium.org>
Diffstat (limited to 'devices/src/pci')
-rw-r--r-- | devices/src/pci/mod.rs | 2 | ||||
-rw-r--r-- | devices/src/pci/pci_root.rs | 127 |
2 files changed, 64 insertions, 65 deletions
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index b9ebc19..0edc3b2 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -23,7 +23,7 @@ pub use self::pci_configuration::{ }; pub use self::pci_device::Error as PciDeviceError; pub use self::pci_device::PciDevice; -pub use self::pci_root::{PciConfigIo, PciConfigMmio, PciRoot}; +pub use self::pci_root::{PciAddress, PciConfigIo, PciConfigMmio, PciRoot}; pub use self::vfio_pci::VfioPciDevice; /// PCI has four interrupt pins A->D. diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs index eef642e..4f0e453 100644 --- a/devices/src/pci/pci_root.rs +++ b/devices/src/pci/pci_root.rs @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use std::collections::BTreeMap; use std::convert::TryInto; +use std::fmt::{self, Display}; use std::os::unix::io::RawFd; use std::sync::Arc; @@ -39,12 +41,40 @@ impl PciDevice for PciRootConfiguration { fn write_bar(&mut self, _addr: u64, _data: &[u8]) {} } +/// PCI Device Address, AKA Bus:Device.Function +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct PciAddress { + pub bus: u8, + pub dev: u8, /* u5 */ + pub func: u8, /* u3 */ +} + +impl Display for PciAddress { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:04x}:{:02x}.{:0x}", self.bus, self.dev, self.func) + } +} + +impl PciAddress { + /// Returns true if the address points to PCI root host-bridge. + fn is_root(&self) -> bool { + matches!( + &self, + PciAddress { + bus: 0, + dev: 0, + func: 0 + } + ) + } +} + /// Emulates the PCI Root bridge. pub struct PciRoot { /// Bus configuration for the root device. root_configuration: PciRootConfiguration, /// Devices attached to this bridge. - devices: Vec<Arc<Mutex<dyn BusDevice>>>, + devices: BTreeMap<PciAddress, Arc<Mutex<dyn BusDevice>>>, } const PCI_VENDOR_ID_INTEL: u16 = 0x8086; @@ -66,44 +96,31 @@ impl PciRoot { 0, ), }, - devices: Vec::new(), + devices: BTreeMap::new(), } } /// Add a `device` to this root PCI bus. - pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) { - self.devices.push(device); - } - - pub fn config_space_read( - &self, - bus: usize, - device: usize, - _function: usize, - register: usize, - ) -> u32 { - // Only support one bus. - if bus != 0 { - return 0xffff_ffff; + pub fn add_device(&mut self, address: PciAddress, device: Arc<Mutex<dyn BusDevice>>) { + // Ignore attempt to replace PCI Root host bridge. + if !address.is_root() { + self.devices.insert(address, device); } + } - match device { - 0 => { - // If bus and device are both zero, then read from the root config. - self.root_configuration.config_register_read(register) - } - dev_num => self - .devices - .get(dev_num - 1) - .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)), + pub fn config_space_read(&self, address: PciAddress, register: usize) -> u32 { + if address.is_root() { + self.root_configuration.config_register_read(register) + } else { + self.devices + .get(&address) + .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)) } } pub fn config_space_write( &mut self, - bus: usize, - device: usize, - _function: usize, + address: PciAddress, register: usize, offset: u64, data: &[u8], @@ -111,24 +128,11 @@ impl PciRoot { if offset as usize + data.len() > 4 { return; } - - // Only support one bus. - if bus != 0 { - return; - } - - match device { - 0 => { - // If bus and device are both zero, then read from the root config. - self.root_configuration - .config_register_write(register, offset, data); - } - dev_num => { - // dev_num is 1-indexed here. - if let Some(d) = self.devices.get(dev_num - 1) { - d.lock().config_register_write(register, offset, data); - } - } + if address.is_root() { + self.root_configuration + .config_register_write(register, offset, data); + } else if let Some(d) = self.devices.get(&address) { + d.lock().config_register_write(register, offset, data); } } } @@ -155,10 +159,8 @@ impl PciConfigIo { return 0xffff_ffff; } - let (bus, device, function, register) = - parse_config_address(self.config_address & !0x8000_0000); - self.pci_root - .config_space_read(bus, device, function, register) + let (address, register) = parse_config_address(self.config_address & !0x8000_0000); + self.pci_root.config_space_read(address, register) } fn config_space_write(&mut self, offset: u64, data: &[u8]) { @@ -167,10 +169,9 @@ impl PciConfigIo { return; } - let (bus, device, function, register) = - parse_config_address(self.config_address & !0x8000_0000); + let (address, register) = parse_config_address(self.config_address & !0x8000_0000); self.pci_root - .config_space_write(bus, device, function, register, offset, data) + .config_space_write(address, register, offset, data) } fn set_config_address(&mut self, offset: u64, data: &[u8]) { @@ -242,15 +243,14 @@ impl PciConfigMmio { } fn config_space_read(&self, config_address: u32) -> u32 { - let (bus, device, function, register) = parse_config_address(config_address); - self.pci_root - .config_space_read(bus, device, function, register) + let (address, register) = parse_config_address(config_address); + self.pci_root.config_space_read(address, register) } fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) { - let (bus, device, function, register) = parse_config_address(config_address); + let (address, register) = parse_config_address(config_address); self.pci_root - .config_space_write(bus, device, function, register, offset, data) + .config_space_write(address, register, offset, data) } } @@ -285,7 +285,7 @@ impl BusDevice for PciConfigMmio { } // Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple. -fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) { +fn parse_config_address(config_address: u32) -> (PciAddress, usize) { const BUS_NUMBER_OFFSET: usize = 16; const BUS_NUMBER_MASK: u32 = 0x00ff; const DEVICE_NUMBER_OFFSET: usize = 11; @@ -295,12 +295,11 @@ fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) { const REGISTER_NUMBER_OFFSET: usize = 2; const REGISTER_NUMBER_MASK: u32 = 0x3f; - let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize; - let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize; - let function_number = - ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize; + let bus = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as u8; + let dev = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as u8; + let func = ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as u8; let register_number = ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize; - (bus_number, device_number, function_number, register_number) + (PciAddress { bus, dev, func }, register_number) } |