Commit a4d1f91d authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

vfio-iommufd: Support iommufd for physical VFIO devices

This creates the iommufd_device for the physical VFIO drivers. These are
all the drivers that are calling vfio_register_group_dev() and expect the
type1 code to setup a real iommu_domain against their parent struct
device.

The design gives the driver a choice in how it gets connected to iommufd
by providing bind_iommufd/unbind_iommufd/attach_ioas callbacks to
implement as required. The core code provides three default callbacks for
physical mode using a real iommu_domain. This is suitable for drivers
using vfio_register_group_dev()

Link: https://lore.kernel.org/r/6-v4-42cd2eb0e3eb+335a-vfio_iommufd_jgg@nvidia.com


Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Tested-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarYi Liu <yi.l.liu@intel.com>
Tested-by: default avatarLixiao Yang <lixiao.yang@intel.com>
Tested-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Tested-by: default avatarYu He <yu.he@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 2a3dab19
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ obj-$(CONFIG_VFIO) += vfio.o
vfio-y += vfio_main.o \
	  iova_bitmap.o \
	  container.o
vfio-$(CONFIG_IOMMUFD) += iommufd.o

obj-$(CONFIG_VFIO_VIRQFD) += vfio_virqfd.o
obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
+3 −0
Original line number Diff line number Diff line
@@ -592,6 +592,9 @@ static const struct vfio_device_ops vfio_fsl_mc_ops = {
	.read		= vfio_fsl_mc_read,
	.write		= vfio_fsl_mc_write,
	.mmap		= vfio_fsl_mc_mmap,
	.bind_iommufd	= vfio_iommufd_physical_bind,
	.unbind_iommufd	= vfio_iommufd_physical_unbind,
	.attach_ioas	= vfio_iommufd_physical_attach_ioas,
};

static struct fsl_mc_driver vfio_fsl_mc_driver = {

drivers/vfio/iommufd.c

0 → 100644
+100 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
 */
#include <linux/vfio.h>
#include <linux/iommufd.h>

#include "vfio.h"

MODULE_IMPORT_NS(IOMMUFD);
MODULE_IMPORT_NS(IOMMUFD_VFIO);

int vfio_iommufd_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx)
{
	u32 ioas_id;
	u32 device_id;
	int ret;

	lockdep_assert_held(&vdev->dev_set->lock);

	/*
	 * If the driver doesn't provide this op then it means the device does
	 * not do DMA at all. So nothing to do.
	 */
	if (!vdev->ops->bind_iommufd)
		return 0;

	ret = vdev->ops->bind_iommufd(vdev, ictx, &device_id);
	if (ret)
		return ret;

	ret = iommufd_vfio_compat_ioas_id(ictx, &ioas_id);
	if (ret)
		goto err_unbind;
	ret = vdev->ops->attach_ioas(vdev, &ioas_id);
	if (ret)
		goto err_unbind;

	/*
	 * The legacy path has no way to return the device id or the selected
	 * pt_id
	 */
	return 0;

err_unbind:
	if (vdev->ops->unbind_iommufd)
		vdev->ops->unbind_iommufd(vdev);
	return ret;
}

void vfio_iommufd_unbind(struct vfio_device *vdev)
{
	lockdep_assert_held(&vdev->dev_set->lock);

	if (vdev->ops->unbind_iommufd)
		vdev->ops->unbind_iommufd(vdev);
}

/*
 * The physical standard ops mean that the iommufd_device is bound to the
 * physical device vdev->dev that was provided to vfio_init_group_dev(). Drivers
 * using this ops set should call vfio_register_group_dev()
 */
int vfio_iommufd_physical_bind(struct vfio_device *vdev,
			       struct iommufd_ctx *ictx, u32 *out_device_id)
{
	struct iommufd_device *idev;

	idev = iommufd_device_bind(ictx, vdev->dev, out_device_id);
	if (IS_ERR(idev))
		return PTR_ERR(idev);
	vdev->iommufd_device = idev;
	return 0;
}
EXPORT_SYMBOL_GPL(vfio_iommufd_physical_bind);

void vfio_iommufd_physical_unbind(struct vfio_device *vdev)
{
	lockdep_assert_held(&vdev->dev_set->lock);

	if (vdev->iommufd_attached) {
		iommufd_device_detach(vdev->iommufd_device);
		vdev->iommufd_attached = false;
	}
	iommufd_device_unbind(vdev->iommufd_device);
	vdev->iommufd_device = NULL;
}
EXPORT_SYMBOL_GPL(vfio_iommufd_physical_unbind);

int vfio_iommufd_physical_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
{
	int rc;

	rc = iommufd_device_attach(vdev->iommufd_device, pt_id);
	if (rc)
		return rc;
	vdev->iommufd_attached = true;
	return 0;
}
EXPORT_SYMBOL_GPL(vfio_iommufd_physical_attach_ioas);
+6 −0
Original line number Diff line number Diff line
@@ -1246,6 +1246,9 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
	.mmap = hisi_acc_vfio_pci_mmap,
	.request = vfio_pci_core_request,
	.match = vfio_pci_core_match,
	.bind_iommufd = vfio_iommufd_physical_bind,
	.unbind_iommufd = vfio_iommufd_physical_unbind,
	.attach_ioas = vfio_iommufd_physical_attach_ioas,
};

static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
@@ -1261,6 +1264,9 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
	.mmap = vfio_pci_core_mmap,
	.request = vfio_pci_core_request,
	.match = vfio_pci_core_match,
	.bind_iommufd = vfio_iommufd_physical_bind,
	.unbind_iommufd = vfio_iommufd_physical_unbind,
	.attach_ioas = vfio_iommufd_physical_attach_ioas,
};

static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+3 −0
Original line number Diff line number Diff line
@@ -623,6 +623,9 @@ static const struct vfio_device_ops mlx5vf_pci_ops = {
	.mmap = vfio_pci_core_mmap,
	.request = vfio_pci_core_request,
	.match = vfio_pci_core_match,
	.bind_iommufd = vfio_iommufd_physical_bind,
	.unbind_iommufd = vfio_iommufd_physical_unbind,
	.attach_ioas = vfio_iommufd_physical_attach_ioas,
};

static int mlx5vf_pci_probe(struct pci_dev *pdev,
Loading