From patchwork Wed Apr 29 08:48:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: chenfan X-Patchwork-Id: 465940 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id BA184140320 for ; Wed, 29 Apr 2015 18:51:03 +1000 (AEST) Received: from localhost ([::1]:37739 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnNhu-0005hm-00 for incoming@patchwork.ozlabs.org; Wed, 29 Apr 2015 04:51:02 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36082) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnNgk-0003za-Se for qemu-devel@nongnu.org; Wed, 29 Apr 2015 04:49:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YnNgg-00030V-6m for qemu-devel@nongnu.org; Wed, 29 Apr 2015 04:49:50 -0400 Received: from [59.151.112.132] (port=1065 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnNgf-0002jM-By for qemu-devel@nongnu.org; Wed, 29 Apr 2015 04:49:46 -0400 X-IronPort-AV: E=Sophos;i="5.04,848,1406563200"; d="scan'208";a="91413659" Received: from localhost (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 29 Apr 2015 16:45:52 +0800 Received: from G08CNEXCHPEKD02.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id t3T8mSRw007395; Wed, 29 Apr 2015 16:48:28 +0800 Received: from G08FNSTD131468.g08.fujitsu.local (10.167.226.78) by G08CNEXCHPEKD02.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.181.6; Wed, 29 Apr 2015 16:49:48 +0800 From: Chen Fan To: Date: Wed, 29 Apr 2015 16:48:39 +0800 Message-ID: X-Mailer: git-send-email 1.9.3 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [10.167.226.78] X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 59.151.112.132 Cc: izumi.taku@jp.fujitsu.com, alex.williamson@redhat.com Subject: [Qemu-devel] [PATCH RFC v6 11/11] vfio: add bus reset notifier for host bus reset X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org add host secondary bus reset for vfio when AER occurs, if reset failed, we should stop vm. Signed-off-by: Chen Fan --- 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); } /*