summary refs log tree commit diff
path: root/devices/src/pci/vfio_pci.rs
diff options
context:
space:
mode:
authorXiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>2019-09-04 16:51:57 +0800
committerCommit Bot <commit-bot@chromium.org>2019-10-28 06:10:01 +0000
commitb19987d93f1f3498e5e1c949ae10dcb93233828b (patch)
tree278e0e55385dc2b9a74be18cb4fd087655605b25 /devices/src/pci/vfio_pci.rs
parentf9815ee26f4452b67ef6e79cf3a4c623851bb620 (diff)
downloadcrosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar.gz
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar.bz2
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar.lz
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar.xz
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.tar.zst
crosvm-b19987d93f1f3498e5e1c949ae10dcb93233828b.zip
vfio: Intx support
When hw reports it could support INTX, this patch enable it by passing
irqfd into vfio kernel.

Then once hw intx happens, the vfio kernel irq handler receives and
handles it, the handler will trigger irqfd and kvm injects the interrupt
into guest.

BUG=chromium:992270
TEST=None

Change-Id: I8b200174a91183b7324b0044fde13b44c751d4d7
Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1813457
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/pci/vfio_pci.rs')
-rw-r--r--devices/src/pci/vfio_pci.rs58
1 files changed, 53 insertions, 5 deletions
diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs
index 645ee19..af70aef 100644
--- a/devices/src/pci/vfio_pci.rs
+++ b/devices/src/pci/vfio_pci.rs
@@ -15,7 +15,9 @@ use vfio_sys::*;
 use crate::pci::pci_device::{Error as PciDeviceError, PciDevice};
 use crate::pci::PciInterruptPin;
 
-use crate::vfio::VfioDevice;
+use crate::vfio::{VfioDevice, VfioIrqType};
+
+const PCI_INTERRUPT_PIN: u32 = 0x3D;
 
 struct VfioPciConfig {
     device: Arc<VfioDevice>,
@@ -225,6 +227,7 @@ pub struct VfioPciDevice {
     mmio_regions: Vec<MmioInfo>,
     io_regions: Vec<IoInfo>,
     msi_cap: Option<VfioMsiCap>,
+    irq_type: Option<VfioIrqType>,
 }
 
 impl VfioPciDevice {
@@ -243,6 +246,7 @@ impl VfioPciDevice {
             mmio_regions: Vec::new(),
             io_regions: Vec::new(),
             msi_cap,
+            irq_type: None,
         }
     }
 
@@ -259,6 +263,45 @@ impl VfioPciDevice {
 
         None
     }
+
+    fn enable_intx(&mut self) {
+        if self.interrupt_evt.is_none() || self.interrupt_resample_evt.is_none() {
+            return;
+        }
+
+        if let Some(ref interrupt_evt) = self.interrupt_evt {
+            if let Err(e) = self.device.irq_enable(interrupt_evt, VfioIrqType::Intx) {
+                error!("Intx enable failed: {}", e);
+                return;
+            }
+            if let Some(ref irq_resample_evt) = self.interrupt_resample_evt {
+                if let Err(e) = self.device.irq_mask(VfioIrqType::Intx) {
+                    error!("Intx mask failed: {}", e);
+                    self.disable_intx();
+                    return;
+                }
+                if let Err(e) = self.device.resample_virq_enable(irq_resample_evt) {
+                    error!("resample enable failed: {}", e);
+                    self.disable_intx();
+                    return;
+                }
+                if let Err(e) = self.device.irq_unmask(VfioIrqType::Intx) {
+                    error!("Intx unmask failed: {}", e);
+                    self.disable_intx();
+                    return;
+                }
+            }
+        }
+
+        self.irq_type = Some(VfioIrqType::Intx);
+    }
+
+    fn disable_intx(&mut self) {
+        if let Err(e) = self.device.irq_disable(VfioIrqType::Intx) {
+            error!("Intx disable failed: {}", e);
+        }
+        self.irq_type = None;
+    }
 }
 
 impl PciDevice for VfioPciDevice {
@@ -286,12 +329,16 @@ impl PciDevice for VfioPciDevice {
         irq_evt: EventFd,
         irq_resample_evt: EventFd,
         irq_num: u32,
-        irq_pin: PciInterruptPin,
+        _irq_pin: PciInterruptPin,
     ) {
         self.config.write_config_byte(irq_num as u8, 0x3C);
-        self.config.write_config_byte(irq_pin as u8 + 1, 0x3D);
         self.interrupt_evt = Some(irq_evt);
         self.interrupt_resample_evt = Some(irq_resample_evt);
+
+        // enable INTX
+        if self.config.read_config_byte(PCI_INTERRUPT_PIN) > 0 {
+            self.enable_intx();
+        }
     }
 
     fn allocate_io_bars(
@@ -420,12 +467,13 @@ impl PciDevice for VfioPciDevice {
                 if let Some(ref interrupt_evt) = self.interrupt_evt {
                     match msi_cap.write_msi_reg(start, data) {
                         Some(VfioMsiChange::Enable) => {
-                            if let Err(e) = self.device.msi_enable(interrupt_evt) {
+                            if let Err(e) = self.device.irq_enable(interrupt_evt, VfioIrqType::Msi)
+                            {
                                 error!("{}", e);
                             }
                         }
                         Some(VfioMsiChange::Disable) => {
-                            if let Err(e) = self.device.msi_disable() {
+                            if let Err(e) = self.device.irq_disable(VfioIrqType::Msi) {
                                 error!("{}", e);
                             }
                         }