From 72007f016ae652dd8d3d2627eb99ce504915c98e Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 16 Jul 2019 17:19:21 -0700 Subject: [PATCH] pci: Improve MSI-X code to let VFIO rely on it This commit enhances the current msi-x code hosted in the pci crate in order to be reused by the vfio crate. Specifically, it creates several useful methods for the MsixCap structure that can simplify the caller's code. Signed-off-by: Sebastien Boeuf --- pci/src/lib.rs | 2 +- pci/src/msix.rs | 71 +++++++++++++++++++++------ vm-virtio/src/transport/pci_device.rs | 3 +- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/pci/src/lib.rs b/pci/src/lib.rs index f58cd8bda..e07c7f0ce 100644 --- a/pci/src/lib.rs +++ b/pci/src/lib.rs @@ -24,7 +24,7 @@ pub use self::configuration::{ pub use self::device::{ Error as PciDeviceError, InterruptDelivery, InterruptParameters, PciDevice, }; -pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry}; +pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE}; /// PCI has four interrupt pins A->D. #[derive(Copy, Clone)] diff --git a/pci/src/msix.rs b/pci/src/msix.rs index e29c8f195..f9abe5da3 100644 --- a/pci/src/msix.rs +++ b/pci/src/msix.rs @@ -18,6 +18,10 @@ const MSIX_TABLE_ENTRIES_MODULO: u64 = 16; const MSIX_PBA_ENTRIES_MODULO: u64 = 8; const BITS_PER_PBA_ENTRY: usize = 64; const FUNCTION_MASK_BIT: u8 = 14; +const MSIX_ENABLE_BIT: u8 = 15; +const FUNCTION_MASK_MASK: u16 = (1 << FUNCTION_MASK_BIT) as u16; +const MSIX_ENABLE_MASK: u16 = (1 << MSIX_ENABLE_BIT) as u16; +pub const MSIX_TABLE_ENTRY_SIZE: usize = 16; #[derive(Debug, Clone)] pub struct MsixTableEntry { @@ -28,8 +32,8 @@ pub struct MsixTableEntry { } impl MsixTableEntry { - pub fn is_masked(&self) -> bool { - self.vector_ctl == 1u32 + pub fn masked(&self) -> bool { + self.vector_ctl & 0x1 == 0x1 } } @@ -73,7 +77,7 @@ impl MsixConfig { self.interrupt_cb = Some(cb); } - pub fn is_masked(&self) -> bool { + pub fn masked(&self) -> bool { self.masked } @@ -88,14 +92,14 @@ impl MsixConfig { // masked. if old_masked && !self.masked { for (index, entry) in self.table_entries.clone().iter().enumerate() { - if !entry.is_masked() && self.get_pba_bit(index as u16) == 1 { + if !entry.masked() && self.get_pba_bit(index as u16) == 1 { self.inject_msix_and_clear_pba(index); } } } } - pub fn read_table(&mut self, offset: u64, data: &mut [u8]) { + pub fn read_table(&self, offset: u64, data: &mut [u8]) { assert!((data.len() == 4 || data.len() == 8)); let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize; @@ -196,9 +200,9 @@ impl MsixConfig { // device. if let Some(old_entry) = old_entry { // Check if bit has been flipped - if !self.is_masked() - && old_entry.is_masked() - && !self.table_entries[index].is_masked() + if !self.masked() + && old_entry.masked() + && !self.table_entries[index].masked() && self.get_pba_bit(index as u16) == 1 { self.inject_msix_and_clear_pba(index); @@ -297,15 +301,15 @@ pub struct MsixCap { // 13-11: Reserved // 14: Mask. Mask all MSI-X when set. // 15: Enable. Enable all MSI-X when set. - msg_ctl: u16, + pub 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, + pub 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, + pub pba: u32, } // It is safe to implement ByteValued. All members are simple numbers and any value is valid. @@ -322,7 +326,13 @@ impl PciCapability for MsixCap { } impl MsixCap { - pub fn new(pci_bar: u8, table_size: u16, table_off: u32, pba_off: u32) -> Self { + 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. @@ -330,8 +340,41 @@ impl MsixCap { MsixCap { msg_ctl, - table: (table_off & 0xffff_fff8u32) | u32::from(pci_bar & 0x7u8), - pba: (pba_off & 0xffff_fff8u32) | u32::from(pci_bar & 0x7u8), + table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8), + pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8), } } + + pub fn set_msg_ctl(&mut self, data: u16) { + self.msg_ctl = (self.msg_ctl & !(FUNCTION_MASK_MASK | MSIX_ENABLE_MASK)) + | (data & (FUNCTION_MASK_MASK | MSIX_ENABLE_MASK)); + } + + pub fn masked(&self) -> bool { + (self.msg_ctl >> FUNCTION_MASK_BIT) & 0x1 == 0x1 + } + + pub fn enabled(&self) -> bool { + (self.msg_ctl >> MSIX_ENABLE_BIT) & 0x1 == 0x1 + } + + pub fn table_offset(&self) -> u32 { + self.table >> 3 + } + + pub fn pba_offset(&self) -> u32 { + self.pba >> 3 + } + + pub fn table_bir(&self) -> u32 { + self.table & 0x7 + } + + pub fn pba_bir(&self) -> u32 { + self.pba & 0x7 + } + + pub fn table_size(&self) -> u16 { + (self.msg_ctl & 0x7ff) + 1 + } } diff --git a/vm-virtio/src/transport/pci_device.rs b/vm-virtio/src/transport/pci_device.rs index b22f7cef6..96d87732f 100755 --- a/vm-virtio/src/transport/pci_device.rs +++ b/vm-virtio/src/transport/pci_device.rs @@ -354,6 +354,7 @@ impl VirtioPciDevice { settings_bar, self.msix_num, MSIX_TABLE_BAR_OFFSET as u32, + settings_bar, MSIX_PBA_BAR_OFFSET as u32, ); self.configuration @@ -401,7 +402,7 @@ impl PciDevice for VirtioPciDevice { // device should not inject the interrupt. // Instead, the Pending Bit Array table is updated to reflect there // is a pending interrupt for this specific vector. - if config.is_masked() || entry.is_masked() { + if config.masked() || entry.masked() { config.set_pba_bit(queue.vector, false); return Ok(()); }