summary refs log tree commit diff stats
path: root/hw/vfio_pci.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-01-10 13:26:12 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2013-01-10 13:26:12 -0600
commit8757c09f15dcd455f81b4faed73da0d35d7e6b53 (patch)
tree25ef7614f321882ceef55e8bacd86e87d7cdab34 /hw/vfio_pci.c
parent5e3bc735d93dd23f074b5116fd11e1ad8cd4962f (diff)
parent8fc94e5a8046e349e07976f9bcaffbcd5833f3a2 (diff)
downloadfocaccia-qemu-8757c09f15dcd455f81b4faed73da0d35d7e6b53.tar.gz
focaccia-qemu-8757c09f15dcd455f81b4faed73da0d35d7e6b53.zip
Merge remote-tracking branch 'awilliam/tags/qemu-1.4-vfio-20130109.0' into staging
vfio-pci: Fixes for qemu 1.4 & stable

* awilliam/tags/qemu-1.4-vfio-20130109.0:
  vfio-pci: Loosen sanity checks to allow future features
  vfio-pci: Make host MSI-X enable track guest

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/vfio_pci.c')
-rw-r--r--hw/vfio_pci.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c
index 28c83031d0..c51ae6761b 100644
--- a/hw/vfio_pci.c
+++ b/hw/vfio_pci.c
@@ -562,8 +562,8 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
     return ret;
 }
 
-static int vfio_msix_vector_use(PCIDevice *pdev,
-                                unsigned int nr, MSIMessage msg)
+static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
+                                   MSIMessage *msg, IOHandler *handler)
 {
     VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
     VFIOMSIVector *vector;
@@ -587,7 +587,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
      * Attempt to enable route through KVM irqchip,
      * default to userspace handling if unavailable.
      */
-    vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg);
+    vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1;
     if (vector->virq < 0 ||
         kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
                                        vector->virq) < 0) {
@@ -596,7 +596,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
             vector->virq = -1;
         }
         qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                            vfio_msi_interrupt, NULL, vector);
+                            handler, NULL, vector);
     }
 
     /*
@@ -639,6 +639,12 @@ static int vfio_msix_vector_use(PCIDevice *pdev,
     return 0;
 }
 
+static int vfio_msix_vector_use(PCIDevice *pdev,
+                                unsigned int nr, MSIMessage msg)
+{
+    return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt);
+}
+
 static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
 {
     VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
@@ -697,6 +703,22 @@ static void vfio_enable_msix(VFIODevice *vdev)
 
     vdev->interrupt = VFIO_INT_MSIX;
 
+    /*
+     * Some communication channels between VF & PF or PF & fw rely on the
+     * physical state of the device and expect that enabling MSI-X from the
+     * guest enables the same on the host.  When our guest is Linux, the
+     * guest driver call to pci_enable_msix() sets the enabling bit in the
+     * MSI-X capability, but leaves the vector table masked.  We therefore
+     * can't rely on a vector_use callback (from request_irq() in the guest)
+     * to switch the physical device into MSI-X mode because that may come a
+     * long time after pci_enable_msix().  This code enables vector 0 with
+     * triggering to userspace, then immediately release the vector, leaving
+     * the physical device with no vectors enabled, but MSI-X enabled, just
+     * like the guest view.
+     */
+    vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL);
+    vfio_msix_vector_release(&vdev->pdev, 0);
+
     if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
                                   vfio_msix_vector_release, NULL)) {
         error_report("vfio: msix_set_vector_notifiers failed\n");
@@ -1815,13 +1837,13 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
         error_report("Warning, device %s does not support reset\n", name);
     }
 
-    if (dev_info.num_regions != VFIO_PCI_NUM_REGIONS) {
+    if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
         error_report("vfio: unexpected number of io regions %u\n",
                      dev_info.num_regions);
         goto error;
     }
 
-    if (dev_info.num_irqs != VFIO_PCI_NUM_IRQS) {
+    if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
         error_report("vfio: unexpected number of irqs %u\n", dev_info.num_irqs);
         goto error;
     }