From: Jean-Philippe Brucker <[email protected]> Support devices that are attached to a CPU and perform DMA through a MMU. They do not have an IOMMU and do not use a VFIO container. The VMM needs device-specific knowledge in order to create a virtual device (device tree, ACPI tables), so it also knows not to allocate a container.
Signed-off-by: Jean-Philippe Brucker <[email protected]> --- drivers/vfio/group.c | 37 +++++++++++++++++++++++++++++-------- drivers/vfio/vfio.h | 5 +++++ drivers/vfio/vfio_main.c | 16 +++++++++++++++- include/linux/vfio.h | 1 + 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c index b2299e5bc6df..99d85880a41c 100644 --- a/drivers/vfio/group.c +++ b/drivers/vfio/group.c @@ -120,7 +120,7 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group, return -EBADF; mutex_lock(&group->group_lock); - if (vfio_group_has_iommu(group)) { + if (vfio_group_has_iommu(group) || group->type == VFIO_CPU_MMU) { ret = -EINVAL; goto out_unlock; } @@ -173,7 +173,8 @@ static int vfio_df_group_open(struct vfio_device_file *df) int ret; mutex_lock(&device->group->group_lock); - if (!vfio_group_has_iommu(device->group)) { + if (!vfio_group_has_iommu(device->group) && + device->group->type != VFIO_CPU_MMU) { ret = -EINVAL; goto out_unlock; } @@ -635,7 +636,8 @@ static bool vfio_group_has_device(struct vfio_group *group, struct device *dev) return false; } -static struct vfio_group *vfio_group_find_or_alloc(struct device *dev) +static struct vfio_group *vfio_group_find_or_alloc(struct device *dev, + enum vfio_group_type type) { struct iommu_group *iommu_group; struct vfio_group *group; @@ -662,12 +664,13 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev) mutex_lock(&vfio.group_lock); group = vfio_group_find_from_iommu(iommu_group); if (group) { - if (WARN_ON(vfio_group_has_device(group, dev))) + if (WARN_ON(vfio_group_has_device(group, dev)) || + WARN_ON(group->type != type)) group = ERR_PTR(-EINVAL); else refcount_inc(&group->drivers); } else { - group = vfio_create_group(iommu_group, VFIO_IOMMU); + group = vfio_create_group(iommu_group, type); } mutex_unlock(&vfio.group_lock); @@ -681,10 +684,18 @@ int vfio_device_set_group(struct vfio_device *device, { struct vfio_group *group; - if (type == VFIO_IOMMU) - group = vfio_group_find_or_alloc(device->dev); - else + switch (type) { + case VFIO_IOMMU: + case VFIO_CPU_MMU: + group = vfio_group_find_or_alloc(device->dev, type); + break; + case VFIO_EMULATED_IOMMU: + case VFIO_NO_IOMMU: group = vfio_noiommu_group_alloc(device->dev, type); + break; + default: + group = ERR_PTR(-EINVAL); + } if (IS_ERR(group)) return PTR_ERR(group); @@ -761,6 +772,11 @@ int vfio_device_group_use_iommu(struct vfio_device *device) lockdep_assert_held(&group->group_lock); + if (group->type == VFIO_CPU_MMU) { + get_file(group->opened_file); + return 0; + } + if (WARN_ON(!group->container)) return -EINVAL; @@ -777,6 +793,11 @@ void vfio_device_group_unuse_iommu(struct vfio_device *device) lockdep_assert_held(&group->group_lock); + if (group->type == VFIO_CPU_MMU) { + fput(group->opened_file); + return; + } + if (WARN_ON(!group->container)) return; diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h index 7728bc99b63d..07c5223612d3 100644 --- a/drivers/vfio/vfio.h +++ b/drivers/vfio/vfio.h @@ -64,6 +64,11 @@ enum vfio_group_type { * taint the kernel. */ VFIO_NO_IOMMU, + + /* + * Physical devices using the CPU MMU + */ + VFIO_CPU_MMU, }; #if IS_ENABLED(CONFIG_VFIO_GROUP) diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 423ead48aafe..41fee81a14cb 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -344,7 +344,8 @@ static int __vfio_register_dev(struct vfio_device *device, { int ret; - if (WARN_ON(IS_ENABLED(CONFIG_IOMMUFD) && + if (type != VFIO_CPU_MMU && + WARN_ON(IS_ENABLED(CONFIG_IOMMUFD) && (!device->ops->bind_iommufd || !device->ops->unbind_iommufd || !device->ops->attach_ioas || @@ -415,6 +416,19 @@ int vfio_register_emulated_iommu_dev(struct vfio_device *device) } EXPORT_SYMBOL_GPL(vfio_register_emulated_iommu_dev); +/* + * Register a devices that accesses memory through the CPU MMU. Although it + * doesn't use an IOMMU, the device must have an IOMMU group. + */ +int vfio_register_cpu_mmu_dev(struct vfio_device *device) +{ + if (!IS_ENABLED(CONFIG_VFIO_GROUP)) + return -EOPNOTSUPP; + + return __vfio_register_dev(device, VFIO_CPU_MMU); +} +EXPORT_SYMBOL_GPL(vfio_register_cpu_mmu_dev); + /* * Decrement the device reference count and wait for the device to be * removed. Open file descriptors for the device... */ diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 45f08986359e..7d3a5ff1ad00 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -337,6 +337,7 @@ static inline void vfio_put_device(struct vfio_device *device) put_device(&device->device); } +int vfio_register_cpu_mmu_dev(struct vfio_device *device); int vfio_register_group_dev(struct vfio_device *device); int vfio_register_emulated_iommu_dev(struct vfio_device *device); void vfio_unregister_group_dev(struct vfio_device *device); -- 2.43.0
