From 1d15851b275b72aa08d13ac7bde9dd8464cfeed0 Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Fri, 13 Sep 2019 14:21:05 -0700 Subject: 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 Signed-off-by: Zide Chen Signed-off-by: Sainath Grandhi Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1873356 Reviewed-by: Daniel Verkamp Tested-by: kokoro Commit-Queue: Stephen Barber --- devices/src/pci/mod.rs | 2 + devices/src/pci/msix.rs | 69 +++++++++++++++++++++++++++++++++ devices/src/virtio/virtio_device.rs | 5 +++ devices/src/virtio/virtio_pci_device.rs | 26 +++++++++++-- 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 devices/src/pci/msix.rs 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, mem: Option, settings_bar: u8, - + msix_cap_reg_idx: Option, 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(()) } -- cgit 1.4.1