[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH RFC v6 11/11] vfio: add bus reset notifier for host
From: |
Chen Fan |
Subject: |
[Qemu-devel] [PATCH RFC v6 11/11] vfio: add bus reset notifier for host bus reset |
Date: |
Wed, 29 Apr 2015 16:48:39 +0800 |
add host secondary bus reset for vfio when AER occurs, if reset failed,
we should stop vm.
Signed-off-by: Chen Fan <address@hidden>
---
hw/vfio/pci.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 138 insertions(+), 13 deletions(-)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 060fb47..619daed 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -154,6 +154,8 @@ typedef struct VFIOPCIDevice {
PCIHostDeviceAddress host;
EventNotifier err_notifier;
EventNotifier req_notifier;
+
+ Notifier sec_bus_reset_notifier;
uint32_t features;
#define VFIO_FEATURE_ENABLE_VGA_BIT 0
#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
@@ -2627,6 +2629,13 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int
pos, uint8_t size)
return pos;
}
+static bool vfio_pci_host_match(PCIHostDeviceAddress *host1,
+ PCIHostDeviceAddress *host2)
+{
+ return (host1->domain == host2->domain && host1->bus == host2->bus &&
+ host1->slot == host2->slot && host1->function == host2->function);
+}
+
static void vfio_check_pcie_flr(VFIOPCIDevice *vdev, uint8_t pos)
{
uint32_t cap = pci_get_long(vdev->pdev.config + pos + PCI_EXP_DEVCAP);
@@ -2819,6 +2828,131 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev,
uint8_t pos)
return 0;
}
+static int vfio_aer_validate_devices(DeviceState *dev,
+ void *opaque)
+{
+ VFIOPCIDevice *vdev;
+ int i;
+ bool found = false;
+ struct vfio_pci_hot_reset_info *info = opaque;
+ struct vfio_pci_dependent_device *devices = &info->devices[0];
+
+ if (!object_dynamic_cast(OBJECT(dev), "vfio-pci")) {
+ return 0;
+ }
+
+ vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(dev));
+ for (i = 0; i < info->count; i++) {
+ PCIHostDeviceAddress host;
+
+ host.domain = devices[i].segment;
+ host.bus = devices[i].bus;
+ host.slot = PCI_SLOT(devices[i].devfn);
+ host.function = PCI_FUNC(devices[i].devfn);
+
+ if (vfio_pci_host_match(&host, &vdev->host)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ error_report("vfio: Cannot reset parent bus with AER supported,"
+ "depends on device %s which is not contained.",
+ vdev->vbasedev.name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void vfio_pci_vm_stop(VFIOPCIDevice *vdev)
+{
+ error_report("%s(%04x:%02x:%02x.%x) Unrecoverable error detected. "
+ "Please collect any data possible and then kill the guest",
+ __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function);
+
+ vm_stop(RUN_STATE_INTERNAL_ERROR);
+}
+
+static void vfio_pci_host_bus_reset(Notifier *n, void *opaque)
+{
+ VFIOPCIDevice *vdev = container_of(n, VFIOPCIDevice,
sec_bus_reset_notifier);
+ PCIDevice *pdev = &vdev->pdev;
+ int ret, i;
+ struct vfio_pci_hot_reset_info *info;
+ struct vfio_pci_dependent_device *devices;
+ VFIOGroup *group;
+
+ if (!(vdev->features & VFIO_FEATURE_ENABLE_AER)) {
+ return;
+ }
+
+ /*
+ * Check the affected devices by virtual bus reset are contained in
+ * the set of groups.
+ */
+ ret = vfio_get_hot_reset_info(vdev, &info);
+ if (ret < 0) {
+ goto stop_vm;
+ }
+
+ devices = &info->devices[0];
+
+ /* Verify that we have all the groups required */
+ for (i = 0; i < info->count; i++) {
+ PCIHostDeviceAddress host;
+
+ host.domain = devices[i].segment;
+ host.bus = devices[i].bus;
+ host.slot = PCI_SLOT(devices[i].devfn);
+ host.function = PCI_FUNC(devices[i].devfn);
+
+ if (vfio_pci_host_match(&host, &vdev->host)) {
+ continue;
+ }
+
+ QLIST_FOREACH(group, &vfio_group_list, next) {
+ if (group->groupid == devices[i].group_id) {
+ break;
+ }
+ }
+
+ if (!group) {
+ if (!vdev->has_pm_reset) {
+ error_report("vfio: Cannot reset device %s with AER supported,"
+ "depends on group %d which is not owned.",
+ vdev->vbasedev.name, devices[i].group_id);
+ }
+ ret = -EPERM;
+ goto stop_vm;
+ }
+ }
+
+ /* Verify that we have all the affected devices under the bus */
+ ret = qbus_walk_children(BUS(pdev->bus), NULL, NULL,
+ vfio_aer_validate_devices,
+ NULL, info);
+ if (ret < 0) {
+ goto stop_vm;
+ }
+
+
+ /* bus reset! */
+ ret = vfio_pci_do_hot_reset(vdev, info);
+ if (ret < 0) {
+ goto stop_vm;
+ }
+
+ g_free(info);
+ return;
+
+stop_vm:
+ g_free(info);
+ vfio_pci_vm_stop(vdev);
+}
+
static int vfio_setup_aer(VFIOPCIDevice *vdev, int pos, uint16_t size)
{
PCIDevice *pdev = &vdev->pdev;
@@ -2852,6 +2986,9 @@ static int vfio_setup_aer(VFIOPCIDevice *vdev, int pos,
uint16_t size)
pdev->exp.aer_cap + PCI_ERR_UNCOR_SEVER, 4);
pci_long_test_and_clear_mask(exp_cap + PCI_ERR_UNCOR_SEVER, ~severity);
+ vdev->sec_bus_reset_notifier.notify = vfio_pci_host_bus_reset;
+ pci_bus_add_reset_notifier(pdev->bus, &vdev->sec_bus_reset_notifier);
+
return 0;
}
@@ -2978,13 +3115,6 @@ static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
vfio_enable_intx(vdev);
}
-static bool vfio_pci_host_match(PCIHostDeviceAddress *host1,
- PCIHostDeviceAddress *host2)
-{
- return (host1->domain == host2->domain && host1->bus == host2->bus &&
- host1->slot == host2->slot && host1->function == host2->function);
-}
-
static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
{
VFIOGroup *group;
@@ -3328,12 +3458,7 @@ static void vfio_err_notifier_handler(void *opaque)
* terminate the guest to contain the error.
*/
- error_report("%s(%04x:%02x:%02x.%x) Unrecoverable error detected. "
- "Please collect any data possible and then kill the guest",
- __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function);
-
- vm_stop(RUN_STATE_INTERNAL_ERROR);
+ vfio_pci_vm_stop(vdev);
}
/*
--
1.9.3
- [Qemu-devel] [PATCH RFC v6 04/11] pcie_aer: expose pcie_aer_msg() interface, (continued)
- [Qemu-devel] [PATCH RFC v6 04/11] pcie_aer: expose pcie_aer_msg() interface, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 02/11] aer: impove pcie_aer_init to support vfio device, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 03/11] vfio: add aer support for vfio device, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 01/11] vfio: add pcie extanded capability support, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 05/11] vfio-pci: pass the aer error to guest, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 06/11] vfio: add 'aer' property to expose aercap, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 07/11] pc: add HW_COMPAT_2_2 to disable aercap for vifo device, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 08/11] vfio: extract vfio_get_hot_reset_info as a single function, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 09/11] qdev: add bus reset_notifiers callbacks for host bus reset, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 10/11] vfio: squeeze out vfio_pci_do_hot_reset for support bus reset, Chen Fan, 2015/04/29
- [Qemu-devel] [PATCH RFC v6 11/11] vfio: add bus reset notifier for host bus reset,
Chen Fan <=