summary refs log tree commit diff
path: root/devices
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2018-09-20 17:43:57 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-01 11:30:00 -0700
commit4f228cb2033b8e8bf94864574b37fe719b1a7930 (patch)
treead0b9aa51e56ff66ce52c50d78cf4344dbcd42f8 /devices
parent0f579cb09c7a2e9cf176c2a689a51ba440398957 (diff)
downloadcrosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar.gz
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar.bz2
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar.lz
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar.xz
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.tar.zst
crosvm-4f228cb2033b8e8bf94864574b37fe719b1a7930.zip
devices: pci: add Programming Interface to device
PCI class codes are made up of three fields: class, subclass, and
programming interface.  Some class/subclass combinations do not define
any programming interfaces, so add an optional parameter to specify the
value and use 0 if it is not provided.

Change-Id: Ib4000eafe2d7d003ed5753d7b0ea05e16fd06130
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1237358
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'devices')
-rw-r--r--devices/src/pci/mod.rs2
-rw-r--r--devices/src/pci/pci_configuration.rs52
-rw-r--r--devices/src/pci/pci_root.rs1
3 files changed, 53 insertions, 2 deletions
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index a1d211d..ce42d62 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -8,7 +8,7 @@ mod pci_configuration;
 mod pci_device;
 mod pci_root;
 
-pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciSubclass};
+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;
diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs
index 0030c5e..d5823ac 100644
--- a/devices/src/pci/pci_configuration.rs
+++ b/devices/src/pci/pci_configuration.rs
@@ -121,6 +121,15 @@ impl PciSubclass for PciSerialBusSubClass {
     }
 }
 
+/// A PCI class programming interface. Each combination of `PciClassCode` and
+/// `PciSubclass` can specify a set of register-level programming interfaces.
+/// This trait is implemented by each programming interface.
+/// It allows use of a trait object to generate configurations.
+pub trait PciProgrammingInterface {
+    /// Convert this programming interface to the value used in the PCI specification.
+    fn get_register_value(&self) -> u8;
+}
+
 /// Types of PCI capabilities.
 pub enum PciCapabilityID {
     ListID = 0,
@@ -169,14 +178,21 @@ impl PciConfiguration {
         device_id: u16,
         class_code: PciClassCode,
         subclass: &PciSubclass,
+        programming_interface: Option<&PciProgrammingInterface>,
         header_type: PciHeaderType,
         subsystem_vendor_id: u16,
         subsystem_id: u16,
     ) -> Self {
         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
+        let pi = if let Some(pi) = programming_interface {
+            pi.get_register_value()
+        } else {
+            0
+        };
         registers[2] = u32::from(class_code.get_register_value()) << 24
-            | u32::from(subclass.get_register_value()) << 16;
+            | u32::from(subclass.get_register_value()) << 16
+            | u32::from(pi) << 8;
         match header_type {
             PciHeaderType::Device => (),
             PciHeaderType::Bridge => registers[3] = 0x0001_0000,
@@ -364,6 +380,7 @@ mod tests {
             0x5678,
             PciClassCode::MultimediaController,
             &PciMultimediaSubclass::AudioController,
+            None,
             PciHeaderType::Device,
             0xABCD,
             0x2468,
@@ -395,4 +412,37 @@ mod tests {
         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
     }
+
+    #[derive(Copy, Clone)]
+    enum TestPI {
+        Test = 0x5a,
+    }
+
+    impl PciProgrammingInterface for TestPI {
+        fn get_register_value(&self) -> u8 {
+            *self as u8
+        }
+    }
+
+    #[test]
+    fn class_code() {
+        let cfg = PciConfiguration::new(
+            0x1234,
+            0x5678,
+            PciClassCode::MultimediaController,
+            &PciMultimediaSubclass::AudioController,
+            Some(&TestPI::Test),
+            PciHeaderType::Device,
+            0xABCD,
+            0x2468,
+        );
+
+        let class_reg = cfg.read_reg(2);
+        let class_code = (class_reg >> 24) & 0xFF;
+        let subclass = (class_reg >> 16) & 0xFF;
+        let prog_if = (class_reg >> 8) & 0xFF;
+        assert_eq!(class_code, 0x04);
+        assert_eq!(subclass, 0x01);
+        assert_eq!(prog_if, 0x5a);
+    }
 }
diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs
index 7988a9f..34e4f2a 100644
--- a/devices/src/pci/pci_root.rs
+++ b/devices/src/pci/pci_root.rs
@@ -52,6 +52,7 @@ impl PciRoot {
                             0,
                             PciClassCode::BridgeDevice,
                             &PciBridgeSubclass::HostBridge,
+                            None,
                             PciHeaderType::Bridge,
                             0,
                             0,