@@ -1179,10 +1179,15 @@ static int vfio_get_iommu_type(VFIOContainer *container,
return -EINVAL;
}
+static struct HostIOMMUOps vfio_host_icx_ops = {
+/* To be added later */
+};
+
static int vfio_init_container(VFIOContainer *container, int group_fd,
Error **errp)
{
int iommu_type, ret;
+ uint64_t flags = 0;
iommu_type = vfio_get_iommu_type(container, errp);
if (iommu_type < 0) {
@@ -1210,6 +1215,11 @@ static int vfio_init_container(VFIOContainer *container, int group_fd,
return -errno;
}
+ if (iommu_type == VFIO_TYPE1_NESTING_IOMMU) {
+ host_iommu_ctx_init(&container->host_icx,
+ flags, &vfio_host_icx_ops);
+ }
+
container->iommu_type = iommu_type;
return 0;
}
@@ -1456,6 +1466,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
}
trace_vfio_disconnect_container(container->fd);
+ host_iommu_ctx_destroy(&container->host_icx);
close(container->fd);
g_free(container);
@@ -2712,11 +2712,20 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
vdev->req_enabled = false;
}
+static HostIOMMUContext *vfio_host_dma_iommu(PCIDevice *pdev)
+{
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
+ VFIOContainer *container = vdev->vbasedev.group->container;
+
+ return &container->host_icx;
+}
+
static void vfio_realize(PCIDevice *pdev, Error **errp)
{
VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
+ VFIOContainer *container;
char *tmp, *subsys, group_path[PATH_MAX], *group_name;
Error *err = NULL;
ssize_t len;
@@ -3028,6 +3037,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
vfio_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
+ container = vdev->vbasedev.group->container;
+ if (container->host_icx.ops) {
+ pci_device_setup_iommu(pdev, vfio_host_dma_iommu);
+ }
+
return;
out_deregister:
@@ -3072,9 +3086,16 @@ static void vfio_instance_finalize(Object *obj)
static void vfio_exitfn(PCIDevice *pdev)
{
VFIOPCIDevice *vdev = PCI_VFIO(pdev);
+ VFIOContainer *container;
vfio_unregister_req_notifier(vdev);
vfio_unregister_err_notifier(vdev);
+
+ container = vdev->vbasedev.group->container;
+ if (container->host_icx.ops) {
+ pci_device_unset_iommu(pdev);
+ }
+
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
if (vdev->irqchip_change_notifier.notify) {
kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
@@ -26,6 +26,7 @@
#include "qemu/notify.h"
#include "ui/console.h"
#include "hw/display/ramfb.h"
+#include "hw/iommu/host_iommu_context.h"
#ifdef CONFIG_LINUX
#include <linux/vfio.h>
#endif
@@ -71,6 +72,7 @@ typedef struct VFIOContainer {
MemoryListener listener;
MemoryListener prereg_listener;
unsigned iommu_type;
+ HostIOMMUContext host_icx;
Error *error;
bool initialized;
unsigned long pgsizes;
After confirming dual stage DMA translation support with kernel by checking VFIO_TYPE1_NESTING_IOMMU, VFIO inits HostIOMMUContet instance and exposes it to PCI layer. Thus vIOMMU emualtors may make use of such capability by leveraging the ops provided by HostIOMMUContext. Cc: Kevin Tian <kevin.tian@intel.com> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com> Cc: Peter Xu <peterx@redhat.com> Cc: Eric Auger <eric.auger@redhat.com> Cc: Yi Sun <yi.y.sun@linux.intel.com> Cc: David Gibson <david@gibson.dropbear.id.au> Cc: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Liu Yi L <yi.l.liu@intel.com> --- hw/vfio/common.c | 11 +++++++++++ hw/vfio/pci.c | 21 +++++++++++++++++++++ include/hw/vfio/vfio-common.h | 2 ++ 3 files changed, 34 insertions(+)