9ae3a8
From 6f572c45ff2c2376a16cd15882067d7fdcd74a83 Mon Sep 17 00:00:00 2001
9ae3a8
From: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Date: Tue, 5 Nov 2013 15:30:40 +0100
9ae3a8
Subject: [PATCH 12/25] vfio-pci: Add support for MSI affinity
9ae3a8
MIME-Version: 1.0
9ae3a8
Content-Type: text/plain; charset=UTF-8
9ae3a8
Content-Transfer-Encoding: 8bit
9ae3a8
9ae3a8
RH-Author: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Message-id: <20131105153040.15749.78283.stgit@bling.home>
9ae3a8
Patchwork-id: 55413
9ae3a8
O-Subject: [RHEL7 qemu-kvm PATCH v2 2/2] vfio-pci: Add support for MSI affinity
9ae3a8
Bugzilla: 1025477
9ae3a8
RH-Acked-by: Bandan Das <bsd@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
9ae3a8
9ae3a8
Bugzilla: 1025477
9ae3a8
Upstream commit: c7679d450ee021eb0826be65e4e018884443643a
9ae3a8
9ae3a8
When MSI is accelerated through KVM the vectors are only programmed
9ae3a8
when the guest first enables MSI support.  Subsequent writes to the
9ae3a8
vector address or data fields are ignored.  Unfortunately that means
9ae3a8
we're ignore updates done to adjust SMP affinity of the vectors.
9ae3a8
MSI SMP affinity already works in non-KVM mode because the address
9ae3a8
and data fields are read from their backing store on each interrupt.
9ae3a8
9ae3a8
This patch stores the MSIMessage programmed into KVM so that we can
9ae3a8
determine when changes are made and update the routes.
9ae3a8
9ae3a8
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c |   47 ++++++++++++++++++++++++++++++++++++++++-------
9ae3a8
 1 file changed, 40 insertions(+), 7 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c |   47 ++++++++++++++++++++++++++++++++++++++++-------
9ae3a8
 1 files changed, 40 insertions(+), 7 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
9ae3a8
index a072fd9..286dad1 100644
9ae3a8
--- a/hw/misc/vfio.c
9ae3a8
+++ b/hw/misc/vfio.c
9ae3a8
@@ -119,6 +119,7 @@ typedef struct VFIOINTx {
9ae3a8
 typedef struct VFIOMSIVector {
9ae3a8
     EventNotifier interrupt; /* eventfd triggered on interrupt */
9ae3a8
     struct VFIODevice *vdev; /* back pointer to device */
9ae3a8
+    MSIMessage msg; /* cache the MSI message so we know when it changes */
9ae3a8
     int virq; /* KVM irqchip route for QEMU bypass */
9ae3a8
     bool use;
9ae3a8
 } VFIOMSIVector;
9ae3a8
@@ -795,7 +796,6 @@ retry:
9ae3a8
     vdev->msi_vectors = g_malloc0(vdev->nr_vectors * sizeof(VFIOMSIVector));
9ae3a8
 
9ae3a8
     for (i = 0; i < vdev->nr_vectors; i++) {
9ae3a8
-        MSIMessage msg;
9ae3a8
         VFIOMSIVector *vector = &vdev->msi_vectors[i];
9ae3a8
 
9ae3a8
         vector->vdev = vdev;
9ae3a8
@@ -805,13 +805,13 @@ retry:
9ae3a8
             error_report("vfio: Error: event_notifier_init failed");
9ae3a8
         }
9ae3a8
 
9ae3a8
-        msg = msi_get_message(&vdev->pdev, i);
9ae3a8
+        vector->msg = msi_get_message(&vdev->pdev, i);
9ae3a8
 
9ae3a8
         /*
9ae3a8
          * Attempt to enable route through KVM irqchip,
9ae3a8
          * default to userspace handling if unavailable.
9ae3a8
          */
9ae3a8
-        vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg);
9ae3a8
+        vector->virq = kvm_irqchip_add_msi_route(kvm_state, vector->msg);
9ae3a8
         if (vector->virq < 0 ||
9ae3a8
             kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
9ae3a8
                                            vector->virq) < 0) {
9ae3a8
@@ -917,6 +917,33 @@ static void vfio_disable_msi(VFIODevice *vdev)
9ae3a8
             vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
 }
9ae3a8
 
9ae3a8
+static void vfio_update_msi(VFIODevice *vdev)
9ae3a8
+{
9ae3a8
+    int i;
9ae3a8
+
9ae3a8
+    for (i = 0; i < vdev->nr_vectors; i++) {
9ae3a8
+        VFIOMSIVector *vector = &vdev->msi_vectors[i];
9ae3a8
+        MSIMessage msg;
9ae3a8
+
9ae3a8
+        if (!vector->use || vector->virq < 0) {
9ae3a8
+            continue;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        msg = msi_get_message(&vdev->pdev, i);
9ae3a8
+
9ae3a8
+        if (msg.address != vector->msg.address ||
9ae3a8
+            msg.data != vector->msg.data) {
9ae3a8
+
9ae3a8
+            DPRINTF("%s(%04x:%02x:%02x.%x) MSI vector %d changed\n",
9ae3a8
+                    __func__, vdev->host.domain, vdev->host.bus,
9ae3a8
+                    vdev->host.slot, vdev->host.function, i);
9ae3a8
+
9ae3a8
+            kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg);
9ae3a8
+            vector->msg = msg;
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+}
9ae3a8
+
9ae3a8
 /*
9ae3a8
  * IO Port/MMIO - Beware of the endians, VFIO is always little endian
9ae3a8
  */
9ae3a8
@@ -1834,10 +1861,16 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
9ae3a8
 
9ae3a8
         is_enabled = msi_enabled(pdev);
9ae3a8
 
9ae3a8
-        if (!was_enabled && is_enabled) {
9ae3a8
-            vfio_enable_msi(vdev);
9ae3a8
-        } else if (was_enabled && !is_enabled) {
9ae3a8
-            vfio_disable_msi(vdev);
9ae3a8
+        if (!was_enabled) {
9ae3a8
+            if (is_enabled) {
9ae3a8
+                vfio_enable_msi(vdev);
9ae3a8
+            }
9ae3a8
+        } else {
9ae3a8
+            if (!is_enabled) {
9ae3a8
+                vfio_disable_msi(vdev);
9ae3a8
+            } else {
9ae3a8
+                vfio_update_msi(vdev);
9ae3a8
+            }
9ae3a8
         }
9ae3a8
     } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
9ae3a8
         ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) {
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8