summary refs log tree commit diff
diff options
context:
space:
mode:
authorZide Chen <zide.chen@intel.corp-partner.google.com>2019-09-13 14:21:05 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-24 20:46:37 +0000
commit1d15851b275b72aa08d13ac7bde9dd8464cfeed0 (patch)
treecd2eaa677385f881b8bf472d16a8836e3e1b225d
parent1955fd1fb317841ecdf31666a5d88021670ae035 (diff)
downloadcrosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar.gz
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar.bz2
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar.lz
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar.xz
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.tar.zst
crosvm-1d15851b275b72aa08d13ac7bde9dd8464cfeed0.zip
devices: implement msix capability structure
The MSI-X feature is ported from Cloud-hypervisor commit 69e27288a2e.
(https://github.com/intel/cloud-hypervisor.git)

In this commit:

- add a new "msix" module to the pci crate.
- implement the MSI-X Capability Structure.
- implement per virtio device msix_vectors() function which represents the
  supported MSI-X vector for this device.

BUG=chromium:854765
TEST=launch Crosvm on eve and Linux
TEST=cargo test -p devices
TEST=./bin/clippy
TEST=./build_test.py --x86_64-sysroot /build/eve

Change-Id: I5498b15a3bf115e34764e6610407b3ba204dae7f
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
Signed-off-by: Zide Chen <zide.chen@intel.corp-partner.google.com>
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1873356
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
-rw-r--r--devices/src/pci/mod.rs2
-rw-r--r--devices/src/pci/msix.rs69
-rw-r--r--devices/src/virtio/virtio_device.rs5
-rw-r--r--devices/src/virtio/virtio_pci_device.rs26
4 files changed, 98 insertions, 4 deletions
diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs
index 5d44dfc..eee87a5 100644
--- a/devices/src/pci/mod.rs
+++ b/devices/src/pci/mod.rs
@@ -8,12 +8,14 @@ mod ac97;
 mod ac97_bus_master;
 mod ac97_mixer;
 mod ac97_regs;
+mod msix;
 mod pci_configuration;
 mod pci_device;
 mod pci_root;
 mod vfio_pci;
 
 pub use self::ac97::Ac97Dev;
+pub use self::msix::MsixCap;
 pub use self::pci_configuration::{
     PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityID,
     PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSerialBusSubClass,
diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs
new file mode 100644
index 0000000..55e71ba
--- /dev/null
+++ b/devices/src/pci/msix.rs
@@ -0,0 +1,69 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::pci::{PciCapability, PciCapabilityID};
+
+use data_model::DataInit;
+
+const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
+
+// It is safe to implement DataInit; all members are simple numbers and any value is valid.
+unsafe impl DataInit for MsixCap {}
+
+#[allow(dead_code)]
+#[repr(C)]
+#[derive(Clone, Copy, Default)]
+/// MSI-X Capability Structure
+pub struct MsixCap {
+    // To make add_capability() happy
+    _cap_vndr: u8,
+    _cap_next: u8,
+    // Message Control Register
+    //   10-0:  MSI-X Table size
+    //   13-11: Reserved
+    //   14:    Mask. Mask all MSI-X when set.
+    //   15:    Enable. Enable all MSI-X when set.
+    msg_ctl: u16,
+    // Table. Contains the offset and the BAR indicator (BIR)
+    //   2-0:  Table BAR indicator (BIR). Can be 0 to 5.
+    //   31-3: Table offset in the BAR pointed by the BIR.
+    table: u32,
+    // Pending Bit Array. Contains the offset and the BAR indicator (BIR)
+    //   2-0:  PBA BAR indicator (BIR). Can be 0 to 5.
+    //   31-3: PBA offset in the BAR pointed by the BIR.
+    pba: u32,
+}
+
+impl PciCapability for MsixCap {
+    fn bytes(&self) -> &[u8] {
+        self.as_slice()
+    }
+
+    fn id(&self) -> PciCapabilityID {
+        PciCapabilityID::MSIX
+    }
+}
+
+impl MsixCap {
+    pub fn new(
+        table_pci_bar: u8,
+        table_size: u16,
+        table_off: u32,
+        pba_pci_bar: u8,
+        pba_off: u32,
+    ) -> Self {
+        assert!(table_size < MAX_MSIX_VECTORS_PER_DEVICE);
+
+        // Set the table size and enable MSI-X.
+        let msg_ctl: u16 = 0x8000u16 + table_size - 1;
+
+        MsixCap {
+            _cap_vndr: 0,
+            _cap_next: 0,
+            msg_ctl,
+            table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8),
+            pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8),
+        }
+    }
+}
diff --git a/devices/src/virtio/virtio_device.rs b/devices/src/virtio/virtio_device.rs
index d024d33..fa80b48 100644
--- a/devices/src/virtio/virtio_device.rs
+++ b/devices/src/virtio/virtio_device.rs
@@ -34,6 +34,11 @@ pub trait VirtioDevice: Send {
     /// The virtio device type.
     fn device_type(&self) -> u32;
 
+    /// number of MSI-X vectors. 0 means MSI-X not supported.
+    fn msix_vectors(&self) -> u16 {
+        0
+    }
+
     /// The maximum size of each queue that this device supports.
     fn queue_max_sizes(&self) -> &[u16];
 
diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs
index f99b753..33b6a5e 100644
--- a/devices/src/virtio/virtio_pci_device.rs
+++ b/devices/src/virtio/virtio_pci_device.rs
@@ -14,8 +14,8 @@ use sys_util::{EventFd, GuestMemory, Result};
 
 use super::*;
 use crate::pci::{
-    PciBarConfiguration, PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice,
-    PciDeviceError, PciHeaderType, PciInterruptPin, PciSubclass,
+    MsixCap, PciBarConfiguration, PciCapability, PciCapabilityID, PciClassCode, PciConfiguration,
+    PciDevice, PciDeviceError, PciHeaderType, PciInterruptPin, PciSubclass,
 };
 
 use self::virtio_pci_common_config::VirtioPciCommonConfig;
@@ -136,7 +136,9 @@ const DEVICE_CONFIG_BAR_OFFSET: u64 = 0x2000;
 const DEVICE_CONFIG_SIZE: u64 = 0x1000;
 const NOTIFICATION_BAR_OFFSET: u64 = 0x3000;
 const NOTIFICATION_SIZE: u64 = 0x1000;
-const CAPABILITY_BAR_SIZE: u64 = 0x4000;
+const MSIX_TABLE_BAR_OFFSET: u64 = 0x6000;
+const MSIX_PBA_BAR_OFFSET: u64 = 0x7000;
+const CAPABILITY_BAR_SIZE: u64 = 0x8000;
 
 const NOTIFY_OFF_MULTIPLIER: u32 = 4; // A dword per notification address.
 
@@ -160,7 +162,7 @@ pub struct VirtioPciDevice {
     queue_evts: Vec<EventFd>,
     mem: Option<GuestMemory>,
     settings_bar: u8,
-
+    msix_cap_reg_idx: Option<usize>,
     common_config: VirtioPciCommonConfig,
 }
 
@@ -202,6 +204,7 @@ impl VirtioPciDevice {
             queue_evts,
             mem: Some(mem),
             settings_bar: 0,
+            msix_cap_reg_idx: None,
             common_config: VirtioPciCommonConfig {
                 driver_status: 0,
                 config_generation: 0,
@@ -292,6 +295,21 @@ impl VirtioPciDevice {
             .add_capability(&configuration_cap)
             .map_err(PciDeviceError::CapabilitiesSetup)?;
 
+        if self.device.msix_vectors() > 0 {
+            let msix_cap = MsixCap::new(
+                settings_bar,
+                self.device.msix_vectors(),
+                MSIX_TABLE_BAR_OFFSET as u32,
+                settings_bar,
+                MSIX_PBA_BAR_OFFSET as u32,
+            );
+            let msix_offset = self
+                .config_regs
+                .add_capability(&msix_cap)
+                .map_err(PciDeviceError::CapabilitiesSetup)?;
+            self.msix_cap_reg_idx = Some(msix_offset / 4);
+        }
+
         self.settings_bar = settings_bar;
         Ok(())
     }