diff mbox

[v2,09/11] vfio: vote a device to do host bus reset

Message ID 1455878558-4672-10-git-send-email-caoj.fnst@cn.fujitsu.com
State New
Headers show

Commit Message

Cao jin Feb. 19, 2016, 10:42 a.m. UTC
From: Chen Fan <chen.fan.fnst@cn.fujitsu.com>

Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
---
 hw/vfio/pci.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/vfio/pci.h |  1 +
 2 files changed, 58 insertions(+)
diff mbox

Patch

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 24848c9..8e902d2 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1937,6 +1937,8 @@  static void vfio_check_host_bus_reset(VFIOPCIDevice *vdev, Error **errp)
     /* List all affected devices by bus reset */
     devices = &info->devices[0];
 
+    vdev->single_depend_dev = (info->count == 1);
+
     /* Verify that we have all the groups required */
     for (i = 0; i < info->count; i++) {
         PCIHostDeviceAddress host;
@@ -2998,6 +3000,49 @@  static void vfio_exitfn(PCIDevice *pdev)
     vfio_unregister_bars(vdev);
 }
 
+static VFIOPCIDevice *vfio_pci_get_do_reset_device(VFIOPCIDevice *vdev)
+{
+    struct vfio_pci_hot_reset_info *info = NULL;
+    struct vfio_pci_dependent_device *devices;
+    VFIOGroup *group;
+    VFIODevice *vbasedev_iter;
+    int ret;
+
+    ret = vfio_get_hot_reset_info(vdev, &info);
+    if (ret) {
+        error_report("vfio: Cannot enable AER for device %s,"
+                     " device does not support hot reset.",
+                     vdev->vbasedev.name);
+        return NULL;
+    }
+
+    devices = &info->devices[0];
+
+    QLIST_FOREACH(group, &vfio_group_list, next) {
+        if (group->groupid == devices[0].group_id) {
+            break;
+        }
+    }
+
+    if (!group) {
+        error_report("vfio: Cannot enable AER for device %s, "
+                    "depends on group %d which is not owned.",
+                    vdev->vbasedev.name, devices[0].group_id);
+        return NULL;
+    }
+
+    QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
+        if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI ||
+            !(vdev->features & VFIO_FEATURE_ENABLE_AER)) {
+            continue;
+        }
+
+        return container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
+    }
+
+    return NULL;
+}
+
 static void vfio_pci_reset(DeviceState *dev)
 {
     PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
@@ -3005,6 +3050,18 @@  static void vfio_pci_reset(DeviceState *dev)
 
     trace_vfio_pci_reset(vdev->vbasedev.name);
 
+    if (pdev->bus->in_hot_reset) {
+        VFIOPCIDevice *tmp;
+
+        tmp = vfio_pci_get_do_reset_device(vdev);
+        if (tmp) {
+            if (tmp == vdev) {
+                vfio_pci_hot_reset(vdev, vdev->single_depend_dev);
+            }
+            return;
+        }
+    }
+
     vfio_pci_pre_reset(vdev);
 
     if (vdev->resetfn && !vdev->resetfn(vdev)) {
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index aff46c2..32bd31f 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -143,6 +143,7 @@  typedef struct VFIOPCIDevice {
     bool no_kvm_intx;
     bool no_kvm_msi;
     bool no_kvm_msix;
+    bool single_depend_dev;
 } VFIOPCIDevice;
 
 uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);