qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [RFC v10 12/19] vfio: add check host bus reset is support o


From: Chen Fan
Subject: [Qemu-devel] [RFC v10 12/19] vfio: add check host bus reset is support or not
Date: Tue, 16 Jun 2015 16:10:56 +0800

when init vfio device, we should test all the devices supported
aer whether conflict with others. For each one, get the hot reset
info for the affected device list.  For each affected device, if
it's attached to the VM, it needs to be on or below the bus of
the target device. also, we should test all of the non-AER supporting
vfio-pci devices on or below the target bus to verify they have a reset
mechanism.

Signed-off-by: Chen Fan <address@hidden>
---
 hw/vfio/pci.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 170 insertions(+)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index ade3196..53fb544 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -32,6 +32,7 @@
 #include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_bridge.h"
 #include "qemu-common.h"
 #include "qemu/error-report.h"
@@ -2929,6 +2930,169 @@ out:
     return ret;
 }
 
+struct VFIODeviceFind {
+    PCIDevice *pdev;
+    bool found;
+};
+
+static void find_devices(PCIBus *bus, void *opaque)
+{
+    struct VFIODeviceFind *find = opaque;
+    int i;
+
+    if (find->found) {
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bus->devices); i++) {
+        if (!bus->devices[i]) {
+            continue;
+        }
+
+        if (bus->devices[i] == find->pdev) {
+            find->found = true;
+            break;
+        }
+    }
+}
+
+static void vfio_check_device_reset(PCIBus *bus, void *opaque)
+{
+    int i;
+    PCIDevice *dev;
+    VFIOPCIDevice *vdev;
+    struct VFIODeviceFind *find = opaque;
+
+    if (find->found) {
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bus->devices); i++) {
+        if (!bus->devices[i]) {
+            continue;
+        }
+        dev = bus->devices[i];
+        if (!object_dynamic_cast(OBJECT(dev), "vfio-pci")) {
+            continue;
+        }
+        vdev = DO_UPCAST(VFIOPCIDevice, pdev, dev);
+        if (!(vdev->features & VFIO_FEATURE_ENABLE_AER) &&
+            !vdev->vbasedev.reset_works &&
+            !vdev->has_flr &&
+            !vdev->has_pm_reset) {
+            find->pdev = dev;
+            find->found = true;
+            break;
+        }
+    }
+}
+
+static int vfio_check_host_bus_reset(VFIOPCIDevice *vdev)
+{
+    PCIBus *bus = vdev->pdev.bus;
+    struct vfio_pci_hot_reset_info *info = NULL;
+    struct vfio_pci_dependent_device *devices;
+    VFIOGroup *group;
+    int ret, i;
+    struct VFIODeviceFind find;
+
+    ret = vfio_get_hot_reset_info(vdev, &info);
+    if (ret) {
+        goto out;
+    }
+
+    /* List all affected devices by bus reset */
+    devices = &info->devices[0];
+
+    /* Verify that we have all the groups required */
+    for (i = 0; i < info->count; i++) {
+        PCIHostDeviceAddress host;
+        VFIOPCIDevice *tmp;
+        VFIODevice *vbasedev_iter;
+
+        host.domain = devices[i].segment;
+        host.bus = devices[i].bus;
+        host.slot = PCI_SLOT(devices[i].devfn);
+        host.function = PCI_FUNC(devices[i].devfn);
+
+        /* Skip the current device */
+        if (vfio_pci_host_match(&host, &vdev->host)) {
+            continue;
+        }
+
+        /* Ensure we own the group of the affected device */
+        QLIST_FOREACH(group, &vfio_group_list, next) {
+            if (group->groupid == devices[i].group_id) {
+                break;
+            }
+        }
+
+        if (!group) {
+            ret = -1;
+            goto out;
+        }
+
+        /* Ensure affected devices for reset under the same bus */
+        QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
+            if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+                continue;
+            }
+            tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
+            if (vfio_pci_host_match(&host, &tmp->host)) {
+                find.pdev = &tmp->pdev;
+                find.found = false;
+
+                pci_for_each_bus(bus, find_devices, &find);
+                if (!find.found) {
+                    ret = -1;
+                    goto out;
+                }
+                break;
+            }
+        }
+    }
+
+    /*
+     * Check the all vfio pci devices on or below the target bus
+     * have a reset mechanism at least.
+     */
+    find.pdev = NULL;
+    find.found = false;
+    pci_for_each_bus(bus, vfio_check_device_reset, &find);
+    if (find.found) {
+        ret = -1;
+        goto out;
+    }
+
+    ret = 0;
+out:
+    g_free(info);
+    return ret;
+}
+
+static int vfio_check_devices_host_bus_reset(void)
+{
+    VFIOGroup *group;
+    VFIODevice *vbasedev;
+    VFIOPCIDevice *vdev;
+
+    /* Check All vfio-pci devices if have bus reset capability */
+    QLIST_FOREACH(group, &vfio_group_list, next) {
+        QLIST_FOREACH(vbasedev, &group->device_list, next) {
+            vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
+            if ((vdev->features & VFIO_FEATURE_ENABLE_AER) &&
+                vfio_check_host_bus_reset(vdev)) {
+                error_report("vfio: Cannot enable AER for device %s, "
+                             "which does not support host bus reset.",
+                              vdev->vbasedev.name);
+                 return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
 static int vfio_setup_aer(VFIOPCIDevice *vdev, uint8_t cap_ver,
                           int pos, uint16_t size)
 {
@@ -2971,6 +3135,12 @@ static int vfio_setup_aer(VFIOPCIDevice *vdev, uint8_t 
cap_ver,
         return ret;
     }
 
+    /* Make sure this devices does conflict the existing aer topology */
+    ret = vfio_check_devices_host_bus_reset();
+    if (ret) {
+        return ret;
+    }
+
     errcap = vfio_pci_read_config(pdev, pdev->exp.aer_cap + PCI_ERR_CAP, 4);
     /*
      * The ability to record multiple headers is depending on
-- 
1.9.3




reply via email to

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