From patchwork Wed May 27 02:46:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: chenfan X-Patchwork-Id: 476898 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 7D6BC1406AA for ; Wed, 27 May 2015 12:53:55 +1000 (AEST) Received: from localhost ([::1]:51514 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxRTd-0007Vw-Nc for incoming@patchwork.ozlabs.org; Tue, 26 May 2015 22:53:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39943) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxRT7-0006Xp-HL for qemu-devel@nongnu.org; Tue, 26 May 2015 22:53:22 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YxRT6-00008R-9T for qemu-devel@nongnu.org; Tue, 26 May 2015 22:53:21 -0400 Received: from [59.151.112.132] (port=65526 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxRT5-0005B1-LS for qemu-devel@nongnu.org; Tue, 26 May 2015 22:53:20 -0400 X-IronPort-AV: E=Sophos;i="5.01,1,1399996800"; d="scan'208";a="95903677" Received: from localhost (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 27 May 2015 10:53:05 +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 t4R2l9Dm008776; Wed, 27 May 2015 10:47:09 +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, 27 May 2015 10:48:39 +0800 From: Chen Fan To: Date: Wed, 27 May 2015 10:46:27 +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] [RFC v8.1 06/13] vfio: add check host bus reset is support or not 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 we introduce a has_bus_reset capability to sign the vfio devices if support host bus reset. Signed-off-by: Chen Fan --- hw/vfio/pci.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index f4e7855..5934fd7 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -33,6 +33,7 @@ #include "hw/pci/msix.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/event_notifier.h" @@ -170,6 +171,7 @@ typedef struct VFIOPCIDevice { bool req_enabled; bool has_flr; bool has_pm_reset; + bool has_bus_reset; bool rom_read_failed; } VFIOPCIDevice; @@ -203,6 +205,7 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, uint32_t val, int len); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); +static void vfio_check_host_bus_reset(VFIOPCIDevice *vdev); /* * Disabling BAR mmaping can be slow, but toggling it around INTx can @@ -2853,6 +2856,20 @@ static int vfio_setup_aer(VFIOPCIDevice *vdev, int pos, uint16_t size) dev_iter = pci_bridge_get_device(dev_iter->bus); } + /* + * Don't check bus reset capability when device is enabled during + * qemu machine creation, which is done by machine init function. + */ + if (DEVICE(vdev)->hotplugged) { + vfio_check_host_bus_reset(vdev); + if (!vdev->has_bus_reset) { + error_report("vfio: Cannot enable AER for device %s, " + "which is not support host bus reset.", + vdev->vbasedev.name); + goto error; + } + } + errcap = vfio_pci_read_config(pdev, pdev->exp.aer_cap + PCI_ERR_CAP, 4); /* * The ability to record multiple headers is depending on @@ -3678,6 +3695,112 @@ static void vfio_setup_resetfn(VFIOPCIDevice *vdev) } } +struct VfioDeviceFind { + PCIBus *pbus; + PCIDevice *pdev; + bool found; +}; + +static void find_devices(PCIBus *bus, void *opaque) +{ + struct VfioDeviceFind *find = opaque; + int i; + + if (find->found == true) { + return; + } + + for (i = 0; i < ARRAY_SIZE(bus->devices); i++) { + if (!bus->devices[i]) { + continue; + } + + if (bus->devices[i] == find->pdev) { + find->pbus = bus; + find->found = true; + break; + } + } +} + +static void 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; + bool has_bus_reset = false; + + ret = vfio_get_hot_reset_info(vdev, &info); + if (ret < 0) { + 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) { + 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)) { + struct VfioDeviceFind find = { .pdev = &tmp->pdev, .found = false }; + + pci_for_each_bus(bus, find_devices, &find); + if (!find.found) { + goto out; + } + /* + * When the check device is hotplugged to a higher bus again, + * which would influence the affected device which enable aer + * below the bus. + */ + if (tmp->features & VFIO_FEATURE_ENABLE_AER && + find.pbus != bus) { + goto out; + } + break; + } + } + } + + has_bus_reset = true; + +out: + vdev->has_bus_reset = has_bus_reset; + g_free(info); +} + static int vfio_initfn(PCIDevice *pdev) { VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);