summary refs log tree commit diff
path: root/devices/src
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2018-09-24 13:15:29 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-01 11:30:03 -0700
commit28a671a95f4927eda528c355f558aab64c7d7cf2 (patch)
tree0a1d7f9c4a4f5b4f8ddc5bc59dcb55f63ba84a83 /devices/src
parentaee0ac2d67bb669fecfae56403bfd7352d2a4d0c (diff)
downloadcrosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar.gz
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar.bz2
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar.lz
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar.xz
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.tar.zst
crosvm-28a671a95f4927eda528c355f558aab64c7d7cf2.zip
devices: pci: refactor config access mechanism
The current PciRoot is only workable for the legacy I/O port 0xCF8
access mechanism; factor out the config access mechanism part of PciRoot
into PciConfigIo so that we can add a MMIO-based access mechanism for
ARM.

Change-Id: I87756b0ab31070d8717c76d419957bf5ea5d75ad
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1241539
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'devices/src')
-rw-r--r--devices/src/lib.rs2
-rw-r--r--devices/src/pci/mod.rs2
-rw-r--r--devices/src/pci/pci_root.rs79
3 files changed, 65 insertions, 18 deletions
diff --git a/devices/src/lib.rs b/devices/src/lib.rs
index 46664fc..912cd85 100644
--- a/devices/src/lib.rs
+++ b/devices/src/lib.rs
@@ -32,7 +32,7 @@ pub use self::bus::Error as BusError;
 pub use self::cmos::Cmos;
 pub use self::pl030::Pl030;
 pub use self::i8042::I8042Device;
-pub use self::pci::{PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
+pub use self::pci::{PciConfigIo, PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
 pub use self::proxy::ProxyDevice;
 pub use self::proxy::Error as ProxyError;
 pub use self::serial::Serial;
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index ce42d62..a0393d3 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -11,7 +11,7 @@ mod pci_root;
 pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSubclass};
 pub use self::pci_device::Error as PciDeviceError;
 pub use self::pci_device::PciDevice;
-pub use self::pci_root::PciRoot;
+pub use self::pci_root::{PciConfigIo, PciRoot};
 
 /// PCI has four interrupt pins A->D.
 #[derive(Copy, Clone)]
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index c500f71..b47094b 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.rs
@@ -40,8 +40,6 @@ impl PciDevice for PciRootConfiguration {
 pub struct PciRoot {
     /// Bus configuration for the root device.
     root_configuration: PciRootConfiguration,
-    /// Current address to read/write from (0xcf8 register, litte endian).
-    config_address: u32,
     /// Devices attached to this bridge.
     devices: Vec<Arc<Mutex<ProxyDevice>>>,
 }
@@ -62,7 +60,6 @@ impl PciRoot {
                             0,
                             ),
             },
-            config_address: 0,
             devices: Vec::new(),
         }
     }
@@ -72,11 +69,15 @@ impl PciRoot {
         self.devices.push(device);
     }
 
-    fn config_space_read(&self) -> u32 {
-        let (enabled, bus, device, _, register) = parse_config_address(self.config_address);
-
+    pub fn config_space_read(
+        &self,
+        bus: usize,
+        device: usize,
+        _function: usize,
+        register: usize,
+    ) -> u32 {
         // Only support one bus.
-        if !enabled || bus != 0 {
+        if bus != 0 {
             return 0xffff_ffff;
         }
 
@@ -94,15 +95,21 @@ impl PciRoot {
         }
     }
 
-    fn config_space_write(&mut self, offset: u64, data: &[u8]) {
+    pub fn config_space_write(
+        &mut self,
+        bus: usize,
+        device: usize,
+        _function: usize,
+        register: usize,
+        offset: u64,
+        data: &[u8],
+    ) {
         if offset as usize + data.len() > 4 {
             return;
         }
 
-        let (enabled, bus, device, _, register) = parse_config_address(self.config_address);
-
         // Only support one bus.
-        if !enabled || bus != 0 {
+        if bus != 0 {
             return;
         }
 
@@ -120,6 +127,48 @@ impl PciRoot {
         }
     }
 
+}
+
+/// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
+pub struct PciConfigIo {
+    /// PCI root bridge.
+    pci_root: PciRoot,
+    /// Current address to read/write from (0xcf8 register, litte endian).
+    config_address: u32,
+}
+
+impl PciConfigIo {
+    pub fn new(pci_root: PciRoot) -> Self {
+        PciConfigIo {
+            pci_root,
+            config_address: 0,
+        }
+    }
+
+    fn config_space_read(&self) -> u32 {
+        let enabled = (self.config_address & 0x8000_0000) != 0;
+        if !enabled {
+            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)
+    }
+
+    fn config_space_write(&mut self, offset: u64, data: &[u8]) {
+        let enabled = (self.config_address & 0x8000_0000) != 0;
+        if !enabled {
+            return;
+        }
+
+        let (bus, device, function, register) =
+            parse_config_address(self.config_address & !0x8000_0000);
+        self.pci_root
+            .config_space_write(bus, device, function, register, offset, data)
+    }
+
     fn set_config_address(&mut self, offset: u64, data: &[u8]) {
         if offset as usize + data.len() > 4 {
             return;
@@ -140,7 +189,7 @@ impl PciRoot {
     }
 }
 
-impl BusDevice for PciRoot {
+impl BusDevice for PciConfigIo {
     fn read(&mut self, offset: u64, data: &mut [u8]) {
         // `offset` is relative to 0xcf8
         let value = match offset {
@@ -173,8 +222,8 @@ impl BusDevice for PciRoot {
     }
 }
 
-// Parse the CONFIG_ADDRESS register to a (enabled, bus, device, function, register) tuple.
-fn parse_config_address(config_address: u32) -> (bool, usize, usize, usize, usize) {
+// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
+fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
     const BUS_NUMBER_OFFSET: usize = 16;
     const BUS_NUMBER_MASK: u32 = 0x00ff;
     const DEVICE_NUMBER_OFFSET: usize = 11;
@@ -184,7 +233,6 @@ fn parse_config_address(config_address: u32) -> (bool, usize, usize, usize, usiz
     const REGISTER_NUMBER_OFFSET: usize = 2;
     const REGISTER_NUMBER_MASK: u32 = 0x3f;
 
-    let enabled = (config_address & 0x8000_0000) != 0;
     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 =
@@ -193,7 +241,6 @@ fn parse_config_address(config_address: u32) -> (bool, usize, usize, usize, usiz
         ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;
 
     (
-        enabled,
         bus_number,
         device_number,
         function_number,