[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v4 33/41] vfio/iommufd: Enable pci hot reset through iommufd cdev
From: |
Zhenzhong Duan |
Subject: |
[PATCH v4 33/41] vfio/iommufd: Enable pci hot reset through iommufd cdev interface |
Date: |
Thu, 2 Nov 2023 15:12:54 +0800 |
Add a new callback iommufd_pci_hot_reset to do iommufd specific
check and reset operation.
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
hw/vfio/pci.h | 2 +
hw/vfio/iommufd.c | 142 +++++++++++++++++++++++++++++++++++++++++++
hw/vfio/pci.c | 4 +-
hw/vfio/trace-events | 1 +
4 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 12cc765821..ec4a03aecd 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -218,6 +218,8 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr);
extern const PropertyInfo qdev_prop_nv_gpudirect_clique;
+void vfio_pci_pre_reset(VFIOPCIDevice *vdev);
+void vfio_pci_post_reset(VFIOPCIDevice *vdev);
int vfio_pci_get_pci_hot_reset_info(VFIOPCIDevice *vdev,
struct vfio_pci_hot_reset_info **info_p);
int vfio_legacy_pci_hot_reset(VFIODevice *vbasedev, bool single);
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 22f02f92a9..aedfe31c3c 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -24,6 +24,7 @@
#include "sysemu/reset.h"
#include "qemu/cutils.h"
#include "qemu/chardev_open.h"
+#include "pci.h"
static int iommufd_map(VFIOContainerBase *bcontainer, hwaddr iova,
ram_addr_t size, void *vaddr, bool readonly)
@@ -543,9 +544,150 @@ static void iommufd_detach_device(VFIODevice *vbasedev)
close(vbasedev->fd);
}
+static VFIODevice *vfio_pci_find_by_iommufd_devid(__u32 devid)
+{
+ VFIODevice *vbasedev_iter;
+
+ QLIST_FOREACH(vbasedev_iter, &vfio_device_list, global_next) {
+ if (vbasedev_iter->bcontainer->ops != &vfio_iommufd_ops) {
+ continue;
+ }
+ if (devid == vbasedev_iter->devid) {
+ return vbasedev_iter;
+ }
+ }
+ return NULL;
+}
+
+static int iommufd_pci_hot_reset(VFIODevice *vbasedev, bool single)
+{
+ VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
+ struct vfio_pci_hot_reset_info *info = NULL;
+ struct vfio_pci_dependent_device *devices;
+ struct vfio_pci_hot_reset *reset;
+ int ret, i;
+ bool multi = false;
+
+ trace_vfio_pci_hot_reset(vdev->vbasedev.name, single ? "one" : "multi");
+
+ if (!single) {
+ vfio_pci_pre_reset(vdev);
+ }
+ vdev->vbasedev.needs_reset = false;
+
+ ret = vfio_pci_get_pci_hot_reset_info(vdev, &info);
+
+ if (ret) {
+ goto out_single;
+ }
+
+ assert(info->flags & VFIO_PCI_HOT_RESET_FLAG_DEV_ID);
+
+ devices = &info->devices[0];
+
+ if (!(info->flags & VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED)) {
+ if (!vdev->has_pm_reset) {
+ for (i = 0; i < info->count; i++) {
+ if (devices[i].devid == VFIO_PCI_DEVID_NOT_OWNED) {
+ error_report("vfio: Cannot reset device %s, "
+ "depends on device %04x:%02x:%02x.%x "
+ "which is not owned.",
+ vdev->vbasedev.name, devices[i].segment,
+ devices[i].bus, PCI_SLOT(devices[i].devfn),
+ PCI_FUNC(devices[i].devfn));
+ }
+ }
+ }
+ ret = -EPERM;
+ goto out_single;
+ }
+
+ trace_vfio_pci_hot_reset_has_dep_devices(vdev->vbasedev.name);
+
+ for (i = 0; i < info->count; i++) {
+ VFIOPCIDevice *tmp;
+ VFIODevice *vbasedev_iter;
+
+ trace_vfio_pci_hot_reset_dep_devices_iommufd(devices[i].segment,
+ devices[i].bus,
+ PCI_SLOT(devices[i].devfn),
+ PCI_FUNC(devices[i].devfn),
+ devices[i].devid);
+
+ /*
+ * If a VFIO cdev device is resettable, all the dependent devices
+ * are either bound to same iommufd or within same iommu_groups as
+ * one of the iommufd bound devices.
+ */
+ assert(devices[i].devid != VFIO_PCI_DEVID_NOT_OWNED);
+
+ if (devices[i].devid == vdev->vbasedev.devid ||
+ devices[i].devid == VFIO_PCI_DEVID_OWNED) {
+ continue;
+ }
+
+ vbasedev_iter = vfio_pci_find_by_iommufd_devid(devices[i].devid);
+ if (!vbasedev_iter || !vbasedev_iter->dev->realized ||
+ vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ continue;
+ }
+ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
+ if (single) {
+ ret = -EINVAL;
+ goto out_single;
+ }
+ vfio_pci_pre_reset(tmp);
+ tmp->vbasedev.needs_reset = false;
+ multi = true;
+ }
+
+ if (!single && !multi) {
+ ret = -EINVAL;
+ goto out_single;
+ }
+
+ /* Use zero length array for hot reset with iommufd backend */
+ reset = g_malloc0(sizeof(*reset));
+ reset->argsz = sizeof(*reset);
+
+ /* Bus reset! */
+ ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_PCI_HOT_RESET, reset);
+ g_free(reset);
+
+ trace_vfio_pci_hot_reset_result(vdev->vbasedev.name,
+ ret ? strerror(errno) : "Success");
+
+ /* Re-enable INTx on affected devices */
+ for (i = 0; i < info->count; i++) {
+ VFIOPCIDevice *tmp;
+ VFIODevice *vbasedev_iter;
+
+ if (devices[i].devid == vdev->vbasedev.devid ||
+ devices[i].devid == VFIO_PCI_DEVID_OWNED) {
+ continue;
+ }
+
+ vbasedev_iter = vfio_pci_find_by_iommufd_devid(devices[i].devid);
+ if (!vbasedev_iter || !vbasedev_iter->dev->realized ||
+ vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ continue;
+ }
+ tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
+ vfio_pci_post_reset(tmp);
+ }
+out_single:
+ if (!single) {
+ vfio_pci_post_reset(vdev);
+ }
+ g_free(info);
+
+ return ret;
+}
+
const VFIOIOMMUOps vfio_iommufd_ops = {
.dma_map = iommufd_map,
.dma_unmap = iommufd_unmap,
.attach_device = iommufd_attach_device,
.detach_device = iommufd_detach_device,
+ .pci_hot_reset = iommufd_pci_hot_reset,
};
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index a6194b7bfe..eb662fd086 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2374,7 +2374,7 @@ static int vfio_add_capabilities(VFIOPCIDevice *vdev,
Error **errp)
return 0;
}
-static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
+void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
uint16_t cmd;
@@ -2411,7 +2411,7 @@ static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
}
-static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
+void vfio_pci_post_reset(VFIOPCIDevice *vdev)
{
Error *err = NULL;
int nr;
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index d85342b65f..e88a7d5ccc 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -34,6 +34,7 @@ vfio_check_af_flr(const char *name) "%s Supports FLR via AF
cap"
vfio_pci_hot_reset(const char *name, const char *type) " (%s) %s"
vfio_pci_hot_reset_has_dep_devices(const char *name) "%s: hot reset dependent
devices:"
vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function,
int group_id) "\t%04x:%02x:%02x.%x group %d"
+vfio_pci_hot_reset_dep_devices_iommufd(int domain, int bus, int slot, int
function, int dev_id) "\t%04x:%02x:%02x.%x devid %d"
vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset:
%s"
vfio_populate_device_config(const char *name, unsigned long size, unsigned
long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset:
0x%lx, flags: 0x%lx"
vfio_populate_device_get_irq_info_failure(const char *errstr)
"VFIO_DEVICE_GET_IRQ_INFO failure: %s"
--
2.34.1
- RE: [PATCH v4 28/41] vfio/iommufd: Implement the iommufd backend, (continued)
- [PATCH v4 31/41] vfio/pci: Extract out a helper vfio_pci_get_pci_hot_reset_info, Zhenzhong Duan, 2023/11/02
- [PATCH v4 32/41] vfio/pci: Introduce a vfio pci hot reset interface, Zhenzhong Duan, 2023/11/02
- [PATCH v4 30/41] vfio/iommufd: Add support for iova_ranges, Zhenzhong Duan, 2023/11/02
- [PATCH v4 29/41] vfio/iommufd: Relax assert check for iommufd backend, Zhenzhong Duan, 2023/11/02
- [PATCH v4 33/41] vfio/iommufd: Enable pci hot reset through iommufd cdev interface,
Zhenzhong Duan <=
- [PATCH v4 34/41] vfio/pci: Allow the selection of a given iommu backend, Zhenzhong Duan, 2023/11/02
- [PATCH v4 35/41] vfio/pci: Make vfio cdev pre-openable by passing a file handle, Zhenzhong Duan, 2023/11/02
- [PATCH v4 37/41] vfio/platform: Make vfio cdev pre-openable by passing a file handle, Zhenzhong Duan, 2023/11/02
- [PATCH v4 36/41] vfio: Allow the selection of a given iommu backend for platform ap and ccw, Zhenzhong Duan, 2023/11/02
- [PATCH v4 38/41] vfio/ap: Make vfio cdev pre-openable by passing a file handle, Zhenzhong Duan, 2023/11/02
- [PATCH v4 39/41] vfio/ccw: Make vfio cdev pre-openable by passing a file handle, Zhenzhong Duan, 2023/11/02
- [PATCH v4 40/41] vfio: Make VFIOContainerBase poiner parameter const in VFIOIOMMUOps callbacks, Zhenzhong Duan, 2023/11/02