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