diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2018-09-20 17:43:57 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-01 11:30:00 -0700 |
commit | 4f228cb2033b8e8bf94864574b37fe719b1a7930 (patch) | |
tree | ad0b9aa51e56ff66ce52c50d78cf4344dbcd42f8 | |
parent | 0f579cb09c7a2e9cf176c2a689a51ba440398957 (diff) | |
download | crosvm-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>
-rw-r--r-- | devices/src/pci/mod.rs | 2 | ||||
-rw-r--r-- | devices/src/pci/pci_configuration.rs | 52 | ||||
-rw-r--r-- | devices/src/pci/pci_root.rs | 1 |
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, |