yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
9ae3a8
From 8ea5e0ba0b1ba054d71bb10f8c45c167dd3d7792 Mon Sep 17 00:00:00 2001
9ae3a8
From: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Date: Tue, 5 Nov 2013 17:31:11 +0100
9ae3a8
Subject: [PATCH 19/25] vfio-pci: Implement PCI hot reset
9ae3a8
9ae3a8
RH-Author: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
Message-id: <20131105173110.19372.22420.stgit@bling.home>
9ae3a8
Patchwork-id: 55440
9ae3a8
O-Subject: [RHEL7 qemu-kvm PATCH 2/2] vfio-pci: Implement PCI hot reset
9ae3a8
Bugzilla: 1025472
9ae3a8
RH-Acked-by: Bandan Das <bsd@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
9ae3a8
Bugzilla: 1025472
9ae3a8
Upstream commit: f16f39c3fc973c5d7cbc2224eefb4ef5eb1e64ff
9ae3a8
9ae3a8
Now that VFIO has a PCI hot reset interface, take advantage of it.
9ae3a8
There are two modes that we need to consider.  The first is when only
9ae3a8
one device within the set of devices affected is actually assigned to
9ae3a8
the guest.  In this case the other devices are are just held by VFIO
9ae3a8
for isolation and we can pretend they're not there, doing an entire
9ae3a8
bus reset whenever the device reset callback is triggered.  Supporting
9ae3a8
this case separately allows us to do the best reset we can do of the
9ae3a8
device even if the device is hotplugged.
9ae3a8
9ae3a8
The second mode is when multiple affected devices are all exposed to
9ae3a8
the guest.  In this case we can only do a hot reset when the entire
9ae3a8
system is being reset.  However, this also allows us to track which
9ae3a8
individual devices are affected by a reset and only do them once.
9ae3a8
9ae3a8
We split our reset function into pre- and post-reset helper functions
9ae3a8
prioritize the types of device resets available to us, and create
9ae3a8
separate _one vs _multi reset interfaces to handle the distinct cases
9ae3a8
above.
9ae3a8
9ae3a8
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c |  338 ++++++++++++++++++++++++++++++++++++++++++++++++++------
9ae3a8
 1 file changed, 300 insertions(+), 38 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/misc/vfio.c |  338 +++++++++++++++++++++++++++++++++++++++++++++++++-------
9ae3a8
 1 files changed, 300 insertions(+), 38 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
9ae3a8
index 6178221..331ae5f 100644
9ae3a8
--- a/hw/misc/vfio.c
9ae3a8
+++ b/hw/misc/vfio.c
9ae3a8
@@ -188,6 +188,7 @@ typedef struct VFIODevice {
9ae3a8
     bool pci_aer;
9ae3a8
     bool has_flr;
9ae3a8
     bool has_pm_reset;
9ae3a8
+    bool needs_reset;
9ae3a8
 } VFIODevice;
9ae3a8
 
9ae3a8
 typedef struct VFIOGroup {
9ae3a8
@@ -2759,6 +2760,279 @@ static int vfio_add_capabilities(VFIODevice *vdev)
9ae3a8
     return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
9ae3a8
 }
9ae3a8
 
9ae3a8
+static void vfio_pci_pre_reset(VFIODevice *vdev)
9ae3a8
+{
9ae3a8
+    PCIDevice *pdev = &vdev->pdev;
9ae3a8
+    uint16_t cmd;
9ae3a8
+
9ae3a8
+    vfio_disable_interrupts(vdev);
9ae3a8
+
9ae3a8
+    /* Make sure the device is in D0 */
9ae3a8
+    if (vdev->pm_cap) {
9ae3a8
+        uint16_t pmcsr;
9ae3a8
+        uint8_t state;
9ae3a8
+
9ae3a8
+        pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
9ae3a8
+        state = pmcsr & PCI_PM_CTRL_STATE_MASK;
9ae3a8
+        if (state) {
9ae3a8
+            pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
9ae3a8
+            vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
9ae3a8
+            /* vfio handles the necessary delay here */
9ae3a8
+            pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
9ae3a8
+            state = pmcsr & PCI_PM_CTRL_STATE_MASK;
9ae3a8
+            if (state) {
9ae3a8
+                error_report("vfio: Unable to power on device, stuck in D%d\n",
9ae3a8
+                             state);
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    /*
9ae3a8
+     * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
9ae3a8
+     * Also put INTx Disable in known state.
9ae3a8
+     */
9ae3a8
+    cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
9ae3a8
+    cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
9ae3a8
+             PCI_COMMAND_INTX_DISABLE);
9ae3a8
+    vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
9ae3a8
+}
9ae3a8
+
9ae3a8
+static void vfio_pci_post_reset(VFIODevice *vdev)
9ae3a8
+{
9ae3a8
+    vfio_enable_intx(vdev);
9ae3a8
+}
9ae3a8
+
9ae3a8
+static bool vfio_pci_host_match(PCIHostDeviceAddress *host1,
9ae3a8
+                                PCIHostDeviceAddress *host2)
9ae3a8
+{
9ae3a8
+    return (host1->domain == host2->domain && host1->bus == host2->bus &&
9ae3a8
+            host1->slot == host2->slot && host1->function == host2->function);
9ae3a8
+}
9ae3a8
+
9ae3a8
+static int vfio_pci_hot_reset(VFIODevice *vdev, bool single)
9ae3a8
+{
9ae3a8
+    VFIOGroup *group;
9ae3a8
+    struct vfio_pci_hot_reset_info *info;
9ae3a8
+    struct vfio_pci_dependent_device *devices;
9ae3a8
+    struct vfio_pci_hot_reset *reset;
9ae3a8
+    int32_t *fds;
9ae3a8
+    int ret, i, count;
9ae3a8
+    bool multi = false;
9ae3a8
+
9ae3a8
+    DPRINTF("%s(%04x:%02x:%02x.%x) %s\n", __func__, vdev->host.domain,
9ae3a8
+            vdev->host.bus, vdev->host.slot, vdev->host.function,
9ae3a8
+            single ? "one" : "multi");
9ae3a8
+
9ae3a8
+    vfio_pci_pre_reset(vdev);
9ae3a8
+    vdev->needs_reset = false;
9ae3a8
+
9ae3a8
+    info = g_malloc0(sizeof(*info));
9ae3a8
+    info->argsz = sizeof(*info);
9ae3a8
+
9ae3a8
+    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
9ae3a8
+    if (ret && errno != ENOSPC) {
9ae3a8
+        ret = -errno;
9ae3a8
+        if (!vdev->has_pm_reset) {
9ae3a8
+            error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, "
9ae3a8
+                         "no available reset mechanism.", vdev->host.domain,
9ae3a8
+                         vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
+        }
9ae3a8
+        goto out_single;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    count = info->count;
9ae3a8
+    info = g_realloc(info, sizeof(*info) + (count * sizeof(*devices)));
9ae3a8
+    info->argsz = sizeof(*info) + (count * sizeof(*devices));
9ae3a8
+    devices = &info->devices[0];
9ae3a8
+
9ae3a8
+    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_PCI_HOT_RESET_INFO, info);
9ae3a8
+    if (ret) {
9ae3a8
+        ret = -errno;
9ae3a8
+        error_report("vfio: hot reset info failed: %m");
9ae3a8
+        goto out_single;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    DPRINTF("%04x:%02x:%02x.%x: hot reset dependent devices:\n",
9ae3a8
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
+            vdev->host.function);
9ae3a8
+
9ae3a8
+    /* Verify that we have all the groups required */
9ae3a8
+    for (i = 0; i < info->count; i++) {
9ae3a8
+        PCIHostDeviceAddress host;
9ae3a8
+        VFIODevice *tmp;
9ae3a8
+
9ae3a8
+        host.domain = devices[i].segment;
9ae3a8
+        host.bus = devices[i].bus;
9ae3a8
+        host.slot = PCI_SLOT(devices[i].devfn);
9ae3a8
+        host.function = PCI_FUNC(devices[i].devfn);
9ae3a8
+
9ae3a8
+        DPRINTF("\t%04x:%02x:%02x.%x group %d\n", host.domain,
9ae3a8
+                host.bus, host.slot, host.function, devices[i].group_id);
9ae3a8
+
9ae3a8
+        if (vfio_pci_host_match(&host, &vdev->host)) {
9ae3a8
+            continue;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+            if (group->groupid == devices[i].group_id) {
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (!group) {
9ae3a8
+            if (!vdev->has_pm_reset) {
9ae3a8
+                error_report("vfio: Cannot reset device %04x:%02x:%02x.%x, "
9ae3a8
+                             "depends on group %d which is not owned.",
9ae3a8
+                             vdev->host.domain, vdev->host.bus, vdev->host.slot,
9ae3a8
+                             vdev->host.function, devices[i].group_id);
9ae3a8
+            }
9ae3a8
+            ret = -EPERM;
9ae3a8
+            goto out;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        /* Prep dependent devices for reset and clear our marker. */
9ae3a8
+        QLIST_FOREACH(tmp, &group->device_list, next) {
9ae3a8
+            if (vfio_pci_host_match(&host, &tmp->host)) {
9ae3a8
+                if (single) {
9ae3a8
+                    DPRINTF("vfio: found another in-use device "
9ae3a8
+                            "%04x:%02x:%02x.%x\n", host.domain, host.bus,
9ae3a8
+                            host.slot, host.function);
9ae3a8
+                    ret = -EINVAL;
9ae3a8
+                    goto out_single;
9ae3a8
+                }
9ae3a8
+                vfio_pci_pre_reset(tmp);
9ae3a8
+                tmp->needs_reset = false;
9ae3a8
+                multi = true;
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (!single && !multi) {
9ae3a8
+        DPRINTF("vfio: No other in-use devices for multi hot reset\n");
9ae3a8
+        ret = -EINVAL;
9ae3a8
+        goto out_single;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    /* Determine how many group fds need to be passed */
9ae3a8
+    count = 0;
9ae3a8
+    QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+        for (i = 0; i < info->count; i++) {
9ae3a8
+            if (group->groupid == devices[i].group_id) {
9ae3a8
+                count++;
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    reset = g_malloc0(sizeof(*reset) + (count * sizeof(*fds)));
9ae3a8
+    reset->argsz = sizeof(*reset) + (count * sizeof(*fds));
9ae3a8
+    fds = &reset->group_fds[0];
9ae3a8
+
9ae3a8
+    /* Fill in group fds */
9ae3a8
+    QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+        for (i = 0; i < info->count; i++) {
9ae3a8
+            if (group->groupid == devices[i].group_id) {
9ae3a8
+                fds[reset->count++] = group->fd;
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    /* Bus reset! */
9ae3a8
+    ret = ioctl(vdev->fd, VFIO_DEVICE_PCI_HOT_RESET, reset);
9ae3a8
+    g_free(reset);
9ae3a8
+
9ae3a8
+    DPRINTF("%04x:%02x:%02x.%x hot reset: %s\n", vdev->host.domain,
9ae3a8
+            vdev->host.bus, vdev->host.slot, vdev->host.function,
9ae3a8
+            ret ? "%m" : "Success");
9ae3a8
+
9ae3a8
+out:
9ae3a8
+    /* Re-enable INTx on affected devices */
9ae3a8
+    for (i = 0; i < info->count; i++) {
9ae3a8
+        PCIHostDeviceAddress host;
9ae3a8
+        VFIODevice *tmp;
9ae3a8
+
9ae3a8
+        host.domain = devices[i].segment;
9ae3a8
+        host.bus = devices[i].bus;
9ae3a8
+        host.slot = PCI_SLOT(devices[i].devfn);
9ae3a8
+        host.function = PCI_FUNC(devices[i].devfn);
9ae3a8
+
9ae3a8
+        if (vfio_pci_host_match(&host, &vdev->host)) {
9ae3a8
+            continue;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+            if (group->groupid == devices[i].group_id) {
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        if (!group) {
9ae3a8
+            break;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        QLIST_FOREACH(tmp, &group->device_list, next) {
9ae3a8
+            if (vfio_pci_host_match(&host, &tmp->host)) {
9ae3a8
+                vfio_pci_post_reset(tmp);
9ae3a8
+                break;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+out_single:
9ae3a8
+    vfio_pci_post_reset(vdev);
9ae3a8
+    g_free(info);
9ae3a8
+
9ae3a8
+    return ret;
9ae3a8
+}
9ae3a8
+
9ae3a8
+/*
9ae3a8
+ * We want to differentiate hot reset of mulitple in-use devices vs hot reset
9ae3a8
+ * of a single in-use device.  VFIO_DEVICE_RESET will already handle the case
9ae3a8
+ * of doing hot resets when there is only a single device per bus.  The in-use
9ae3a8
+ * here refers to how many VFIODevices are affected.  A hot reset that affects
9ae3a8
+ * multiple devices, but only a single in-use device, means that we can call
9ae3a8
+ * it from our bus ->reset() callback since the extent is effectively a single
9ae3a8
+ * device.  This allows us to make use of it in the hotplug path.  When there
9ae3a8
+ * are multiple in-use devices, we can only trigger the hot reset during a
9ae3a8
+ * system reset and thus from our reset handler.  We separate _one vs _multi
9ae3a8
+ * here so that we don't overlap and do a double reset on the system reset
9ae3a8
+ * path where both our reset handler and ->reset() callback are used.  Calling
9ae3a8
+ * _one() will only do a hot reset for the one in-use devices case, calling
9ae3a8
+ * _multi() will do nothing if a _one() would have been sufficient.
9ae3a8
+ */
9ae3a8
+static int vfio_pci_hot_reset_one(VFIODevice *vdev)
9ae3a8
+{
9ae3a8
+    return vfio_pci_hot_reset(vdev, true);
9ae3a8
+}
9ae3a8
+
9ae3a8
+static int vfio_pci_hot_reset_multi(VFIODevice *vdev)
9ae3a8
+{
9ae3a8
+    return vfio_pci_hot_reset(vdev, false);
9ae3a8
+}
9ae3a8
+
9ae3a8
+static void vfio_pci_reset_handler(void *opaque)
9ae3a8
+{
9ae3a8
+    VFIOGroup *group;
9ae3a8
+    VFIODevice *vdev;
9ae3a8
+
9ae3a8
+    QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+        QLIST_FOREACH(vdev, &group->device_list, next) {
9ae3a8
+            if (!vdev->reset_works || (!vdev->has_flr && vdev->has_pm_reset)) {
9ae3a8
+                vdev->needs_reset = true;
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    QLIST_FOREACH(group, &group_list, next) {
9ae3a8
+        QLIST_FOREACH(vdev, &group->device_list, next) {
9ae3a8
+            if (vdev->needs_reset) {
9ae3a8
+                vfio_pci_hot_reset_multi(vdev);
9ae3a8
+            }
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+}
9ae3a8
+
9ae3a8
 static int vfio_connect_container(VFIOGroup *group)
9ae3a8
 {
9ae3a8
     VFIOContainer *container;
9ae3a8
@@ -2901,6 +3175,10 @@ static VFIOGroup *vfio_get_group(int groupid)
9ae3a8
         return NULL;
9ae3a8
     }
9ae3a8
 
9ae3a8
+    if (QLIST_EMPTY(&group_list)) {
9ae3a8
+        qemu_register_reset(vfio_pci_reset_handler, NULL);
9ae3a8
+    }
9ae3a8
+
9ae3a8
     QLIST_INSERT_HEAD(&group_list, group, next);
9ae3a8
 
9ae3a8
     return group;
9ae3a8
@@ -2917,6 +3195,10 @@ static void vfio_put_group(VFIOGroup *group)
9ae3a8
     DPRINTF("vfio_put_group: close group->fd\n");
9ae3a8
     close(group->fd);
9ae3a8
     g_free(group);
9ae3a8
+
9ae3a8
+    if (QLIST_EMPTY(&group_list)) {
9ae3a8
+        qemu_unregister_reset(vfio_pci_reset_handler, NULL);
9ae3a8
+    }
9ae3a8
 }
9ae3a8
 
9ae3a8
 static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
9ae3a8
@@ -2955,9 +3237,6 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
9ae3a8
     }
9ae3a8
 
9ae3a8
     vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
9ae3a8
-    if (!vdev->reset_works) {
9ae3a8
-        error_report("Warning, device %s does not support reset", name);
9ae3a8
-    }
9ae3a8
 
9ae3a8
     if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
9ae3a8
         error_report("vfio: unexpected number of io regions %u",
9ae3a8
@@ -3363,51 +3642,34 @@ static void vfio_pci_reset(DeviceState *dev)
9ae3a8
 {
9ae3a8
     PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
9ae3a8
     VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
9ae3a8
-    uint16_t cmd;
9ae3a8
 
9ae3a8
     DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
9ae3a8
             vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
 
9ae3a8
-    vfio_disable_interrupts(vdev);
9ae3a8
-
9ae3a8
-    /* Make sure the device is in D0 */
9ae3a8
-    if (vdev->pm_cap) {
9ae3a8
-        uint16_t pmcsr;
9ae3a8
-        uint8_t state;
9ae3a8
+    vfio_pci_pre_reset(vdev);
9ae3a8
 
9ae3a8
-        pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
9ae3a8
-        state = pmcsr & PCI_PM_CTRL_STATE_MASK;
9ae3a8
-        if (state) {
9ae3a8
-            pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
9ae3a8
-            vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
9ae3a8
-            /* vfio handles the necessary delay here */
9ae3a8
-            pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
9ae3a8
-            state = pmcsr & PCI_PM_CTRL_STATE_MASK;
9ae3a8
-            if (state) {
9ae3a8
-                error_report("vfio: Unable to power on device, stuck in D%d\n",
9ae3a8
-                             state);
9ae3a8
-            }
9ae3a8
-        }
9ae3a8
+    if (vdev->reset_works && (vdev->has_flr || !vdev->has_pm_reset) &&
9ae3a8
+        !ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
9ae3a8
+        DPRINTF("%04x:%02x:%02x.%x FLR/VFIO_DEVICE_RESET\n", vdev->host.domain,
9ae3a8
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
+        goto post_reset;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    /*
9ae3a8
-     * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
9ae3a8
-     * Also put INTx Disable in known state.
9ae3a8
-     */
9ae3a8
-    cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
9ae3a8
-    cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
9ae3a8
-             PCI_COMMAND_INTX_DISABLE);
9ae3a8
-    vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
9ae3a8
+    /* See if we can do our own bus reset */
9ae3a8
+    if (!vfio_pci_hot_reset_one(vdev)) {
9ae3a8
+        goto post_reset;
9ae3a8
+    }
9ae3a8
 
9ae3a8
-    if (vdev->reset_works) {
9ae3a8
-        if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
9ae3a8
-            error_report("vfio: Error unable to reset physical device "
9ae3a8
-                         "(%04x:%02x:%02x.%x): %m", vdev->host.domain,
9ae3a8
-                         vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
-        }
9ae3a8
+    /* If nothing else works and the device supports PM reset, use it */
9ae3a8
+    if (vdev->reset_works && vdev->has_pm_reset &&
9ae3a8
+        !ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
9ae3a8
+        DPRINTF("%04x:%02x:%02x.%x PCI PM Reset\n", vdev->host.domain,
9ae3a8
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
9ae3a8
+        goto post_reset;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    vfio_enable_intx(vdev);
9ae3a8
+post_reset:
9ae3a8
+    vfio_pci_post_reset(vdev);
9ae3a8
 }
9ae3a8
 
9ae3a8
 static Property vfio_pci_dev_properties[] = {
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8