qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PULL 2/2] vfio-pci: Fix interrupt disabling


From: Alex Williamson
Subject: [Qemu-devel] [PULL 2/2] vfio-pci: Fix interrupt disabling
Date: Fri, 09 Jan 2015 09:30:56 -0700
User-agent: StGit/0.17.1-dirty

When disabling MSI/X interrupts the disable functions will leave the
device in INTx mode (when available).  This matches how hardware
operates, INTx is enabled unless MSI/X is enabled (DisINTx is handled
separately).  Therefore when we really want to disable all interrupts,
such as when removing the device, and we start with the device in
MSI/X mode, we need to pass through INTx on our way to being
completely quiesced.

In well behaved situations, the guest driver will have shutdown the
device and it will start vfio_exitfn() in INTx mode, producing the
desired result.  If hot-unplug causes the guest to crash, we may get
the device in MSI/X state, which will leave QEMU with a bogus handler
installed.

Fix this by re-ordering our disable routine so that it should always
finish in VFIO_INT_NONE state, which is what all callers expect.

Signed-off-by: Alex Williamson <address@hidden>
---
 hw/vfio/pci.c |   21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index b6703c7..014a92c 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2129,16 +2129,19 @@ static void vfio_pci_write_config(PCIDevice *pdev, 
uint32_t addr,
  */
 static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
 {
-    switch (vdev->interrupt) {
-    case VFIO_INT_INTx:
-        vfio_disable_intx(vdev);
-        break;
-    case VFIO_INT_MSI:
-        vfio_disable_msi(vdev);
-        break;
-    case VFIO_INT_MSIX:
+    /*
+     * More complicated than it looks.  Disabling MSI/X transitions the
+     * device to INTx mode (if supported).  Therefore we need to first
+     * disable MSI/X and then cleanup by disabling INTx.
+     */
+    if (vdev->interrupt == VFIO_INT_MSIX) {
         vfio_disable_msix(vdev);
-        break;
+    } else if (vdev->interrupt == VFIO_INT_MSI) {
+        vfio_disable_msi(vdev);
+    }
+
+    if (vdev->interrupt == VFIO_INT_INTx) {
+        vfio_disable_intx(vdev);
     }
 }
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]