diff options
author | Jason Gunthorpe <jgg@nvidia.com> | 2023-03-31 19:43:57 +0300 |
---|---|---|
committer | Jason Gunthorpe <jgg@nvidia.com> | 2023-03-31 19:43:57 +0300 |
commit | 9fdf791612866da2ae09930774fe5c8604962691 (patch) | |
tree | 360227082d1fe3e356dd208eeaccbb32e128b183 | |
parent | fd8c1a4aee973e87d890a5861e106625a33b2c4e (diff) | |
parent | 7d12578c5d508050554bcd9ca3d2331914d86d71 (diff) | |
download | linux-9fdf791612866da2ae09930774fe5c8604962691.tar.xz |
Merge branch 'vfio_mdev_ops' into iommufd.git for-next
Yi Liu says
===================
The .bind_iommufd op of vfio emulated devices are either empty or does
nothing. This is different with the vfio physical devices, to add vfio
device cdev, need to make them act the same.
This series first makes the .bind_iommufd op of vfio emulated devices to
create iommufd_access, this introduces a new iommufd API. Then let the
driver that does not provide .bind_iommufd op to use the vfio emulated
iommufd op set. This makes all vfio device drivers have consistent iommufd
operations, which is good for adding new device uAPIs in the device cdev
===================
* branch 'vfio_mdev_ops':
vfio: Check the presence for iommufd callbacks in __vfio_register_dev()
vfio/mdev: Uses the vfio emulated iommufd ops set in the mdev sample drivers
vfio-iommufd: Make vfio_iommufd_emulated_bind() return iommufd_access ID
vfio-iommufd: No need to record iommufd_ctx in vfio_device
iommufd: Create access in vfio_iommufd_emulated_bind()
iommu/iommufd: Pass iommufd_ctx pointer in iommufd_get_ioas()
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
-rw-r--r-- | drivers/iommu/iommufd/device.c | 56 | ||||
-rw-r--r-- | drivers/iommu/iommufd/ioas.c | 14 | ||||
-rw-r--r-- | drivers/iommu/iommufd/iommufd_private.h | 4 | ||||
-rw-r--r-- | drivers/iommu/iommufd/selftest.c | 12 | ||||
-rw-r--r-- | drivers/iommu/iommufd/vfio_compat.c | 2 | ||||
-rw-r--r-- | drivers/vfio/iommufd.c | 37 | ||||
-rw-r--r-- | drivers/vfio/vfio_main.c | 5 | ||||
-rw-r--r-- | include/linux/iommufd.h | 5 | ||||
-rw-r--r-- | include/linux/vfio.h | 1 | ||||
-rw-r--r-- | samples/vfio-mdev/mbochs.c | 3 | ||||
-rw-r--r-- | samples/vfio-mdev/mdpy.c | 3 | ||||
-rw-r--r-- | samples/vfio-mdev/mtty.c | 3 |
12 files changed, 84 insertions, 61 deletions
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index c6f4852a8a0c..4f9b2142274c 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -395,17 +395,20 @@ void iommufd_access_destroy_object(struct iommufd_object *obj) struct iommufd_access *access = container_of(obj, struct iommufd_access, obj); - iopt_remove_access(&access->ioas->iopt, access); + if (access->ioas) { + iopt_remove_access(&access->ioas->iopt, access); + refcount_dec(&access->ioas->obj.users); + access->ioas = NULL; + } iommufd_ctx_put(access->ictx); - refcount_dec(&access->ioas->obj.users); } /** * iommufd_access_create - Create an iommufd_access * @ictx: iommufd file descriptor - * @ioas_id: ID for a IOMMUFD_OBJ_IOAS * @ops: Driver's ops to associate with the access * @data: Opaque data to pass into ops functions + * @id: Output ID number to return to userspace for this access * * An iommufd_access allows a driver to read/write to the IOAS without using * DMA. The underlying CPU memory can be accessed using the @@ -414,12 +417,10 @@ void iommufd_access_destroy_object(struct iommufd_object *obj) * The provided ops are required to use iommufd_access_pin_pages(). */ struct iommufd_access * -iommufd_access_create(struct iommufd_ctx *ictx, u32 ioas_id, - const struct iommufd_access_ops *ops, void *data) +iommufd_access_create(struct iommufd_ctx *ictx, + const struct iommufd_access_ops *ops, void *data, u32 *id) { struct iommufd_access *access; - struct iommufd_object *obj; - int rc; /* * There is no uAPI for the access object, but to keep things symmetric @@ -432,33 +433,18 @@ iommufd_access_create(struct iommufd_ctx *ictx, u32 ioas_id, access->data = data; access->ops = ops; - obj = iommufd_get_object(ictx, ioas_id, IOMMUFD_OBJ_IOAS); - if (IS_ERR(obj)) { - rc = PTR_ERR(obj); - goto out_abort; - } - access->ioas = container_of(obj, struct iommufd_ioas, obj); - iommufd_ref_to_users(obj); - if (ops->needs_pin_pages) access->iova_alignment = PAGE_SIZE; else access->iova_alignment = 1; - rc = iopt_add_access(&access->ioas->iopt, access); - if (rc) - goto out_put_ioas; /* The calling driver is a user until iommufd_access_destroy() */ refcount_inc(&access->obj.users); access->ictx = ictx; iommufd_ctx_get(ictx); iommufd_object_finalize(ictx, &access->obj); + *id = access->obj.id; return access; -out_put_ioas: - refcount_dec(&access->ioas->obj.users); -out_abort: - iommufd_object_abort(ictx, &access->obj); - return ERR_PTR(rc); } EXPORT_SYMBOL_NS_GPL(iommufd_access_create, IOMMUFD); @@ -477,6 +463,30 @@ void iommufd_access_destroy(struct iommufd_access *access) } EXPORT_SYMBOL_NS_GPL(iommufd_access_destroy, IOMMUFD); +int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id) +{ + struct iommufd_ioas *new_ioas; + int rc = 0; + + if (access->ioas) + return -EINVAL; + + new_ioas = iommufd_get_ioas(access->ictx, ioas_id); + if (IS_ERR(new_ioas)) + return PTR_ERR(new_ioas); + + rc = iopt_add_access(&new_ioas->iopt, access); + if (rc) { + iommufd_put_object(&new_ioas->obj); + return rc; + } + iommufd_ref_to_users(&new_ioas->obj); + + access->ioas = new_ioas; + return 0; +} +EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, IOMMUFD); + /** * iommufd_access_notify_unmap - Notify users of an iopt to stop using it * @iopt: iopt to work on diff --git a/drivers/iommu/iommufd/ioas.c b/drivers/iommu/iommufd/ioas.c index 31577e9d434f..d5624577f79f 100644 --- a/drivers/iommu/iommufd/ioas.c +++ b/drivers/iommu/iommufd/ioas.c @@ -71,7 +71,7 @@ int iommufd_ioas_iova_ranges(struct iommufd_ucmd *ucmd) if (cmd->__reserved) return -EOPNOTSUPP; - ioas = iommufd_get_ioas(ucmd, cmd->ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); @@ -151,7 +151,7 @@ int iommufd_ioas_allow_iovas(struct iommufd_ucmd *ucmd) if (cmd->__reserved) return -EOPNOTSUPP; - ioas = iommufd_get_ioas(ucmd, cmd->ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); iopt = &ioas->iopt; @@ -213,7 +213,7 @@ int iommufd_ioas_map(struct iommufd_ucmd *ucmd) if (cmd->iova >= ULONG_MAX || cmd->length >= ULONG_MAX) return -EOVERFLOW; - ioas = iommufd_get_ioas(ucmd, cmd->ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); @@ -253,7 +253,7 @@ int iommufd_ioas_copy(struct iommufd_ucmd *ucmd) cmd->dst_iova >= ULONG_MAX) return -EOVERFLOW; - src_ioas = iommufd_get_ioas(ucmd, cmd->src_ioas_id); + src_ioas = iommufd_get_ioas(ucmd->ictx, cmd->src_ioas_id); if (IS_ERR(src_ioas)) return PTR_ERR(src_ioas); rc = iopt_get_pages(&src_ioas->iopt, cmd->src_iova, cmd->length, @@ -262,7 +262,7 @@ int iommufd_ioas_copy(struct iommufd_ucmd *ucmd) if (rc) return rc; - dst_ioas = iommufd_get_ioas(ucmd, cmd->dst_ioas_id); + dst_ioas = iommufd_get_ioas(ucmd->ictx, cmd->dst_ioas_id); if (IS_ERR(dst_ioas)) { rc = PTR_ERR(dst_ioas); goto out_pages; @@ -292,7 +292,7 @@ int iommufd_ioas_unmap(struct iommufd_ucmd *ucmd) unsigned long unmapped = 0; int rc; - ioas = iommufd_get_ioas(ucmd, cmd->ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); @@ -381,7 +381,7 @@ int iommufd_ioas_option(struct iommufd_ucmd *ucmd) if (cmd->__reserved) return -EOPNOTSUPP; - ioas = iommufd_get_ioas(ucmd, cmd->object_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->object_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h index d523ef12890e..b38e67d1988b 100644 --- a/drivers/iommu/iommufd/iommufd_private.h +++ b/drivers/iommu/iommufd/iommufd_private.h @@ -212,10 +212,10 @@ struct iommufd_ioas { struct list_head hwpt_list; }; -static inline struct iommufd_ioas *iommufd_get_ioas(struct iommufd_ucmd *ucmd, +static inline struct iommufd_ioas *iommufd_get_ioas(struct iommufd_ctx *ictx, u32 id) { - return container_of(iommufd_get_object(ucmd->ictx, id, + return container_of(iommufd_get_object(ictx, id, IOMMUFD_OBJ_IOAS), struct iommufd_ioas, obj); } diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index 58471f9452be..4463060ec84b 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -75,7 +75,7 @@ void iommufd_test_syz_conv_iova_id(struct iommufd_ucmd *ucmd, return; *flags &= ~(u32)MOCK_FLAGS_ACCESS_SYZ; - ioas = iommufd_get_ioas(ucmd, ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, ioas_id); if (IS_ERR(ioas)) return; *iova = iommufd_test_syz_conv_iova(&ioas->iopt, iova); @@ -463,7 +463,7 @@ static int iommufd_test_add_reserved(struct iommufd_ucmd *ucmd, struct iommufd_ioas *ioas; int rc; - ioas = iommufd_get_ioas(ucmd, mockpt_id); + ioas = iommufd_get_ioas(ucmd->ictx, mockpt_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); down_write(&ioas->iopt.iova_rwsem); @@ -700,6 +700,7 @@ static int iommufd_test_create_access(struct iommufd_ucmd *ucmd, struct iommu_test_cmd *cmd = ucmd->cmd; struct selftest_access *staccess; struct iommufd_access *access; + u32 id; int fdno; int rc; @@ -717,15 +718,18 @@ static int iommufd_test_create_access(struct iommufd_ucmd *ucmd, } access = iommufd_access_create( - ucmd->ictx, ioas_id, + ucmd->ictx, (flags & MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES) ? &selftest_access_ops_pin : &selftest_access_ops, - staccess); + staccess, &id); if (IS_ERR(access)) { rc = PTR_ERR(access); goto out_put_fdno; } + rc = iommufd_access_attach(access, ioas_id); + if (rc) + goto out_destroy; cmd->create_access.out_access_fd = fdno; rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); if (rc) diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c index 514494a0025b..fe02517c73cc 100644 --- a/drivers/iommu/iommufd/vfio_compat.c +++ b/drivers/iommu/iommufd/vfio_compat.c @@ -137,7 +137,7 @@ int iommufd_vfio_ioas(struct iommufd_ucmd *ucmd) return iommufd_ucmd_respond(ucmd, sizeof(*cmd)); case IOMMU_VFIO_IOAS_SET: - ioas = iommufd_get_ioas(ucmd, cmd->ioas_id); + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); if (IS_ERR(ioas)) return PTR_ERR(ioas); xa_lock(&ucmd->ictx->objects); diff --git a/drivers/vfio/iommufd.c b/drivers/vfio/iommufd.c index db4efbd56042..88b00c501015 100644 --- a/drivers/vfio/iommufd.c +++ b/drivers/vfio/iommufd.c @@ -32,13 +32,6 @@ int vfio_iommufd_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx) return 0; } - /* - * 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; @@ -119,7 +112,8 @@ EXPORT_SYMBOL_GPL(vfio_iommufd_physical_attach_ioas); /* * The emulated standard ops mean that vfio_device is going to use the * "mdev path" and will call vfio_pin_pages()/vfio_dma_rw(). Drivers using this - * ops set should call vfio_register_emulated_iommu_dev(). + * ops set should call vfio_register_emulated_iommu_dev(). Drivers that do + * not call vfio_pin_pages()/vfio_dma_rw() have no need to provide dma_unmap. */ static void vfio_emulated_unmap(void *data, unsigned long iova, @@ -127,7 +121,8 @@ static void vfio_emulated_unmap(void *data, unsigned long iova, { struct vfio_device *vdev = data; - vdev->ops->dma_unmap(vdev, iova, length); + if (vdev->ops->dma_unmap) + vdev->ops->dma_unmap(vdev, iova, length); } static const struct iommufd_access_ops vfio_user_ops = { @@ -138,10 +133,14 @@ static const struct iommufd_access_ops vfio_user_ops = { int vfio_iommufd_emulated_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx, u32 *out_device_id) { + struct iommufd_access *user; + lockdep_assert_held(&vdev->dev_set->lock); - vdev->iommufd_ictx = ictx; - iommufd_ctx_get(ictx); + user = iommufd_access_create(ictx, &vfio_user_ops, vdev, out_device_id); + if (IS_ERR(user)) + return PTR_ERR(user); + vdev->iommufd_access = user; return 0; } EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_bind); @@ -152,24 +151,24 @@ void vfio_iommufd_emulated_unbind(struct vfio_device *vdev) if (vdev->iommufd_access) { iommufd_access_destroy(vdev->iommufd_access); + vdev->iommufd_attached = false; vdev->iommufd_access = NULL; } - iommufd_ctx_put(vdev->iommufd_ictx); - vdev->iommufd_ictx = NULL; } EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_unbind); int vfio_iommufd_emulated_attach_ioas(struct vfio_device *vdev, u32 *pt_id) { - struct iommufd_access *user; + int rc; lockdep_assert_held(&vdev->dev_set->lock); - user = iommufd_access_create(vdev->iommufd_ictx, *pt_id, &vfio_user_ops, - vdev); - if (IS_ERR(user)) - return PTR_ERR(user); - vdev->iommufd_access = user; + if (vdev->iommufd_attached) + return -EBUSY; + rc = iommufd_access_attach(vdev->iommufd_access, *pt_id); + if (rc) + return rc; + vdev->iommufd_attached = true; return 0; } EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_attach_ioas); diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 43bd6b76e2b6..89497c933490 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -255,8 +255,9 @@ static int __vfio_register_dev(struct vfio_device *device, { int ret; - if (WARN_ON(device->ops->bind_iommufd && - (!device->ops->unbind_iommufd || + if (WARN_ON(IS_ENABLED(CONFIG_IOMMUFD) && + (!device->ops->bind_iommufd || + !device->ops->unbind_iommufd || !device->ops->attach_ioas))) return -EINVAL; diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h index c0b5b3ac34f1..1129a36a74c4 100644 --- a/include/linux/iommufd.h +++ b/include/linux/iommufd.h @@ -40,9 +40,10 @@ enum { }; struct iommufd_access * -iommufd_access_create(struct iommufd_ctx *ictx, u32 ioas_id, - const struct iommufd_access_ops *ops, void *data); +iommufd_access_create(struct iommufd_ctx *ictx, + const struct iommufd_access_ops *ops, void *data, u32 *id); void iommufd_access_destroy(struct iommufd_access *access); +int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id); void iommufd_ctx_get(struct iommufd_ctx *ictx); diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 93134b023968..3188d8a374bd 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -60,7 +60,6 @@ struct vfio_device { void (*put_kvm)(struct kvm *kvm); #if IS_ENABLED(CONFIG_IOMMUFD) struct iommufd_device *iommufd_device; - struct iommufd_ctx *iommufd_ictx; bool iommufd_attached; #endif }; diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index e54eb752e1ba..19391dda5fba 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -1374,6 +1374,9 @@ static const struct vfio_device_ops mbochs_dev_ops = { .write = mbochs_write, .ioctl = mbochs_ioctl, .mmap = mbochs_mmap, + .bind_iommufd = vfio_iommufd_emulated_bind, + .unbind_iommufd = vfio_iommufd_emulated_unbind, + .attach_ioas = vfio_iommufd_emulated_attach_ioas, }; static struct mdev_driver mbochs_driver = { diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index e8400fdab71d..5f48aef36995 100644 --- a/samples/vfio-mdev/mdpy.c +++ b/samples/vfio-mdev/mdpy.c @@ -663,6 +663,9 @@ static const struct vfio_device_ops mdpy_dev_ops = { .write = mdpy_write, .ioctl = mdpy_ioctl, .mmap = mdpy_mmap, + .bind_iommufd = vfio_iommufd_emulated_bind, + .unbind_iommufd = vfio_iommufd_emulated_unbind, + .attach_ioas = vfio_iommufd_emulated_attach_ioas, }; static struct mdev_driver mdpy_driver = { diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index e887de672c52..35460901b9f7 100644 --- a/samples/vfio-mdev/mtty.c +++ b/samples/vfio-mdev/mtty.c @@ -1269,6 +1269,9 @@ static const struct vfio_device_ops mtty_dev_ops = { .read = mtty_read, .write = mtty_write, .ioctl = mtty_ioctl, + .bind_iommufd = vfio_iommufd_emulated_bind, + .unbind_iommufd = vfio_iommufd_emulated_unbind, + .attach_ioas = vfio_iommufd_emulated_attach_ioas, }; static struct mdev_driver mtty_driver = { |