9ae3a8
From fdad8c197b91f1010e4f61147f27513a4f061e40 Mon Sep 17 00:00:00 2001
9ae3a8
From: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Date: Mon, 12 Jan 2015 04:52:17 +0100
9ae3a8
Subject: [PATCH 1/3] vfio-pci: Fix interrupt disabling
9ae3a8
9ae3a8
Message-id: <20150112045144.9215.59820.stgit@gimli.home>
9ae3a8
Patchwork-id: 63242
9ae3a8
O-Subject: [RHEL7.1 qemu-kvm PATCH] vfio-pci: Fix interrupt disabling
9ae3a8
Bugzilla: 1180942
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
RH-Acked-by: Bandan Das <bsd@redhat.com>
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
9ae3a8
Upstream: b3e27c3aee8f5a96debfe0346e9c0e3a641a8516
9ae3a8
9ae3a8
When disabling MSI/X interrupts the disable functions will leave the
9ae3a8
device in INTx mode (when available).  This matches how hardware
9ae3a8
operates, INTx is enabled unless MSI/X is enabled (DisINTx is handled
9ae3a8
separately).  Therefore when we really want to disable all interrupts,
9ae3a8
such as when removing the device, and we start with the device in
9ae3a8
MSI/X mode, we need to pass through INTx on our way to being
9ae3a8
completely quiesced.
9ae3a8
9ae3a8
In well behaved situations, the guest driver will have shutdown the
9ae3a8
device and it will start vfio_exitfn() in INTx mode, producing the
9ae3a8
desired result.  If hot-unplug causes the guest to crash, we may get
9ae3a8
the device in MSI/X state, which will leave QEMU with a bogus handler
9ae3a8
installed.
9ae3a8
9ae3a8
Fix this by re-ordering our disable routine so that it should always
9ae3a8
finish in VFIO_INT_NONE state, which is what all callers expect.
9ae3a8
9ae3a8
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c | 21 ++++++++++++---------
9ae3a8
 1 file changed, 12 insertions(+), 9 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
9ae3a8
index abaa4c1..40b0923 100644
9ae3a8
--- a/hw/misc/vfio.c
9ae3a8
+++ b/hw/misc/vfio.c
9ae3a8
@@ -2353,16 +2353,19 @@ static void vfio_listener_release(VFIOContainer *container)
9ae3a8
  */
9ae3a8
 static void vfio_disable_interrupts(VFIODevice *vdev)
9ae3a8
 {
9ae3a8
-    switch (vdev->interrupt) {
9ae3a8
-    case VFIO_INT_INTx:
9ae3a8
-        vfio_disable_intx(vdev);
9ae3a8
-        break;
9ae3a8
-    case VFIO_INT_MSI:
9ae3a8
-        vfio_disable_msi(vdev);
9ae3a8
-        break;
9ae3a8
-    case VFIO_INT_MSIX:
9ae3a8
+    /*
9ae3a8
+     * More complicated than it looks.  Disabling MSI/X transitions the
9ae3a8
+     * device to INTx mode (if supported).  Therefore we need to first
9ae3a8
+     * disable MSI/X and then cleanup by disabling INTx.
9ae3a8
+     */
9ae3a8
+    if (vdev->interrupt == VFIO_INT_MSIX) {
9ae3a8
         vfio_disable_msix(vdev);
9ae3a8
-        break;
9ae3a8
+    } else if (vdev->interrupt == VFIO_INT_MSI) {
9ae3a8
+        vfio_disable_msi(vdev);
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (vdev->interrupt == VFIO_INT_INTx) {
9ae3a8
+        vfio_disable_intx(vdev);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8