Add Tegra241 (Grace) CMDQV Support (part 2/2)
Subsystems (6)
cover Add Tegra241 (Grace) CMDQV Support (part 2/2)
This is an experimental RFC series for VIOMMU infrastructure, using NVIDIA Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed by an underlying IOMMU's HW-accelerated feature for virtualizaion: for example, NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
VQUEUE obj is used to represent a virtual command queue (buffer) backed by an underlying IOMMU command queue to passthrough for VMs to use directly:
for example, NVIDIA's Virtual Command Queue and AMD's Command Buffer.
NVIDIA's CMDQV requires a pair of physical and virtual device Stream IDs to process ATC invalidation commands by ARM SMMU. So, set/unset_dev_id ops and ioctls are introduced to VIOMMU.
Also, a passthrough queue has a pair of start and tail pointers/indexes in the real HW registers, which should be mmaped to user space for hypervisor to map to VM's mmio region directly. Thus, iommufd needs an mmap op too.
Some todos/opens:
1. Add selftest coverages for new ioctls
2. The mmap needs a way to get viommu_id. Currently it's getting from vma->vm_pgoff, which might not be ideal.
3. This series is only verified with a single passthrough device that's hehind a physical ARM SMMU. So, devices behind two+ IOMMUs might need some additional support (and verifications).
4. Requires for comments from AMD folks to support AMD's vIOMMU feature.
This series is on Github (for review and reference only):
https://github.com/nicolinc/iommufd/commits/vcmdq_user_space-rfc-v1
Real HW tests wre conducted with this QEMU branch:
https://github.com/nicolinc/qemu/commits/wip/iommufd_vcmdq/
Thanks
Nicolin Chen (14):
iommufd: Move iommufd_object to public iommufd header
iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
iommufd: Prepare for viommu structures and functions
iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC iommufd/selftest: Add IOMMU_VIOMMU_ALLOC test coverage
iommufd: Add viommu set/unset_dev_id ops
iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl iommufd/selftest: Add IOMMU_VIOMMU_SET_DEV_ID test coverage iommufd/selftest: Add IOMMU_TEST_OP_MV_CHECK_DEV_ID
iommufd: Add struct iommufd_vqueue and its related viommu ops
iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
iommufd: Add mmap infrastructure iommu/tegra241-cmdqv: Add user-space use support
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 ++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 19 ++ .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 284 +++++++++++++++++- drivers/iommu/iommufd/Makefile | 3 +- drivers/iommu/iommufd/device.c | 11 + drivers/iommu/iommufd/hw_pagetable.c | 4 +- drivers/iommu/iommufd/iommufd_private.h | 71 +++-- drivers/iommu/iommufd/iommufd_test.h | 5 + drivers/iommu/iommufd/main.c | 69 ++++- drivers/iommu/iommufd/selftest.c | 100 ++++++ drivers/iommu/iommufd/viommu.c | 235 +++++++++++++++ include/linux/iommu.h | 16 + include/linux/iommufd.h | 100 ++++++ include/uapi/linux/iommufd.h | 98 ++++++ tools/testing/selftests/iommu/iommufd.c | 44 +++ tools/testing/selftests/iommu/iommufd_utils.h | 71 +++++ 16 files changed, 1103 insertions(+), 46 deletions(-) create mode 100644 drivers/iommu/iommufd/viommu.c
Signature · 1 line
2.43.0
RFC PATCH 1/14 iommufd: Move iommufd_object to public iommufd header
To prepare for a new public iommufd_viommu structure that will be an embedded object in a driver's viommu structure:
// include/linux/iommufd.h
struct iommufd_viommu {
struct iommufd_object obj;
....
};
// Some IOMMU driver
struct iommu_driver_viommu {
struct iommufd_viommu core;
....
};Move iommufd_object and iommufd_object_type to the public header.
--- drivers/iommu/iommufd/iommufd_private.h | 24 +----------------------- include/linux/iommufd.h | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-)
drivers/iommu/iommufd/iommufd_private.h +1 -23
@@ -6,9 +6,9 @@#include <linux/rwsem.h> #include <linux/xarray.h> -#include <linux/refcount.h> #include <linux/uaccess.h> #include <linux/iommu.h> +#include <linux/iommufd.h> #include <linux/iova_bitmap.h> #include <uapi/linux/iommufd.h>
@@ -120,28 +120,6 @@ static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd,return 0 ; } -enum iommufd_object_type { -IOMMUFD_OBJ_NONE , -IOMMUFD_OBJ_ANY =IOMMUFD_OBJ_NONE , -IOMMUFD_OBJ_DEVICE , -IOMMUFD_OBJ_HWPT_PAGING , -IOMMUFD_OBJ_HWPT_NESTED , -IOMMUFD_OBJ_IOAS , -IOMMUFD_OBJ_ACCESS , -#ifdef CONFIG_IOMMUFD_TEST -IOMMUFD_OBJ_SELFTEST , -#endif -IOMMUFD_OBJ_MAX , -}; - -/* Base struct for all objects with a userspace ID handle. */ -struct iommufd_object { -refcount_t shortterm_users; -refcount_t users; -enum iommufd_object_type type; -unsigned int id; -}; -static inline bool iommufd_lock_obj (struct iommufd_object *obj) {if (!refcount_inc_not_zero (&obj->users))
include/linux/iommufd.h +23 -0
@@ -9,6 +9,7 @@#include <linux/types.h> #include <linux/errno.h> #include <linux/err.h> +#include <linux/refcount.h> struct device ;struct iommufd_device ;
@@ -18,6 +19,28 @@ struct iommufd_access;struct file ;struct iommu_group ; +enum iommufd_object_type { +IOMMUFD_OBJ_NONE , +IOMMUFD_OBJ_ANY =IOMMUFD_OBJ_NONE , +IOMMUFD_OBJ_DEVICE , +IOMMUFD_OBJ_HWPT_PAGING , +IOMMUFD_OBJ_HWPT_NESTED , +IOMMUFD_OBJ_IOAS , +IOMMUFD_OBJ_ACCESS , +#ifdef CONFIG_IOMMUFD_TEST +IOMMUFD_OBJ_SELFTEST , +#endif +IOMMUFD_OBJ_MAX , +}; + +/* Base struct for all objects with a userspace ID handle. */ +struct iommufd_object { +refcount_t shortterm_users; +refcount_t users; +enum iommufd_object_type type; +unsigned int id; +}; +struct iommufd_device *iommufd_device_bind (struct iommufd_ctx *ictx,struct device *dev,u32 *id);void iommufd_device_unbind (struct iommufd_device *idev);
Signature · 1 line
2.43.0
Re: [PATCH RFCv1 01/14] iommufd: Move iommufd_object to public iommufd header
Quoted 19 lines · Nicolin Chen
include/linux/iommufd.h +4
-0@@ -9,6 +9,7 @@#include <linux/types.h> #include <linux/errno.h> #include <linux/err.h> +#include <linux/refcount.h> struct device ;struct iommufd_device ;@@ -18,6 +19,28 @@ struct iommufd_access;struct file ;struct iommu_group ; +enum iommufd_object_type { +IOMMUFD_OBJ_NONE , +IOMMUFD_OBJ_ANY =IOMMUFD_OBJ_NONE ,
include/linux/iommufd.h struct iommufd_access; · line 34
Quoted 10 lines
include/linux/iommufd.h +10
-0+IOMMUFD_OBJ_DEVICE , +IOMMUFD_OBJ_HWPT_PAGING , +IOMMUFD_OBJ_HWPT_NESTED , +IOMMUFD_OBJ_IOAS , +IOMMUFD_OBJ_ACCESS , +#ifdef CONFIG_IOMMUFD_TEST +IOMMUFD_OBJ_SELFTEST , +#endif + IOMMUFD_OBJ_MAX, +};
Can we just forward declare the enum? It would be nice to keep it in the private header
Otherwise makes sense
Jason
Re: [PATCH RFCv1 01/14] iommufd: Move iommufd_object to public iommufd header
Quoted 10 lines · Jason Gunthorpe
Quoted 9 lines · Nicolin Chen
include/linux/iommufd.h +8
-0+enum iommufd_object_type { +IOMMUFD_OBJ_NONE , +IOMMUFD_OBJ_ANY =IOMMUFD_OBJ_NONE , +IOMMUFD_OBJ_DEVICE , +IOMMUFD_OBJ_HWPT_PAGING , +IOMMUFD_OBJ_HWPT_NESTED , +IOMMUFD_OBJ_IOAS , +IOMMUFD_OBJ_ACCESS ,
Quoted 8 lines
include/linux/iommufd.h struct iommufd_access; · line 34
Quoted 5 lines
include/linux/iommufd.h +5
-0+#ifdef CONFIG_IOMMUFD_TEST +IOMMUFD_OBJ_SELFTEST , +#endif + IOMMUFD_OBJ_MAX, +};Can we just forward declare the enum? It would be nice to keep it in the private header
It doesn't seem to support that:./include/linux/iommufd.h:31:34: error: field ‘type’ has incomplete type
31 | enum iommufd_object_type type;
By testing the following change on top of the series:
===================================
-enum iommufd_object_type {
- IOMMUFD_OBJ_NONE, - IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE, - IOMMUFD_OBJ_DEVICE, - IOMMUFD_OBJ_HWPT_PAGING, - IOMMUFD_OBJ_HWPT_NESTED, - IOMMUFD_OBJ_IOAS, - IOMMUFD_OBJ_ACCESS, - IOMMUFD_OBJ_VIOMMU, - IOMMUFD_OBJ_VQUEUE,
-#ifdef CONFIG_IOMMUFD_TEST
- IOMMUFD_OBJ_SELFTEST,
-#endif
- IOMMUFD_OBJ_MAX,
-};
+enum iommufd_object_type;
/* Base struct for all objects with a userspace ID handle. */
struct iommufd_object {
refcount_t shortterm_users;
refcount_t users;
enum iommufd_object_type type;
unsigned int id; };
===================================
We could change the "enum iommufd_object_type type" in struct iommufd_object to "unsigned int type" though...
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 01/14] iommufd: Move iommufd_object to public iommufd header
Quoted 2 lines · Nicolin Chen
We could change the "enum
iommufd_object_typetype" in structiommufd_objectto "unsigned int type" though...
That might be the best compromise
Jason
RFC PATCH 2/14 iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
In reply to Nicolin ChenCurrently, the object allocation function calls:
level-0: iommufd_object_alloc() level-1: ___iommufd_object_alloc() level-2: _iommufd_object_alloc()
So the level-1 and level-2 look inverted.
As the following change will add another level-3 helper, to make it clear:
level-0: iommufd_object_alloc() level-1: _iommufd_object_alloc() level-2: __iommufd_object_alloc() level-3: ___iommufd_object_alloc()
Swap the names of the level-1 and level-2 functions.
--- drivers/iommu/iommufd/hw_pagetable.c | 4 ++-- drivers/iommu/iommufd/iommufd_private.h | 12 ++++++------ drivers/iommu/iommufd/main.c | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-)
drivers/iommu/iommufd/hw_pagetable.c +2 -2
@@ -115,7 +115,7 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,if (flags & ~valid_flags)return ERR_PTR (-EOPNOTSUPP ); - hwpt_paging =__iommufd_object_alloc ( + hwpt_paging =_iommufd_object_alloc ( ictx, hwpt_paging,IOMMUFD_OBJ_HWPT_PAGING , common.obj);if (IS_ERR (hwpt_paging))return ERR_CAST (hwpt_paging);
@@ -218,7 +218,7 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx,if (parent->auto_domain || !parent->nest_parent)return ERR_PTR (-EINVAL ); - hwpt_nested =__iommufd_object_alloc ( + hwpt_nested =_iommufd_object_alloc ( ictx, hwpt_nested,IOMMUFD_OBJ_HWPT_NESTED , common.obj);if (IS_ERR (hwpt_nested))return ERR_CAST (hwpt_nested);
drivers/iommu/iommufd/iommufd_private.h +6 -6
@@ -200,12 +200,12 @@ iommufd_object_put_and_try_destroy(struct iommufd_ctx *ictx,iommufd_object_remove (ictx, obj, obj->id,0 ); } -struct iommufd_object *_iommufd_object_alloc (struct iommufd_ctx *ictx, -size_t size, -enum iommufd_object_type type); +struct iommufd_object *__iommufd_object_alloc (struct iommufd_ctx *ictx, +size_t size, +enum iommufd_object_type type); -#define __iommufd_object_alloc (ictx, ptr, type, obj) \ - container_of(_iommufd_object_alloc( \ +#define _iommufd_object_alloc (ictx, ptr, type, obj) \ + container_of(__iommufd_object_alloc( \ ictx, \ sizeof(*(ptr)) + BUILD_BUG_ON_ZERO( \ offsetof(typeof(*(ptr)), \
@@ -214,7 +214,7 @@ struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, typeof(*(ptr)), obj)#define iommufd_object_alloc (ictx, ptr, type) \ - __iommufd_object_alloc(ictx, ptr, type, obj) + _iommufd_object_alloc(ictx, ptr, type, obj)/* * The IO Address Space (IOAS) pagetable is a virtual page table backed by the
drivers/iommu/iommufd/main.c +3 -3
@@ -29,9 +29,9 @@ struct iommufd_object_ops {static const struct iommufd_object_ops iommufd_object_ops[];static struct miscdevice vfio_misc_dev; -struct iommufd_object *_iommufd_object_alloc (struct iommufd_ctx *ictx, -size_t size, -enum iommufd_object_type type) +struct iommufd_object *__iommufd_object_alloc (struct iommufd_ctx *ictx, +size_t size, +enum iommufd_object_type type) {struct iommufd_object *obj;int rc;
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 02/14] iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
Quoted 4 lines · Nicolin Chen
Currently, the object allocation function calls:
level-0: iommufd_object_alloc() level-1: ___iommufd_object_alloc() level-2: _iommufd_object_alloc()
Let's give __iommufd_object_alloc() a better name then
It is a less general version of iommufd_object_alloc(), maybe iommufd_object_alloc_elm() ?
Jason
Re: [PATCH RFCv1 02/14] iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Currently, the object allocation function calls:
level-0: iommufd_object_alloc() level-1: ___iommufd_object_alloc() level-2: _iommufd_object_alloc()Let's give
__iommufd_object_alloc()a better name thenIt is a less general version of
iommufd_object_alloc(), maybeiommufd_object_alloc_elm()?
With the level-3 allocator, something like the followings?
level-0: iommufd_object_alloc() level-1: __iommufd_object_alloc() level-2: iommufd_object_alloc_elm() level-3: __iommufd_object_alloc_elm()
In this case, this patch will be:
"iommufd: Rename _iommufd_object_alloc to iommufd_object_alloc_elm"
Thanks
Nicolin
Re: [PATCH RFCv1 02/14] iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
Quoted 14 lines · Nicolin Chen
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Currently, the object allocation function calls:
level-0: iommufd_object_alloc() level-1: ___iommufd_object_alloc() level-2: _iommufd_object_alloc()Let's give
__iommufd_object_alloc()a better name thenIt is a less general version of
iommufd_object_alloc(), maybeiommufd_object_alloc_elm()?With the level-3 allocator, something like the followings?
Quoted 7 lines
level-0: iommufd_object_alloc() level-1: __iommufd_object_alloc() level-2: iommufd_object_alloc_elm() level-3: __iommufd_object_alloc_elm()In this case, this patch will be:
"iommufd: Rename_iommufd_object_alloctoiommufd_object_alloc_elm"
After reading your comments in PATCH-4, seems that we don't need the level-3 allocator, if we pass an ictx pointer throughout the core and driver. I will try with this first.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 02/14] iommufd: Swap _iommufd_object_alloc and __iommufd_object_alloc
In reply to Nicolin ChenQuoted 14 lines · Nicolin Chen
Quoted 10 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Currently, the object allocation function calls:
level-0: iommufd_object_alloc() level-1: ___iommufd_object_alloc() level-2: _iommufd_object_alloc()Let's give
__iommufd_object_alloc()a better name thenIt is a less general version of
iommufd_object_alloc(), maybeiommufd_object_alloc_elm()?With the level-3 allocator, something like the followings?
Quoted 7 lines
level-0: iommufd_object_alloc() level-1: __iommufd_object_alloc() level-2: iommufd_object_alloc_elm() level-3: __iommufd_object_alloc_elm()In this case, this patch will be:
"iommufd: Rename_iommufd_object_alloctoiommufd_object_alloc_elm"
Yes
Jason
RFC PATCH 3/14 iommufd: Prepare for viommu structures and functions
In reply to Nicolin ChenThe following changes will introduce a new iommufd_viommu and its related structures and functions. These new core-level structures will be embedded in the driver-level structures. So a helper to allocate the bundle of core and driver strucutres will be nice to have.
As a preparatory change, introduce a viommu.c file and put a new structure allocator in it. Since some of the object allocation will be similar, also move the common part to a new level-3 allocator ___iommufd_object_alloc().
--- drivers/iommu/iommufd/Makefile | 3 ++- drivers/iommu/iommufd/iommufd_private.h | 20 ++++++++++++++++++++ drivers/iommu/iommufd/main.c | 9 +++------ drivers/iommu/iommufd/viommu.c | 19 +++++++++++++++++++ 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 drivers/iommu/iommufd/viommu.c
drivers/iommu/iommufd/Makefile +2 -1
@@ -6,7 +6,8 @@ iommufd-y := \ ioas.o \ main.o \ pages.o \ - vfio_compat.o + vfio_compat.o \ + viommu.o iommufd-$(CONFIG_IOMMUFD_TEST) += selftest.o
drivers/iommu/iommufd/iommufd_private.h +20 -0
@@ -156,6 +156,26 @@ void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,void iommufd_object_finalize (struct iommufd_ctx *ictx,struct iommufd_object *obj); +static inline struct iommufd_object *___iommufd_object_alloc (size_t size) +{ +struct iommufd_object *obj; + + obj =kzalloc (size,GFP_KERNEL_ACCOUNT ); +if (!obj) +return ERR_PTR (-ENOMEM ); + +/* Starts out bias'd by 1 until it is removed from the xarray */ +refcount_set (&obj->shortterm_users,1 ); +refcount_set (&obj->users,1 ); + +/* +* The allocation of an obj->id needs an ictx, so it has to be done +* after this ___iommufd_object_alloc() callback. +*/ + +return obj; +} +enum {REMOVE_WAIT_SHORTTERM =1 , };
drivers/iommu/iommufd/main.c +3 -6
@@ -36,13 +36,10 @@ struct iommufd_object *__iommufd_object_alloc(struct iommufd_ctx *ictx,struct iommufd_object *obj;int rc; - obj =kzalloc (size,GFP_KERNEL_ACCOUNT ); -if (!obj) -return ERR_PTR (-ENOMEM ); + obj =___iommufd_object_alloc (size); +if (IS_ERR (obj)) +return obj; obj->type = type; -/* Starts out bias'd by 1 until it is removed from the xarray */ -refcount_set (&obj->shortterm_users,1 ); -refcount_set (&obj->users,1 );/* * Reserve an ID in the xarray but do not publish the pointer yet since
drivers/iommu/iommufd/viommu.c new file +19 -0
@@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES +*/ + +#include <linux/iommufd.h> + +#include "iommufd_private.h" + +#define viommu_struct_alloc (name) \ + struct iommufd_##name *_iommufd_##name##_alloc(size_t size) \ + { \ + struct iommufd_object *obj; \ + if (WARN_ON(size < sizeof(struct iommufd_##name))) \ + return NULL; \ + obj = ___iommufd_object_alloc(size); \ + if (IS_ERR(obj)) \ + return NULL; \ + return container_of(obj, struct iommufd_##name, obj); \ + }
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 03/14] iommufd: Prepare for viommu structures and functions
Quoted 9 lines · Nicolin Chen
drivers/iommu/iommufd/iommufd_private.h +9
-0+static inline struct iommufd_object *___iommufd_object_alloc (size_t size) +{ +struct iommufd_object *obj; + + obj =kzalloc (size,GFP_KERNEL_ACCOUNT ); +if (!obj) +return ERR_PTR (-ENOMEM ); + +/* Starts out bias'd by 1 until it is removed from the xarray */
drivers/iommu/iommufd/iommufd_private.h void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx, · line 177
Quoted 10 lines
drivers/iommu/iommufd/iommufd_private.h +10
-0+refcount_set (&obj->shortterm_users,1 ); +refcount_set (&obj->users,1 ); + +/* +* The allocation of an obj->id needs an ictx, so it has to be done +* after this ___iommufd_object_alloc() callback. +*/ + +return obj; +}
It is probably cleaner to just make the existing allocation work with a NULL ictx for this case? Then we can use the existing alloc functions.
drivers/iommu/iommufd/viommu.c line 14
Quoted 6 lines
drivers/iommu/iommufd/viommu.c new file +6
-0+#define viommu_struct_alloc (name) \ + struct iommufd_##name *_iommufd_##name##_alloc(size_t size) \ + { \ + struct iommufd_object *obj; \ + if (WARN_ON(size < sizeof(struct iommufd_##name))) \ + return NULL; \
Then here you'd just use the exisint container_of based flow with the driver sub struct name passed as the 'obj'
Jason
Re: [PATCH RFCv1 03/14] iommufd: Prepare for viommu structures and functions
Quoted 26 lines · Jason Gunthorpe
Quoted 9 lines · Nicolin Chen
drivers/iommu/iommufd/iommufd_private.h +9
-0+static inline struct iommufd_object *___iommufd_object_alloc (size_t size) +{ +struct iommufd_object *obj; + + obj =kzalloc (size,GFP_KERNEL_ACCOUNT ); +if (!obj) +return ERR_PTR (-ENOMEM ); + +/* Starts out bias'd by 1 until it is removed from the xarray */ drivers/iommu/iommufd/iommufd_private.h void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx, · line 177
Quoted 10 lines
drivers/iommu/iommufd/iommufd_private.h +10
-0+refcount_set (&obj->shortterm_users,1 ); +refcount_set (&obj->users,1 ); + +/* +* The allocation of an obj->id needs an ictx, so it has to be done +* after this ___iommufd_object_alloc() callback. +*/ + +return obj; +}It is probably cleaner to just make the existing allocation work with a NULL ictx for this case? Then we can use the existing alloc functions.
Quoted 9 lines
drivers/iommu/iommufd/viommu.c line 14
Quoted 6 lines
drivers/iommu/iommufd/viommu.c new file +6
-0+#define viommu_struct_alloc (name) \ + struct iommufd_##name *_iommufd_##name##_alloc(size_t size) \ + { \ + struct iommufd_object *obj; \ + if (WARN_ON(size < sizeof(struct iommufd_##name))) \ + return NULL; \Then here you'd just use the exisint
container_ofbased flow with the driver sub struct name passed as the 'obj'
Yes. And then we can probably unwrap this macro too since it's no long that verbose to duplicate in viommu/vqueue allocators.
Thanks
Nicolin
RFC PATCH 4/14 iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
In reply to Nicolin ChenAdd a new iommufd_viommu core structure to represent a vIOMMU instance in the user space, typically backed by a HW-accelerated feature of an IOMMU, e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and AMD Hardware Accelerated Virtualized IOMMU (vIOMMU).
Define a new iommufd_viommu_ops to hold the free op and any future op.
A driver should embed this core structure in its driver viommu structure and call the new iommufd_viommu_alloc() helper to allocate a core/driver structure bundle and fill its core viommu->ops:
struct my_driver_viommu {
struct iommufd_viommu core;
....
};
static const struct iommufd_viommu_ops my_driver_viommu_ops = {
.free = my_driver_viommu_free,
};
struct my_driver_viommu *my_viommu =
iommufd_viommu_alloc(my_driver_viommu, core);
my_viommu->core.ops = &my_driver_viommu_ops;Lastly, add viommu_alloc to iommu_ops so iommufd can link to the driver to allocate a viommu object.
Any future viommu op will be added to the new struct iommufd_viommu_ops.
--- drivers/iommu/iommufd/viommu.c | 2 ++ include/linux/iommu.h | 15 ++++++++++++++ include/linux/iommufd.h | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+)
drivers/iommu/iommufd/viommu.c +2 -0
@@ -17,3 +17,5 @@return NULL ; \ return container_of(obj, struct iommufd_##name, obj); \ } + +viommu_struct_alloc (viommu);
include/linux/iommu.h +15 -0
@@ -145,6 +145,8 @@ struct iopf_queue {struct mutex lock; }; +struct iommufd_viommu ; +/* iommu fault flags */ #define IOMMU_FAULT_READ 0x0#define IOMMU_FAULT_WRITE 0x1
@@ -527,6 +529,14 @@ static inline int __iommu_copy_struct_from_user_array(* @of_xlate: add OF master IDs to iommu grouping * @is_attach_deferred: Check if domain attach should be deferred from iommu * driver init to device driver init (default no) +* @viommu_alloc: Allocate an iommufd_viommu as a user space IOMMU instance, +* associated to a nested parent @domain, for iommu-specific +* hardware acceleration. The @viommu_type must be defined in +* the include/uapi/linux/iommufd.h header. +* It is suggested to call iommufd_viommu_alloc() helper for +* a bundled allocation of the core and the driver structure, +* and a driver in gernal should assign an iommufd_viommu_ops +* to the core structure's viommu->ops. * @dev_enable/disable_feat: per device entries to enable/disable * iommu specific features. * @page_response: handle page request response
@@ -570,6 +580,11 @@ struct iommu_ops {int (*of_xlate)(struct device *dev,const struct of_phandle_args *args);bool (*is_attach_deferred)(struct device *dev); +/* User space instance allocation by the iommu driver */ +struct iommufd_viommu *(*viommu_alloc)(struct device *dev, +unsigned int viommu_type, +struct iommu_domain *domain); +/* Per device IOMMU features */ int (*dev_enable_feat)(struct device *dev,enum iommu_dev_features f);int (*dev_disable_feat)(struct device *dev,enum iommu_dev_features f);
include/linux/iommufd.h +38 -0
@@ -16,6 +16,7 @@ struct iommufd_device;struct page ;struct iommufd_ctx ;struct iommufd_access ; +struct iommufd_hwpt_paging ;struct file ;struct iommu_group ;
@@ -77,6 +78,26 @@ void iommufd_access_detach(struct iommufd_access *access);void iommufd_ctx_get (struct iommufd_ctx *ictx); +struct iommufd_viommu { +struct iommufd_object obj; +struct iommufd_ctx *ictx; +struct iommu_device *iommu_dev; +struct iommufd_hwpt_paging *hwpt; + +const struct iommufd_viommu_ops *ops; + +unsigned int type; +}; + +/** +* struct iommufd_viommu_ops - viommu specific operations +* @free: Free all driver-specific parts of an iommufd_viommu. The memory +* of the entire viommu will be free-ed by iommufd core +*/ +struct iommufd_viommu_ops { +void (*free)(struct iommufd_viommu *viommu); +}; +#if IS_ENABLED (CONFIG_IOMMUFD )struct iommufd_ctx *iommufd_ctx_from_file (struct file *file);struct iommufd_ctx *iommufd_ctx_from_fd (int fd);
@@ -93,6 +114,8 @@ int iommufd_access_rw(struct iommufd_access *access, unsigned long iova,int iommufd_vfio_compat_ioas_get_id (struct iommufd_ctx *ictx,u32 *out_ioas_id);int iommufd_vfio_compat_ioas_create (struct iommufd_ctx *ictx);int iommufd_vfio_compat_set_no_iommu (struct iommufd_ctx *ictx); + +struct iommufd_viommu *_iommufd_viommu_alloc (size_t size);#else /* !CONFIG_IOMMUFD */ static inline struct iommufd_ctx *iommufd_ctx_from_file (struct file *file) {
@@ -133,5 +156,20 @@ static inline int iommufd_vfio_compat_set_no_iommu(struct iommufd_ctx *ictx) {return -EOPNOTSUPP ; } + +static inline struct iommufd_viommu *_iommufd_viommu_alloc (size_t size) +{ +return NULL ; +}#endif /* CONFIG_IOMMUFD */ + +/* +* Helpers for IOMMU driver to allocate driver structures that will be freed by +* the iommufd core. A driver is only responsible for its own struct cleanup. +*/ +#define iommufd_viommu_alloc (drv_struct, member) \ + container_of(_iommufd_viommu_alloc(sizeof(struct drv_struct) + \ + BUILD_BUG_ON_ZERO(offsetof( \ + struct drv_struct, member))), \ + struct drv_struct, member)#endif
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 4 lines · Nicolin Chen
Add a new
iommufd_viommucore structure to represent a vIOMMU instance in the user space, typically backed by a HW-accelerated feature of an IOMMU, e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and AMD Hardware Accelerated Virtualized IOMMU (vIOMMU).
I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address space
I haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Does the nesting domain create need the viommu as well (in place of the S2 hwpt)? That feels sort of natural.
There is still a lot of fixing before everything can work fully, but do we need to make some preperations here in the uapi? Like starting to thread the S2 through it as I described?
Kevin, does Intel forsee any viommu needs on current/future Intel HW? I assume you are thinking about invalidation queue bypass like everyone else. I think it is an essential feature for vSVA.
Quoted 14 lines
A driver should embed this core structure in its driver viommu structure and call the new
iommufd_viommu_alloc()helper to allocate a core/driver structure bundle and fill its coreviommu->ops:struct my_driver_viommu { struct iommufd_viommu core; .... }; static const struct iommufd_viommu_ops my_driver_viommu_ops = { .free = my_driver_viommu_free, }; struct my_driver_viommu *my_viommu = iommufd_viommu_alloc(my_driver_viommu, core);
Why don't we have an ictx here anyhow? The caller has it? Just pass it down and then it is normal:
my_viommu = iommufd_object_alloc_elm(ictx, my_viommu, IOMMUFD_OBJ_HWPT_VIOMMU, core.obj);
And abort works properly for error handling.
Jason
Re: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 19 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Add a new
iommufd_viommucore structure to represent a vIOMMU instance in the user space, typically backed by a HW-accelerated feature of an IOMMU, e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and AMD Hardware Accelerated Virtualized IOMMU (vIOMMU).I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address spaceI haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
Quoted 6 lines
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Does the nesting domain create need the viommu as well (in place of the S2 hwpt)? That feels sort of natural.
Yes, I had a similar thought initially: each viommu is backed by a nested IOMMU HW, and a special HW accelerator like VCMDQ could be treated as an extension on top of that. It might not be very straightforward like the current design having vintf<->viommu and vcmdq <-> vqueue though...
In that case, we can then support viommu_cache_invalidate, which is quite natural for SMMUv3. Yet, I recall Kevin said that VT-d doesn't want or need that.
Quoted 20 lines
There is still a lot of fixing before everything can work fully, but do we need to make some preperations here in the uapi? Like starting to thread the S2 through it as I described?
Kevin, does Intel forsee any viommu needs on current/future Intel HW? I assume you are thinking about invalidation queue bypass like everyone else. I think it is an essential feature for vSVA.
Quoted 12 lines
A driver should embed this core structure in its driver viommu structure and call the new
iommufd_viommu_alloc()helper to allocate a core/driver structure bundle and fill its coreviommu->ops:struct my_driver_viommu { struct iommufd_viommu core; .... }; static const struct iommufd_viommu_ops my_driver_viommu_ops = { .free = my_driver_viommu_free, };
Quoted 7 lines
Quoted 2 lines
struct
my_driver_viommu*my_viommu=
iommufd_viommu_alloc(my_driver_viommu, core);Why don't we have an ictx here anyhow? The caller has it? Just pass it down and then it is normal:
my_viommu=iommufd_object_alloc_elm(ictx, my_viommu, IOMMUFD_OBJ_HWPT_VIOMMU, core.obj);
Oh, in that case, we probably don't need a level-3 obj allocator that was previously missing ictx to allocate an obj->id.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 24 lines · Nicolin Chen
Quoted 23 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Add a new
iommufd_viommucore structure to represent a vIOMMU instance in the user space, typically backed by a HW-accelerated feature of an IOMMU, e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and AMD Hardware Accelerated Virtualized IOMMU (vIOMMU).I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address spaceI haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Quoted 8 lines
Quoted 2 lines
Does the nesting domain create need the viommu as well (in place of the S2 hwpt)? That feels sort of natural.
Yes, I had a similar thought initially: each viommu is backed by a nested IOMMU HW, and a special HW accelerator like VCMDQ could be treated as an extension on top of that. It might not be very straightforward like the current design having vintf<->viommu and vcmdq <-> vqueue though...
vqueue should be considered a sub object of the viommu and hold a refcount on the viommu object for its lifetime.
Quoted 3 lines
In that case, we can then support
viommu_cache_invalidate, which is quite natural for SMMUv3. Yet, I recall Kevin said that VT-d doesn't want or need that.
Right, Intel currently doesn't need it, but I feel like everyone will need this eventually as the fast invalidation path is quite important.
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 4 lines
From: Jason Gunthorpe <[email protected]>
Sent: Tuesday, May 14, 2024 11:56 PMOn Sun, May 12, 2024 at 08:34:02PM -0700, Nicolin Chen wrote:
Quoted 26 lines
Quoted 3 lines · Jason Gunthorpe
Quoted 2 lines · Nicolin Chen
Quoted 1 line
Add a new
iommufd_viommucore structure to represent a vIOMMUinstance in
Quoted 1 line
Quoted 1 line
Quoted 1 line
the user space, typically backed by a HW-accelerated feature of an
IOMMU,
Quoted 1 line
Quoted 1 line
Quoted 1 line
e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and
AMD Hardware
Quoted 18 lines
Quoted 18 lines
Quoted 1 line
Accelerated Virtualized IOMMU (vIOMMU).
I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address spaceI haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Can you elaborate on this point? VIOMMU is a dummy container when it's created and the association to S2 comes relevant only until when VQUEUE is created inside and linked to a device? then there should be a window in between allowing the userspace to configure S2.
Not saying against setting S2 up before vIOMMU creation. Just want to better understand the rationale here.
Quoted 13 lines
Quoted 9 lines
Quoted 3 lines
Does the nesting domain create need the viommu as well (in place of the S2 hwpt)? That feels sort of natural.
Yes, I had a similar thought initially: each viommu is backed by a nested IOMMU HW, and a special HW accelerator like VCMDQ could be treated as an extension on top of that. It might not be very straightforward like the current design having vintf<->viommu and vcmdq <-> vqueue though...
vqueue should be considered a sub object of the viommu and hold a refcount on the viommu object for its lifetime.
Quoted 7 lines
Quoted 3 lines
In that case, we can then support
viommu_cache_invalidate, which is quite natural for SMMUv3. Yet, I recall Kevin said that VT-d doesn't want or need that.Right, Intel currently doesn't need it, but I feel like everyone will need this eventually as the fast invalidation path is quite important.
yes, there is no need but I don't see any harm of preparing for such extension on VT-d. Logically it's clearer, e.g. if we decide to move device TLB invalidation to a separate uAPI then vIOMMU is certainly a clearer object to carry it. and hardware extensions really looks like optimization on software implementations.
and we do need make a decision now, given if we make vIOMMU as a generic object for all vendors it may have potential impact on the user page fault support which Baolu is working on. the so-called fault object will be contained in vIOMMU, which is software managed on VT-d/SMMU but passed through on AMD. And probably we don't need another handle mechanism in the attach path, suppose the vIOMMU object already contains necessary information to find out iommufd_object for a reported fault.
Baolu, your thoughts?
Re: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 59 lines · Kevin
Quoted 4 lines
From: Jason Gunthorpe<[email protected]>
Sent: Tuesday, May 14, 2024 11:56 PMOn Sun, May 12, 2024 at 08:34:02PM -0700, Nicolin Chen wrote:
Quoted 25 lines
Quoted 3 lines · Jason Gunthorpe
Quoted 2 lines · Nicolin Chen
Quoted 1 line
Add a new
iommufd_viommucore structure to represent a vIOMMUinstance in
Quoted 1 line
Quoted 1 line
Quoted 1 line
the user space, typically backed by a HW-accelerated feature of an
IOMMU,
Quoted 1 line
Quoted 1 line
Quoted 1 line
e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and
AMD Hardware
Quoted 17 lines
Quoted 17 lines
Quoted 1 line
Accelerated Virtualized IOMMU (vIOMMU).
I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address spaceI haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Can you elaborate on this point? VIOMMU is a dummy container when it's created and the association to S2 comes relevant only until when VQUEUE is created inside and linked to a device? then there should be a window in between allowing the userspace to configure S2.
Not saying against setting S2 up before vIOMMU creation. Just want to better understand the rationale here.
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
Does the nesting domain create need the viommu as well (in place of the S2 hwpt)? That feels sort of natural.
Yes, I had a similar thought initially: each viommu is backed by a nested IOMMU HW, and a special HW accelerator like VCMDQ could be treated as an extension on top of that. It might not be very straightforward like the current design having vintf<->viommu and vcmdq <-> vqueue though...
Quoted 9 lines
vqueue should be considered a sub object of the viommu and hold a refcount on the viommu object for its lifetime.
Quoted 3 lines
In that case, we can then support
viommu_cache_invalidate, which is quite natural for SMMUv3. Yet, I recall Kevin said that VT-d doesn't want or need that.Right, Intel currently doesn't need it, but I feel like everyone will need this eventually as the fast invalidation path is quite important.
yes, there is no need but I don't see any harm of preparing for such extension on VT-d. Logically it's clearer, e.g. if we decide to move device TLB invalidation to a separate uAPI then vIOMMU is certainly a clearer object to carry it. and hardware extensions really looks like optimization on software implementations.
Quoted 8 lines
and we do need make a decision now, given if we make vIOMMU as a generic object for all vendors it may have potential impact on the user page fault support which Baolu is working on. the so-called fault object will be contained in vIOMMU, which is software managed on VT-d/SMMU but passed through on AMD. And probably we don't need another handle mechanism in the attach path, suppose the vIOMMU object already contains necessary information to find out
iommufd_objectfor a reported fault.
Yes, if the vIOMMU object tracks all iommufd devices that it manages.
Best regards,
baolu
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
In reply to Tian, KevinQuoted 27 lines · Kevin
Quoted 27 lines
From: Jason Gunthorpe <[email protected]>
Sent: Tuesday, May 14, 2024 11:56 PMQuoted 3 lines · Nicolin Chen
Quoted 2 lines · Jason Gunthorpe
Quoted 1 line · Nicolin Chen
Add a new
iommufd_viommucore structure to represent a vIOMMUinstance in
Quoted 1 line
Quoted 1 line
Quoted 1 line
the user space, typically backed by a HW-accelerated feature of an
IOMMU,
Quoted 1 line
Quoted 1 line
Quoted 1 line
e.g. NVIDIA CMDQ-Virtualization (an ARM SMMUv3 extension) and
AMD Hardware
Quoted 15 lines
Quoted 15 lines
Quoted 1 line
Accelerated Virtualized IOMMU (vIOMMU).
I expect this will also be the only way to pass in an associated KVM, userspace would supply the kvm when creating the viommu.
The tricky bit of this flow is how to manage the S2. It is necessary that the S2 be linked to the viommu:
1) ARM BTM requires the VMID to be shared with KVM
2) AMD and others need the S2 translation because some of the HW acceleration is done inside the guest address spaceI haven't looked closely at AMD but presumably the VIOMMU create will have to install the S2 into a DID or something?
Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Can you elaborate on this point? VIOMMU is a dummy container when it's created and the association to S2 comes relevant only until when VQUEUE is created inside and linked to a device?
VIOMMU contains:
- A nesting parent
- A KVM
- Any global per-VM data the driver needs
* In ARM case this is VMID, sometimes shared with KVM
* In AMD case this is will allocate memory in the "viommu backing storage memory"
Objects can be created on top of a VIOMMU:
- A nested HWPT (iommu_hwpt_alloc::pt_id can be a viommu)
- A vqueue (ARM/AMD)
- Other AMD virtualized objects (EventLog, PPRLog)
It is desirable to keep the VIOMMU linked to only a single nesting parent that never changes. Given it seems to be a small ask to allocate the nesting parent before the VIOMMU providing it at VIOMMU creation time looks like it will simplify the drivers because they can rely on it always existing and never changing.
I think this lends itself to a logical layered VMM design..
- If VFIO is being used get an iommufd
- Allocate an IOAS for the entire guest physical
- Determine the vIOMMU driver to use
- Allocate a HWPT for use by all the vIOMMU instances
- Allocate a VIOMMU per vIOMMU instance
On ARM the S2 is not divorced from the VIOMMU, ARM requires a single VMID, shared with KVM, and localized to a single VM for some of the bypass features (vBTM, vCMDQ). So to attach a S2 you actually have to attach the VIOMMU to pick up the correct VMID.
I imagine something like this:
hwpt_alloc(deva, nesting_parent=true) = shared_s2 viommu_alloc(deva, shared_s2) = viommu1 viommu_alloc(devb, shared_s2) = viommu2 hwpt_alloc(deva, viommu1, vste) = deva_vste hwpt_alloc(devb, viommu2, vste) = devb_vste attach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
The driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the pt_id for the iommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.
Both AMD and the vCMDQ thing need to translate some PFNs through the S2 and program them elsewhere, this is manually done by SW, and there are three choices I guess:
- Have the VMM do it and provide void __user * to the driver
- Have the driver do it through the S2 directly and track S2 invalidations
- Have the driver open an access on the IOAS and use the access unmap
Not sure which is the best..
Quoted 9 lines
Quoted 2 lines
Right, Intel currently doesn't need it, but I feel like everyone will need this eventually as the fast invalidation path is quite important.
yes, there is no need but I don't see any harm of preparing for such extension on VT-d. Logically it's clearer, e.g. if we decide to move device TLB invalidation to a separate uAPI then vIOMMU is certainly a clearer object to carry it. and hardware extensions really looks like optimization on software implementations.
Quoted 7 lines
and we do need make a decision now, given if we make vIOMMU as a generic object for all vendors it may have potential impact on the user page fault support which Baolu is working on.
the so-called
fault object will be contained in vIOMMU, which is software managed on VT-d/SMMU but passed through on AMD.
Hmm, given we currently have no known hardware entanglement between PRI and VIOMMU it does seem OK for PRI to just exist seperate for now. If someone needs them linked someday we can add a viommu_id to the create pri queue command.
Quoted 3 lines
And probably we don't need another handle mechanism in the attach path, suppose the vIOMMU object already contains necessary information to find out
iommufd_objectfor a reported fault.
The viommu might be useful to have the kernel return the vRID instead of the dev_id in the fault messages. I'm not sure how valuable this is..
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 15 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PMQuoted 10 lines · Kevin
Quoted 6 lines
From: Jason Gunthorpe <[email protected]>
Sent: Tuesday, May 14, 2024 11:56 PMQuoted 3 lines
Quoted 3 lines
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Can you elaborate on this point? VIOMMU is a dummy container when it's created and the association to S2 comes relevant only until when VQUEUE is created inside and linked to a device?
Quoted 5 lines
VIOMMU contains:
- A nesting parent
- A KVM
- Any global per-VM data the driver needs
* In ARM case this is VMID, sometimes shared with KVM
In which case is it not shared with KVM? I had the impression that VMID always comes from KVM in this VCMDQ usage. 😊
Quoted 8 lines
* In AMD case this is will allocate memory in the "viommu backing storage memory"
Objects can be created on top of a VIOMMU:
- A nested HWPT (iommu_hwpt_alloc::pt_idcan be a viommu)
- A vqueue (ARM/AMD)
- Other AMD virtualized objects (EventLog, PPRLog)
Quoted 5 lines
It is desirable to keep the VIOMMU linked to only a single nesting parent that never changes. Given it seems to be a small ask to allocate the nesting parent before the VIOMMU providing it at VIOMMU creation time looks like it will simplify the drivers because they can rely on it always existing and never changing.
yes, this makes sense.
Quoted 14 lines
I think this lends itself to a logical layered VMM design..
- If VFIO is being used get an iommufd
- Allocate an IOAS for the entire guest physical
- Determine the vIOMMU driver to use
- Allocate a HWPT for use by all the vIOMMU instances
- Allocate a VIOMMU per vIOMMU instanceOn ARM the S2 is not divorced from the VIOMMU, ARM requires a single VMID, shared with KVM, and localized to a single VM for some of the bypass features (vBTM, vCMDQ). So to attach a S2 you actually have to attach the VIOMMU to pick up the correct VMID.
Quoted 9 lines
I imagine something like this:
hwpt_alloc(deva, nesting_parent=true)=shared_s2viommu_alloc(deva, shared_s2)= viommu1viommu_alloc(devb, shared_s2)= viommu2hwpt_alloc(deva, viommu1, vste)=deva_vstehwpt_alloc(devb, viommu2, vste)=devb_vsteattach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
I wonder whether we want to make viommu as the 1st-class citizen for any nested hwpt if it is desirable to enable it even for VT-d which lacks of a hw viommu concept at the moment.
Quoted 6 lines
The driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.
Can you elaborate the aspect about "three different VMIDs"? They are all for the same VM hence sharing the same VMID per the earlier description. This is also echo-ed in patch14:
tegra241_cmdqv_viommu_alloc()
vintf->vmid = smmu_domain->vmid;
Quoted 5 lines
Both AMD and the vCMDQ thing need to translate some PFNs through the S2 and program them elsewhere, this is manually done by SW, and there are three choices I guess:
- Have the VMM do it and provide void__user* to the driver
this sounds redundant to what S2 already provides
Quoted 2 lines
- Have the driver do it through the S2 directly and track S2 invalidations
this makes more sense to me. Just like the driver already needs to track S2 invalidations to flush any nested cache related to the affected S2 range.
Quoted 2 lines
- Have the driver open an access on the IOAS and use the access unmap
it requires adding more iommufd awareness into the iommu driver. I'm inclined to do it only at minimal necessity.
Quoted 16 lines
Not sure which is the best..
Quoted 12 lines
Quoted 2 lines
Right, Intel currently doesn't need it, but I feel like everyone will need this eventually as the fast invalidation path is quite important.
yes, there is no need but I don't see any harm of preparing for such extension on VT-d. Logically it's clearer, e.g. if we decide to move device TLB invalidation to a separate uAPI then vIOMMU is certainly a clearer object to carry it. and hardware extensions really looks like optimization on software implementations.
and we do need make a decision now, given if we make vIOMMU as a generic object for all vendors it may have potential impact on the user page fault support which Baolu is working on.
Quoted 6 lines
Quoted 3 lines
the so-called
fault object will be contained in vIOMMU, which is software managed on VT-d/SMMU but passed through on AMD.Hmm, given we currently have no known hardware entanglement between PRI and VIOMMU it does seem OK for PRI to just exist seperate for
Isn't AMD vPPRLog for directly sending PRI request into the guest?
Quoted 2 lines
now. If someone needs them linked someday we can add a
viommu_idto the create pri queue command.
I'm more worried about the potential conflict between the vqueue object here and the fault queue object in Baolu's series, if we want to introduce vIOMMU concept to platforms which lack of the hw support.
In that case both objects are software constructs to deliver faults.
Re: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 10 lines · Kevin
Quoted 7 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PM
VIOMMU contains:
- A nesting parent
- A KVM
- Any global per-VM data the driver needs
* In ARM case this is VMID, sometimes shared with KVMIn which case is it not shared with KVM? I had the impression that VMID always comes from KVM in this VCMDQ usage. 😊
Not actually. I guess that shared VMID is for BTM.
Quoted 15 lines
Quoted 5 lines
On ARM the S2 is not divorced from the VIOMMU, ARM requires a single VMID, shared with KVM, and localized to a single VM for some of the bypass features (vBTM, vCMDQ). So to attach a S2 you actually have to attach the VIOMMU to pick up the correct VMID.
Quoted 9 lines
I imagine something like this:
hwpt_alloc(deva, nesting_parent=true)=shared_s2viommu_alloc(deva, shared_s2)= viommu1viommu_alloc(devb, shared_s2)= viommu2hwpt_alloc(deva, viommu1, vste)=deva_vstehwpt_alloc(devb, viommu2, vste)=devb_vsteattach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
Quoted 3 lines
I wonder whether we want to make viommu as the 1st-class citizen for any nested hwpt if it is desirable to enable it even for VT-d which lacks of a hw viommu concept at the moment.
I think Jason is completely using SMMU as an example here.
Also FWIW, I am trying a core-allocated core-managed viommu for IOMMU_VIOMMU_TYPE_DEFAULT. So VT-d driver doesn't need to hold a viommu while VMM could still allocate one if it wants. And the VIOMMU interface can provide some helpers if driver wants some info from the core-managed viommu: a virtual dev ID to physical dev ID (returning device pointer) translation for example. And we can add more after we brain storm.
Sample change:
@@ -623,6 +625,18 @@ struct iommu_ops {
+ * @viommu_alloc: Allocate an iommufd_viommu associating to a nested parent
+ * @domain as a user space IOMMU instance for HW-accelerated + * features from the physical IOMMU behind the @dev. The + * @viommu_type must be defined in include/uapi/linux/iommufd.h + * It is suggested to call iommufd_viommu_alloc() helper for + * a bundled allocation of the core and the driver structures, + * using the given @ictx pointer. + * @default_viommu_ops: Driver can choose to use a default core-allocated core- + * managed viommu object by providing a default viommu ops. + * Otherwise, i.e. for a driver-managed viommu, viommu_ops + * should be passed in via iommufd_viommu_alloc() helper in + * its own viommu_alloc op.
[..]
+int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd) +{
...
+ if (cmd->type == IOMMU_VIOMMU_TYPE_DEFAULT) {
+ viommu = __iommufd_viommu_alloc(
+ ucmd->ictx, sizeof(*viommu),
+ domain->ops->default_viommu_ops);
+ } else {
+ if (!domain->ops->viommu_alloc) {
+ rc = -EOPNOTSUPP;
+ goto out_put_hwpt;
+ }
+
+ viommu = domain->ops->viommu_alloc(domain, idev->dev,
+ ucmd->ictx, cmd->type);
+ }
[..]
// Helper:
+struct device *
+iommufd_viommu_find_device(struct iommufd_viommu *viommu, u64 id);
Quoted 6 lines
Quoted 5 lines
The driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.
Quoted 6 lines
Can you elaborate the aspect about "three different VMIDs"? They are all for the same VM hence sharing the same VMID per the earlier description. This is also echo-ed in patch14:
tegra241_cmdqv_viommu_alloc()vintf->vmid = smmu_domain->vmid;
The design in the series is still old using a 1:1 relationship between a viommu and an S2 domain. I think the "three" is from his SMMU example above? Leaving it to Jason to reply though.
Quoted 7 lines
Quoted 2 lines
now. If someone needs them linked someday we can add a
viommu_idto the create pri queue command.I'm more worried about the potential conflict between the vqueue object here and the fault queue object in Baolu's series, if we want to introduce vIOMMU concept to platforms which lack of the hw support.
I actually see one argument is whether we should use a vqueue v.s. Baolu's fault queue object, and a counter argument whether we should also use vqueue for viommu invalidation v.s an array- based invalidation request that we have similarly for HWPT...
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 12 lines
From: Nicolin Chen <[email protected]>
Sent: Thursday, May 23, 2024 12:02 PMQuoted 8 lines · Kevin
Quoted 7 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PM
VIOMMU contains:
- A nesting parent
- A KVM
- Any global per-VM data the driver needs
* In ARM case this is VMID, sometimes shared with KVM
Quoted 4 lines
Quoted 2 lines
In which case is it not shared with KVM? I had the impression that VMID always comes from KVM in this VCMDQ usage. 😊
Not actually. I guess that shared VMID is for BTM.
yes. now that is clear to me after reading more context.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
On ARM the S2 is not divorced from the VIOMMU, ARM requires a single VMID, shared with KVM, and localized to a single VM for some of the bypass features (vBTM, vCMDQ). So to attach a S2 you actually have
but here the description should be only for vBTM too. vCMDQ has its own VMID policy.
Quoted 18 lines
Quoted 12 lines
Quoted 11 lines
attach the VIOMMU to pick up the correct VMID.
I imagine something like this:
hwpt_alloc(deva, nesting_parent=true)=shared_s2viommu_alloc(deva, shared_s2)= viommu1viommu_alloc(devb, shared_s2)= viommu2hwpt_alloc(deva, viommu1, vste)=deva_vstehwpt_alloc(devb, viommu2, vste)=devb_vsteattach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)Quoted 3 lines
I wonder whether we want to make viommu as the 1st-class citizen for any nested hwpt if it is desirable to enable it even for VT-d which lacks of a hw viommu concept at the moment.
I think Jason is completely using SMMU as an example here.
Quoted 7 lines
Also FWIW, I am trying a core-allocated core-managed viommu for
IOMMU_VIOMMU_TYPE_DEFAULT. So VT-d driver doesn't need to hold a viommu while VMM could still allocate one if it wants. And the VIOMMU interface can provide some helpers if driver wants some info from the core-managed viommu: a virtual dev ID to physical dev ID (returning device pointer) translation for example. And we can add more after we brain storm.
that'd be nice.
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
The driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.Can you elaborate the aspect about "three different VMIDs"? They are all for the same VM hence sharing the same VMID per the earlier description. This is also echo-ed in patch14:
Quoted 6 lines
Quoted 2 lines
tegra241_cmdqv_viommu_alloc()vintf->vmid = smmu_domain->vmid;The design in the series is still old using a 1:1 relationship between a viommu and an S2 domain. I think the "three" is from his SMMU example above? Leaving it to Jason to reply though.
I'd expect some detailed explanation in the commit msg about how VCMDQ actually works. It's unclear to me whether this "three different VMIDs" thing comes from the hw requirement or certain software design choices.
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
In reply to Tian, KevinQuoted 15 lines · Kevin
Quoted 15 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PMQuoted 10 lines · Kevin
Quoted 6 lines
From: Jason Gunthorpe <[email protected]>
Sent: Tuesday, May 14, 2024 11:56 PMQuoted 3 lines
Quoted 3 lines
So we need the S2 to exist before the VIOMMU is created, but the drivers are going to need some more fixing before that will fully work.
Can you elaborate on this point? VIOMMU is a dummy container when it's created and the association to S2 comes relevant only until when VQUEUE is created inside and linked to a device?
Quoted 8 lines
Quoted 5 lines
VIOMMU contains:
- A nesting parent
- A KVM
- Any global per-VM data the driver needs
* In ARM case this is VMID, sometimes shared with KVMIn which case is it not shared with KVM? I had the impression that VMID always comes from KVM in this VCMDQ usage. 😊
Not quite, only vBTM needs it to be shared with KVM because the CPU will forward the KVM VMID to the SMMU during invalidations.
Everything else in the nesting space (including vCMDQ) just needs the VMID to be unique to the VM since it scopes the ASID that is stored in guest table.s
For non-nesting cases (ie no viommu) the VMID can be unique to the S2.
Quoted 15 lines
Quoted 5 lines
On ARM the S2 is not divorced from the VIOMMU, ARM requires a single VMID, shared with KVM, and localized to a single VM for some of the bypass features (vBTM, vCMDQ). So to attach a S2 you actually have to attach the VIOMMU to pick up the correct VMID.
Quoted 9 lines
I imagine something like this:
hwpt_alloc(deva, nesting_parent=true)=shared_s2viommu_alloc(deva, shared_s2)= viommu1viommu_alloc(devb, shared_s2)= viommu2hwpt_alloc(deva, viommu1, vste)=deva_vstehwpt_alloc(devb, viommu2, vste)=devb_vsteattach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
Quoted 3 lines
I wonder whether we want to make viommu as the 1st-class citizen for any nested hwpt if it is desirable to enable it even for VT-d which lacks of a hw viommu concept at the moment.
I think we may as well code it like that, yes. It is easy to get the S2 out of the viommu and feed that into the intel driver.
Quoted 7 lines
Quoted 5 lines
The driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.Can you elaborate the aspect about "three different VMIDs"?
In SMMUv3 the cache is tagged by (VMID,ASID) where ASID is completely controlled by the guest.
Every time the guest observes a SMMUv3 instance it is allowed to creates its own private ASID number space for that instance. The guest could re-use ASID #1 on two instances.
So every SMMUv3 instance plugged into the guest needs to have its own unique VMID so that the overlapping ASID's are disambiguate. The above would create a VM where:
deva -> vSMMUv3 #1
devb -> vSMMUv3 #2
devc -> No IOMMU
Quoted 2 lines
tegra241_cmdqv_viommu_alloc()vintf->vmid = smmu_domain->vmid;
And same here the 'vintf' is processing ASIDs directly from the guest, it needs to understand the VMID they are scoped under. Every vSMMUv3 instance in the guest must get a VMID, vintf, and vCMDQ all to its own. The above needs revising in a viommu world.
Quoted 6 lines
Quoted 4 lines
Both AMD and the vCMDQ thing need to translate some PFNs through the S2 and program them elsewhere, this is manually done by SW, and there are three choices I guess:
- Have the VMM do it and provide void__user* to the driverthis sounds redundant to what S2 already provides
Yes, but we don't have to track invalidations here..
Quoted 5 lines
Quoted 2 lines
- Have the driver do it through the S2 directly and track S2 invalidations
this makes more sense to me. Just like the driver already needs to track S2 invalidations to flush any nested cache related to the affected S2 range.
I'm a bit worried about 'track invalidations' though..
Quoted 4 lines
Quoted 1 line
- Have the driver open an access on the IOAS and use the access unmap
it requires adding more iommufd awareness into the iommu driver. I'm inclined to do it only at minimal necessity.
Yes, it is certainly annoying because of the modular/builtin problem.
Quoted 4 lines
Quoted 2 lines
Hmm, given we currently have no known hardware entanglement between PRI and VIOMMU it does seem OK for PRI to just exist seperate for
Isn't AMD vPPRLog for directly sending PRI request into the guest?
I think it is, but that would be a vQUEUE on the VIOMMU not adding a VIOMMU to Lu's patches, which is what I ment.
Quoted 7 lines
Quoted 2 lines
now. If someone needs them linked someday we can add a
viommu_idto the create pri queue command.I'm more worried about the potential conflict between the vqueue object here and the fault queue object in Baolu's series, if we want to introduce vIOMMU concept to platforms which lack of the hw support.
I assume the vPPRLog will steal all the PRI before it reaches the kernel, so once this is turned on Lu's path won't see anything.
I don't know if AMD can turn vPPRLog on individually or if it is a whole package once they switch on VIOMMU..
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 21 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 8:59 PMQuoted 10 lines · Kevin
Quoted 8 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PMThe driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.Can you elaborate the aspect about "three different VMIDs"?
In SMMUv3 the cache is tagged by (VMID,ASID) where ASID is completely controlled by the guest.
Every time the guest observes a SMMUv3 instance it is allowed to creates its own private ASID number space for that instance. The guest could re-use ASID #1 on two instances.
Quoted 7 lines
So every SMMUv3 instance plugged into the guest needs to have its own unique VMID so that the overlapping ASID's are disambiguate. The above would create a VM where:
deva -> vSMMUv3 #1
devb -> vSMMUv3 #2
devc -> No IOMMU
This assumes that each vSMMUv3 instance has only one ASID space i.e. the guest cannot create multiple VMID's itself?
Quoted 12 lines
Quoted 1 line
Quoted 1 line
Hmm, given we currently have no known hardware entanglement
between
Quoted 3 lines
Quoted 1 line
PRI and VIOMMU it does seem OK for PRI to just exist seperate for
Isn't AMD vPPRLog for directly sending PRI request into the guest?
I think it is, but that would be a vQUEUE on the VIOMMU not adding a VIOMMU to Lu's patches, which is what I ment.
Quoted 3 lines
Quoted 2 lines
now. If someone needs them linked someday we can add a
viommu_idto the create pri queue command.
Quoted 8 lines
Quoted 4 lines
I'm more worried about the potential conflict between the vqueue object here and the fault queue object in Baolu's series, if we want to introduce vIOMMU concept to platforms which lack of the hw support.
I assume the vPPRLog will steal all the PRI before it reaches the kernel, so once this is turned on Lu's path won't see anything.
Okay, then we expect this vqueue object only for HW acceleration while software-based fault logging is still routed via Baolu's work.
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
Quoted 25 lines · Kevin
Quoted 25 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 8:59 PMQuoted 10 lines · Kevin
Quoted 8 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 9:39 PMThe driver will then know it should program three different VMIDs for the same S2 page table, which matches the ARM expectation for VMID. That is to say we'd pass in the viommu as the
pt_idfor theiommu_hwpt_alloc. The viommu would imply both the S2 page table and any meta information like VMID the driver needs.Can you elaborate the aspect about "three different VMIDs"?
In SMMUv3 the cache is tagged by (VMID,ASID) where ASID is completely controlled by the guest.
Every time the guest observes a SMMUv3 instance it is allowed to creates its own private ASID number space for that instance. The guest could re-use ASID #1 on two instances.
So every SMMUv3 instance plugged into the guest needs to have its own unique VMID so that the overlapping ASID's are disambiguate. The above would create a VM where:
Quoted 6 lines
Quoted 3 lines
deva -> vSMMUv3 #1
devb -> vSMMUv3 #2
devc -> No IOMMUThis assumes that each vSMMUv3 instance has only one ASID space i.e. the guest cannot create multiple VMID's itself?
Right, the vSMMUv3 in the guest has no support VMID at all.
Quoted 5 lines
Quoted 2 lines
I assume the vPPRLog will steal all the PRI before it reaches the kernel, so once this is turned on Lu's path won't see anything.
Okay, then we expect this vqueue object only for HW acceleration while software-based fault logging is still routed via Baolu's work.
Yeah, I think it mirrors the invalidation that way, we have a SW invalidation path and a HW path. The PRI is standards based so it is easier to make a generic API for it.
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 04/14] iommufd: Add struct iommufd_viommu and iommufd_viommu_ops
In reply to Jason GunthorpeQuoted 11 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 8:59 PMQuoted 7 lines
Quoted 2 lines
now. If someone needs them linked someday we can add a
viommu_idto the create pri queue command.I'm more worried about the potential conflict between the vqueue object here and the fault queue object in Baolu's series, if we want to introduce vIOMMU concept to platforms which lack of the hw support.
Quoted 6 lines
I assume the vPPRLog will steal all the PRI before it reaches the kernel, so once this is turned on Lu's path won't see anything.
I don't know if AMD can turn vPPRLog on individually or if it is a whole package once they switch on VIOMMU..
their spec says:
"
This feature is supported if MMIO Offset 0030h[vIommuSup]=1. When enabled, DTE[vImuEn]=1 indicates the guest owning this device is a vIOMMU enabled guest, and IOMMU should write event and peripheral page requests associated with this device into the guest data structures. "
so it's configured per device.
RFC PATCH 5/14 iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
In reply to Nicolin ChenCorresponding to the new iommufd_viommu core structure that represents a vIOMMU instance in the user space for HW-accelerated features, add a new IOMMUFD_OBJ_VIOMMU and its ioctl for user space to allocate it.
--- drivers/iommu/iommufd/iommufd_private.h | 3 + drivers/iommu/iommufd/main.c | 6 ++ drivers/iommu/iommufd/viommu.c | 83 +++++++++++++++++++++++++ include/linux/iommufd.h | 1 + include/uapi/linux/iommufd.h | 30 +++++++++ 5 files changed, 123 insertions(+)
drivers/iommu/iommufd/iommufd_private.h +3 -0
@@ -424,6 +424,9 @@ void iopt_remove_access(struct io_pagetable *iopt, u32 iopt_access_list_id);void iommufd_access_destroy_object (struct iommufd_object *obj); +int iommufd_viommu_alloc_ioctl (struct iommufd_ucmd *ucmd); +void iommufd_viommu_destroy (struct iommufd_object *obj); +#ifdef CONFIG_IOMMUFD_TEST int iommufd_test (struct iommufd_ucmd *ucmd);void iommufd_selftest_destroy (struct iommufd_object *obj);
drivers/iommu/iommufd/main.c +6 -0
@@ -323,6 +323,7 @@ union ucmd_buffer {struct iommu_hwpt_set_dirty_tracking set_dirty_tracking;struct iommu_ioas_alloc alloc;struct iommu_ioas_allow_iovas allow_iovas; +struct iommu_viommu_alloc viommu;struct iommu_ioas_copy ioas_copy;struct iommu_ioas_iova_ranges iova_ranges;struct iommu_ioas_map map;
@@ -378,6 +379,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { val64),IOCTL_OP (IOMMU_VFIO_IOAS ,iommufd_vfio_ioas ,struct iommu_vfio_ioas ,__reserved ), +IOCTL_OP (IOMMU_VIOMMU_ALLOC ,iommufd_viommu_alloc_ioctl , +struct iommu_viommu_alloc ,out_viommu_id ), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif
@@ -510,6 +513,9 @@ static const struct iommufd_object_ops iommufd_object_ops[] = { .destroy = iommufd_hwpt_nested_destroy, .abort = iommufd_hwpt_nested_abort, }, + [IOMMUFD_OBJ_VIOMMU] = { + .destroy = iommufd_viommu_destroy, + }, #ifdef CONFIG_IOMMUFD_TEST [IOMMUFD_OBJ_SELFTEST] = { .destroy = iommufd_selftest_destroy,
drivers/iommu/iommufd/viommu.c +83 -0
86 lines not on this page · raw message
include/linux/iommufd.h +1 -0
@@ -28,6 +28,7 @@ enum iommufd_object_type {IOMMUFD_OBJ_HWPT_NESTED ,IOMMUFD_OBJ_IOAS ,IOMMUFD_OBJ_ACCESS , +IOMMUFD_OBJ_VIOMMU , #ifdef CONFIG_IOMMUFD_TEST IOMMUFD_OBJ_SELFTEST, #endif
include/uapi/linux/iommufd.h +30 -0
@@ -50,6 +50,7 @@ enum {IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING ,IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP ,IOMMUFD_CMD_HWPT_INVALIDATE , + IOMMUFD_CMD_VIOMMU_ALLOC, };/**
@@ -692,4 +693,33 @@ struct iommu_hwpt_invalidate { __u32 __reserved; };#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE) + +/** +* enum iommu_viommu_type - VIOMMU Type +* @IOMMU_VIOMMU_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension for SMMUv3 +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV , +}; + +/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the VIOMMU object. Must be defined in enum iommu_viommu_type +* @dev_id: The device to allocate this virtual IOMMU for +* @hwpt_id: ID of a nested parent HWPT +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +* +* Allocate an virtual IOMMU object that holds a (shared) nested parent HWPT +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +}; +#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC)#endif
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 29 lines · Nicolin Chen
drivers/iommu/iommufd/viommu.c +29
-0+int iommufd_viommu_alloc_ioctl (struct iommufd_ucmd *ucmd) +{ +struct iommu_viommu_alloc *cmd = ucmd->cmd; +struct iommufd_hwpt_paging *hwpt_paging; +struct iommu_device *iommu_dev; +struct iommufd_viommu *viommu; +struct iommufd_device *idev; +int rc; + +if (cmd->flags) +return -EOPNOTSUPP ; + + idev =iommufd_get_device (ucmd, cmd->dev_id); +if (IS_ERR (idev)) +return PTR_ERR (idev); + iommu_dev = idev->dev->iommu->iommu_dev; + +if (!iommu_dev->ops->viommu_alloc) { + rc = -EOPNOTSUPP ; + goto out_put_idev; + } + + hwpt_paging =iommufd_get_hwpt_paging (ucmd, cmd->hwpt_id); +if (IS_ERR (hwpt_paging)) { + rc =PTR_ERR (hwpt_paging); + goto out_put_idev; + } + +if (!hwpt_paging->nest_parent) {
drivers/iommu/iommufd/viommu.c line 71
Quoted 10 lines
drivers/iommu/iommufd/viommu.c +10
-0+ rc = -EINVAL ; + goto out_put_hwpt; + } + + viommu = iommu_dev->ops->viommu_alloc (idev->dev, cmd->type, + hwpt_paging->common.domain); +if (IS_ERR (viommu)) { + rc =PTR_ERR (viommu); + goto out_put_hwpt; + }
Ah you did already include the S2, So should it be domain->viommu_alloc() then?
drivers/iommu/iommufd/viommu.c line 79
Quoted 8 lines
drivers/iommu/iommufd/viommu.c +8
-0+ +/* iommufd_object_finalize will store the viommu->obj.id */ + rc =xa_alloc (&ucmd->ictx->objects, &viommu->obj.id,XA_ZERO_ENTRY , + xa_limit_31b,GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_free; + + viommu->obj.type =IOMMUFD_OBJ_VIOMMU ;
See my other notes, lets try not to open code this.
Quoted 9 lines
drivers/iommu/iommufd/viommu.c +9
-0+ viommu->type = cmd->type; + + viommu->ictx = ucmd->ictx; + viommu->hwpt = hwpt_paging; + viommu->iommu_dev = idev->dev->iommu->iommu_dev; + cmd->out_viommu_id = viommu->obj.id; + rc =iommufd_ucmd_respond (ucmd,sizeof (*cmd)); +if (rc) + goto out_erase_xa;
drivers/iommu/iommufd/viommu.c line 98
Quoted 10 lines
drivers/iommu/iommufd/viommu.c +10
-0+iommufd_object_finalize (ucmd->ictx, &viommu->obj); +refcount_inc (&viommu->hwpt->common.obj.users); + goto out_put_hwpt; + +out_erase_xa: +xa_erase (&ucmd->ictx->objects, viommu->obj.id); +out_free: +if (viommu->ops && viommu->ops->free) + viommu->ops->free (viommu); +kfree (viommu);
This really should use the abort flow. The driver free callback has to be in the object release..
include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 703
Quoted 8 lines
include/uapi/linux/iommufd.h +8
-0+ +/** +* enum iommu_viommu_type - VIOMMU Type +* @IOMMU_VIOMMU_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension for SMMUv3 +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV , +};
At least the 241 line should be in a following patch
Quoted 9 lines
include/uapi/linux/iommufd.h +9
-0+/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the VIOMMU object. Must be defined in enum iommu_viommu_type +* @dev_id: The device to allocate this virtual IOMMU for +* @hwpt_id: ID of a nested parent HWPT +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +*
include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 723
Quoted 10 lines
include/uapi/linux/iommufd.h +10
-0+* Allocate an virtual IOMMU object that holds a (shared) nested parent HWPT +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +};
This seems fine.
Let's have a following patch to change the hwpt_alloc to accept the viommu as a hwpt as a uAPI change as well.
The more I think about how this needs to work the more sure I am that we need to do that.
ARM will need a fairly tricky set of things to manage the VMID lifecycle. In BTM mode the VMID must come from the KVM. For vcmdq the VMID is needed to create the queue/viommu. For AMD the S2 is needed to create the VIOMMU in the first place.
So, to make this all work perfectly we need approx the following
- S2 sharing across instances in ARM - meaning the VMID is allocated at attach not domain alloc
- S2 hwpt is refcounted by the VIOMMU in the iommufd layer
- VIOMMU is refcounted by every nesting child in the iommufd layer
- The nesting child holds a pointer to both the S2 and the VIOMMU (viommu optional)
- When the nesting child attaches to a device the STE will source the VMID from the VIOMMU if present otherwise from the S2
- "RID" attach (ie naked S2) will have to be done with a Nesting Child using a vSTE that indicates Identity. Then the attach logic will have enough information to get the VMID from the VIOMMU
- In full VIOMMU mode the S2 will never get a VMID of its own, it will always use the VIOMMU. Life cycle is simple, the VMID is freed when the VIOMMU is freed. That can't happen until all Nesting Children are freed. That can't happen until all Nesting Children are detached from devices. Detatching removes the HW touch of the VMID.
At this point you don't need the full generality, but let's please get ready and get the viommu pointer available in all the right spots and we can keep the current logic to borrow the VMID from the S2 for the VIOMMU.
AMD folks, please consider if this works for you as well.
Jason
Re: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 10 lines · Jason Gunthorpe
drivers/iommu/iommufd/viommu.c line 71
Quoted 6 lines · Nicolin Chen
drivers/iommu/iommufd/viommu.c +6
-0+ viommu = iommu_dev->ops->viommu_alloc (idev->dev, cmd->type, + hwpt_paging->common.domain); +if (IS_ERR (viommu)) { + rc =PTR_ERR (viommu); + goto out_put_hwpt; + }Ah you did already include the S2, So should it be
domain->viommu_alloc()then?
We can do that. In that case, the VIOMMU_ALLOC ioctl should be simply per S2 HWPT too v.s. per IDEV.
Quoted 10 lines
drivers/iommu/iommufd/viommu.c line 79
Quoted 8 lines
drivers/iommu/iommufd/viommu.c +8
-0+ +/* iommufd_object_finalize will store the viommu->obj.id */ + rc =xa_alloc (&ucmd->ictx->objects, &viommu->obj.id,XA_ZERO_ENTRY , + xa_limit_31b,GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_free; + + viommu->obj.type =IOMMUFD_OBJ_VIOMMU ;See my other notes, lets try not to open code this.
Ack.
Quoted 14 lines
Quoted 14 lines
drivers/iommu/iommufd/viommu.c +14
-0+ viommu->type = cmd->type; + + viommu->ictx = ucmd->ictx; + viommu->hwpt = hwpt_paging; + viommu->iommu_dev = idev->dev->iommu->iommu_dev; + cmd->out_viommu_id = viommu->obj.id; + rc =iommufd_ucmd_respond (ucmd,sizeof (*cmd)); +if (rc) + goto out_erase_xa; +iommufd_object_finalize (ucmd->ictx, &viommu->obj); +refcount_inc (&viommu->hwpt->common.obj.users); + goto out_put_hwpt; + +out_erase_xa:
Quoted 8 lines
drivers/iommu/iommufd/viommu.c line 98
Quoted 5 lines
drivers/iommu/iommufd/viommu.c +5
-0+xa_erase (&ucmd->ictx->objects, viommu->obj.id); +out_free: +if (viommu->ops && viommu->ops->free) + viommu->ops->free (viommu); +kfree (viommu);This really should use the abort flow. The driver free callback has to be in the object release..
Yea, with the original object allocator, we probably can do abort().
Quoted 10 lines
include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 703
Quoted 8 lines
include/uapi/linux/iommufd.h +8
-0+ +/** +* enum iommu_viommu_type - VIOMMU Type +* @IOMMU_VIOMMU_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension for SMMUv3 +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV , +};At least the 241 line should be in a following patch
It's for the "enum iommu_viommu_type" mentioned in the following structure. Yi told me that you don't like an empty enum, and he did something like this in HWPT_INVALIDATE series:
https://lore.kernel.org/linux-iommu/[email protected]/
Quoted 33 lines
Quoted 9 lines
include/uapi/linux/iommufd.h +9
-0+/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the VIOMMU object. Must be defined in enum iommu_viommu_type +* @dev_id: The device to allocate this virtual IOMMU for +* @hwpt_id: ID of a nested parent HWPT +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +* include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 723
Quoted 10 lines
include/uapi/linux/iommufd.h +10
-0+* Allocate an virtual IOMMU object that holds a (shared) nested parent HWPT +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +};This seems fine.
Let's have a following patch to change the
hwpt_allocto accept the viommu as a hwpt as a uAPI change as well.The more I think about how this needs to work the more sure I am that we need to do that.
ARM will need a fairly tricky set of things to manage the VMID lifecycle. In BTM mode the VMID must come from the KVM. For vcmdq the VMID is needed to create the queue/viommu. For AMD the S2 is needed to create the VIOMMU in the first place.
Quoted 12 lines
So, to make this all work perfectly we need approx the following
- S2 sharing across instances in ARM - meaning the VMID is allocated at attach not domain alloc
- S2 hwpt is refcounted by the VIOMMU in the iommufd layer
- VIOMMU is refcounted by every nesting child in the iommufd layer
- The nesting child holds a pointer to both the S2 and the VIOMMU (viommu optional)
- When the nesting child attaches to a device the STE will source the VMID from the VIOMMU if present otherwise from the S2
- "RID" attach (ie naked S2) will have to be done with a Nesting Child using a vSTE that indicates Identity. Then the attach logic will have enough information to get the VMID from the VIOMMU
What is this RID attach (naked S2) case? S1DSS_BYPASS + SVA?
Quoted 5 lines
- In full VIOMMU mode the S2 will never get a VMID of its own, it will always use the VIOMMU. Life cycle is simple, the VMID is freed when the VIOMMU is freed. That can't happen until all Nesting Children are freed. That can't happen until all Nesting Children are detached from devices. Detatching removes the HW touch of the VMID.
So, each VM will have one S2 HWPT/domain/iopt, but each VM can have multiple VIOMMU instances sharing that single S2 HWPT, and each VIOMMU instance (in the SMMU driver at least) holds a vmid.
This seems to be a quite clear big picture now!
Quoted 4 lines
At this point you don't need the full generality, but let's please get ready and get the viommu pointer available in all the right spots and we can keep the current logic to borrow the VMID from the S2 for the VIOMMU.
Yea. Will try as much as I can.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 11 lines
Quoted 10 lines
include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 703
Quoted 8 lines
include/uapi/linux/iommufd.h +8
-0+ +/** +* enum iommu_viommu_type - VIOMMU Type +* @IOMMU_VIOMMU_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension for SMMUv3 +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV , +};At least the 241 line should be in a following patch
Quoted 4 lines
It's for the "enum
iommu_viommu_type" mentioned in the following structure. Yi told me that you don't like an empty enum, and he did something like this inHWPT_INVALIDATEseries:
https://lore.kernel.org/linux-iommu/[email protected]/
I suspect 0 should be reserved as a non-set value for some basic sanity in all these driver type enums.
Jason
Quoted 13 lines
Quoted 4 lines
So, to make this all work perfectly we need approx the following
- S2 sharing across instances in ARM - meaning the VMID is allocated at attach not domain alloc
- S2 hwpt is refcounted by the VIOMMU in the iommufd layerQuoted 8 lines
- VIOMMU is refcounted by every nesting child in the iommufd layer
- The nesting child holds a pointer to both the S2 and the VIOMMU (viommu optional)
- When the nesting child attaches to a device the STE will source the VMID from the VIOMMU if present otherwise from the S2
- "RID" attach (ie naked S2) will have to be done with a Nesting Child using a vSTE that indicates Identity. Then the attach logic will have enough information to get the VMID from the VIOMMU
Quoted 1 line
What is this RID attach (naked S2) case?
S1DSS_BYPASS+ SVA?
No, when the guest installs a vSTE that simply says bypass with no CD table pointer. That should result in a pSTE that is the S2 with on CD pointer.
I was originally thinking that the VMM would simply directly attach the S2 HWPT in this caes, but given the above issue with the VMID lifetime it makes more sense to 'attach' the viommu which holds the correct VMID.
The issue with direct attach the S2 HWPT is the VMID lifetime, as it would have to borrow the VMID from the viommu but then the lifetime becomes more complex as it has to live beyond VIOMMU destruction. Not unsolvable but it seems easier to just avoid it entirely.
Quoted 9 lines
Quoted 5 lines
- In full VIOMMU mode the S2 will never get a VMID of its own, it will always use the VIOMMU. Life cycle is simple, the VMID is freed when the VIOMMU is freed. That can't happen until all Nesting Children are freed. That can't happen until all Nesting Children are detached from devices. Detatching removes the HW touch of the VMID.
So, each VM will have one S2 HWPT/domain/iopt, but each VM can have multiple VIOMMU instances sharing that single S2 HWPT, and each VIOMMU instance (in the SMMU driver at least) holds a vmid.
Yes, right. We really want to share the S2 across instances in the end and I have made the VMID per-instance along with the per-instance ASID. So the above sounds like it could work
Jason
Re: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 11 lines · Jason Gunthorpe
Quoted 11 lines
Quoted 10 lines
include/uapi/linux/iommufd.h struct iommu_hwpt_invalidate { · line 703
Quoted 8 lines
include/uapi/linux/iommufd.h +8
-0+ +/** +* enum iommu_viommu_type - VIOMMU Type +* @IOMMU_VIOMMU_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension for SMMUv3 +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV , +};At least the 241 line should be in a following patch
Quoted 7 lines
Quoted 4 lines
It's for the "enum
iommu_viommu_type" mentioned in the following structure. Yi told me that you don't like an empty enum, and he did something like this inHWPT_INVALIDATEseries:
https://lore.kernel.org/linux-iommu/[email protected]/I suspect 0 should be reserved as a non-set value for some basic sanity in all these driver type enums.
We have an IOMMU_HWPT_DATA_NONE for HWPT_ALLOC to compatible with an S2 hwpt, since it doesn't need a data.
Maybe we can have an IOMMU_VIOMMU_TYPE_DEFAULT to be 0, for an IOMMU driver (e.g. VT-d) that doesn't need to handle nor be aware of any viommu object?
So, VMM can have a unified "attach-to-viommu" practice with different IOMMUs, v.s. some still doing "attach-to-s2"?
Quoted 24 lines
Quoted 13 lines
Quoted 4 lines
So, to make this all work perfectly we need approx the following
- S2 sharing across instances in ARM - meaning the VMID is allocated at attach not domain alloc
- S2 hwpt is refcounted by the VIOMMU in the iommufd layerQuoted 8 lines
- VIOMMU is refcounted by every nesting child in the iommufd layer
- The nesting child holds a pointer to both the S2 and the VIOMMU (viommu optional)
- When the nesting child attaches to a device the STE will source the VMID from the VIOMMU if present otherwise from the S2
- "RID" attach (ie naked S2) will have to be done with a Nesting Child using a vSTE that indicates Identity. Then the attach logic will have enough information to get the VMID from the VIOMMUQuoted 1 line
What is this RID attach (naked S2) case?
S1DSS_BYPASS+ SVA?No, when the guest installs a vSTE that simply says bypass with no CD table pointer. That should result in a pSTE that is the S2 with on CD pointer.
I was originally thinking that the VMM would simply directly attach the S2 HWPT in this caes, but given the above issue with the VMID lifetime it makes more sense to 'attach' the viommu which holds the correct VMID.
Quoted 4 lines
The issue with direct attach the S2 HWPT is the VMID lifetime, as it would have to borrow the VMID from the viommu but then the lifetime becomes more complex as it has to live beyond VIOMMU destruction. Not unsolvable but it seems easier to just avoid it entirely.
That makes a lot sense. I'd need to go through QEMU code and see how we will accommodate these two more naturally: likely the QEMU core should allocate an S2 HWPT for a VM, while the viommu code should allocate a VIOMMU for each instance.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 9 lines · Nicolin Chen
Quoted 2 lines
I suspect 0 should be reserved as a non-set value for some basic sanity in all these driver type enums.
We have an
IOMMU_HWPT_DATA_NONEforHWPT_ALLOCto compatible with an S2 hwpt, since it doesn't need a data.Maybe we can have an
IOMMU_VIOMMU_TYPE_DEFAULTto be 0, for an IOMMU driver (e.g. VT-d) that doesn't need to handle nor be aware of any viommu object?
Seems like a good practice, and perhaps userspace will find value in a generic viommu object that is always present.
Quoted 4 lines
That makes a lot sense. I'd need to go through QEMU code and see how we will accommodate these two more naturally: likely the QEMU core should allocate an S2 HWPT for a VM, while the viommu code should allocate a VIOMMU for each instance.
I'd suggest that core qemu should allocate the S2 IOAS and pass that to the qemu viommu driver
The qemu viommu driver should create the hwpt and then the viommu and perhaps return the viommu or hwpt back to the core code.
If the vSTE flow above is used for identity then the qemu viommu driver would also have to go an create vSTEs for identity and attach them to all devices before the VM starts up. Then when the OS activates the SMMU it would have to mirror the real vSTE from guest memory to the kernel.
Not sure there is value in having the core qemu code directly access the hwpt/viommu?
Jason
Re: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 7 lines · Jason Gunthorpe
Quoted 6 lines · Nicolin Chen
Quoted 2 lines
I suspect 0 should be reserved as a non-set value for some basic sanity in all these driver type enums.
We have an
IOMMU_HWPT_DATA_NONEforHWPT_ALLOCto compatible with an S2 hwpt, since it doesn't need a data.
Quoted 6 lines
Quoted 3 lines
Maybe we can have an
IOMMU_VIOMMU_TYPE_DEFAULTto be 0, for an IOMMU driver (e.g. VT-d) that doesn't need to handle nor be aware of any viommu object?Seems like a good practice, and perhaps userspace will find value in a generic viommu object that is always present.
Yea. VMM is always allowed to create a viommu to wrap an S2 HWPT. Then, I assume iommufd in this case should allocate a viommu object if !domain_ops->viommu_alloc.
Quoted 8 lines
Quoted 4 lines
That makes a lot sense. I'd need to go through QEMU code and see how we will accommodate these two more naturally: likely the QEMU core should allocate an S2 HWPT for a VM, while the viommu code should allocate a VIOMMU for each instance.
I'd suggest that core qemu should allocate the S2 IOAS and pass that to the qemu viommu driver
Quoted 8 lines
The qemu viommu driver should create the hwpt and then the viommu and perhaps return the viommu or hwpt back to the core code.
If the vSTE flow above is used for identity then the qemu viommu driver would also have to go an create vSTEs for identity and attach them to all devices before the VM starts up. Then when the OS activates the SMMU it would have to mirror the real vSTE from guest memory to the kernel.
The entire flow makes sense to me.
Quoted 2 lines
Not sure there is value in having the core qemu code directly access the hwpt/viommu?
I think so, though here might be some complication here.
On one side, it may not be straightforward for a qemu viommu driver to hold a shared S2 hwpt, as the driver is typically per instance, though I think it can keep viommu to its own. So passing the S2 hwpt back to qemu core and tie to iommufd handler (ictx) makes sense.
On the other side, there can be some future HW potentially supporting two+ kinds of IO page tables so a VM may have two+ S2 hwpts? Then the core would hold a list of S2 hwpts and the viommu driver would need to try-n-allocate viommu against the list..
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 05/14] iommufd: Add IOMMUFD_OBJ_VIOMMU and IOMMUFD_CMD_VIOMMU_ALLOC
Quoted 3 lines · Nicolin Chen
Yea. VMM is always allowed to create a viommu to wrap an S2 HWPT. Then, I assume iommufd in this case should allocate a viommu object if !domain_ops->viommu_alloc.
Yeah
Quoted 5 lines
On one side, it may not be straightforward for a qemu viommu driver to hold a shared S2 hwpt, as the driver is typically per instance, though I think it can keep viommu to its own. So passing the S2 hwpt back to qemu core and tie to iommufd handler (ictx) makes sense.
Yes, qemu will need some per-driver-type but not per-instance storage to make this work. Ie the ARM per-driver-type shared storage would hold the ARM specific list of S2 hwpts.
Quoted 5 lines
On the other side, there can be some future HW potentially supporting two+ kinds of IO page tables so a VM may have two+ S2 hwpts? Then the core would hold a list of S2 hwpts and the viommu driver would need to try-n-allocate viommu against the list..
Yes, it is supported in the API. Userspace should try to create viommus with all the S2 hwpts available and build a new one if it can't, just like hwpt attachment to a device.
Jason
RFC PATCH 6/14 iommufd/selftest: Add IOMMU_VIOMMU_ALLOC test coverage
In reply to Nicolin ChenAdd mock_viommu to cover the new IOMMU_VIOMMU_ALLOC ioctl.
--- drivers/iommu/iommufd/selftest.c | 18 +++++++++++++ tools/testing/selftests/iommu/iommufd.c | 23 ++++++++++++++++ tools/testing/selftests/iommu/iommufd_utils.h | 26 +++++++++++++++++++ 3 files changed, 67 insertions(+)
drivers/iommu/iommufd/selftest.c +18 -0
@@ -514,6 +514,23 @@ static struct iommu_device *mock_probe_device(struct device *dev)return &mock_iommu_device; } +struct mock_viommu { +struct iommufd_viommu core; +}; + +static struct iommufd_viommu *mock_viommu_alloc (struct device *dev, +unsigned int viommu_type, +struct iommu_domain *domain) +{ +struct mock_viommu *mv; + + mv =iommufd_viommu_alloc (mock_viommu, core); +if (!mv) +return ERR_PTR (-ENOMEM ); + +return &mv->core; +} +static const struct iommu_ops mock_ops = {/* * IOMMU_DOMAIN_BLOCKED cannot be returned from def_domain_type()
@@ -529,6 +546,7 @@ static const struct iommu_ops mock_ops = { .capable = mock_domain_capable, .device_group = generic_device_group, .probe_device = mock_probe_device, + .viommu_alloc = mock_viommu_alloc, .default_domain_ops = &(struct iommu_domain_ops ){ .free = mock_domain_free,
tools/testing/selftests/iommu/iommufd.c +23 -0
@@ -266,6 +266,29 @@ TEST_F(iommufd_ioas, ioas_destroy) } } +TEST_F(iommufd_ioas, viommu) +{ +uint32_t dev_id = self->device_id; +uint32_t viommu_id =0 ; +uint32_t hwpt_id =0 ; + +if (dev_id) { +test_err_viommu_alloc (ENOENT , dev_id, hwpt_id, &viommu_id); +test_cmd_hwpt_alloc (dev_id, self->ioas_id,0 , &hwpt_id); +test_err_viommu_alloc (EINVAL , dev_id, hwpt_id, &viommu_id); +test_ioctl_destroy (hwpt_id); + +test_cmd_hwpt_alloc (dev_id, self->ioas_id, +IOMMU_HWPT_ALLOC_NEST_PARENT , + &hwpt_id); +test_cmd_viommu_alloc (dev_id, hwpt_id, &viommu_id); +test_ioctl_destroy (viommu_id); +test_ioctl_destroy (hwpt_id); + }else { +test_err_viommu_alloc (ENOENT , dev_id, hwpt_id, &viommu_id); + } +} + TEST_F(iommufd_ioas, alloc_hwpt_nested) { const uint32_t min_data_len =
tools/testing/selftests/iommu/iommufd_utils.h +26 -0
@@ -684,3 +684,29 @@ static int _test_cmd_get_hw_info(int fd, __u32 device_id, void *data,#define test_cmd_get_hw_capabilities (device_id, caps, mask) \ ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, NULL, 0, &caps)) + +static int _test_cmd_viommu_alloc (int fd,__u32 device_id,__u32 hwpt_id, +__u32 flags,__u32 *viommu_id) +{ +struct iommu_viommu_alloc cmd = { + .size =sizeof (cmd), + .flags = flags, + .dev_id = device_id, + .hwpt_id = hwpt_id, + }; +int ret; + + ret =ioctl (fd,IOMMU_VIOMMU_ALLOC , &cmd); +if (ret) +return ret; +if (viommu_id) + *viommu_id = cmd.out_viommu_id; +return 0 ; +} + +#define test_cmd_viommu_alloc (device_id, hwpt_id, viommu_id) \ + ASSERT_EQ(0, _test_cmd_viommu_alloc(self->fd, device_id, hwpt_id, \ + 0, viommu_id)) +#define test_err_viommu_alloc (_errno, device_id, hwpt_id, viommu_id) \ + EXPECT_ERRNO(_errno, _test_cmd_viommu_alloc(self->fd, device_id, \ + hwpt_id, 0, viommu_id))
Signature · 1 line
2.43.0
RFC PATCH 7/14 iommufd: Add viommu set/unset_dev_id ops
In reply to Nicolin ChenAdd a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct invalidation requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface to execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
--- include/linux/iommufd.h | 4 ++++ 1 file changed, 4 insertions(+)
include/linux/iommufd.h +4 -0
@@ -94,9 +94,13 @@ struct iommufd_viommu {* struct iommufd_viommu_ops - viommu specific operations * @free: Free all driver-specific parts of an iommufd_viommu. The memory * of the entire viommu will be free-ed by iommufd core +* @set/unset_dev_id: set/unset a user space virtual id for a device */ struct iommufd_viommu_ops {void (*free)(struct iommufd_viommu *viommu); +int (*set_dev_id)(struct iommufd_viommu *viommu, +struct device *dev,u64 dev_id); +void (*unset_dev_id)(struct iommufd_viommu *viommu,struct device *dev); };#if IS_ENABLED (CONFIG_IOMMUFD )
Signature · 1 line
2.43.0
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 4 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
Quoted 9 lines
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct invalidation requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface to execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
Seems fine as is
Jason
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 15 lines · Jason Gunthorpe
Quoted 4 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
Quoted 9 lines
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct invalidation requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface to execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
Quoted 4 lines
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
You mean the nested SMMU series right? Actually the set_dev_id ioctl was a part of that until we wanted to try DEV_INVALIDATE.
So again, yes, it makes sense to me that we move viommu and the set_dev_id to the nested series, and then drop DEV_INVALIDATE.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 16 lines · Nicolin Chen
Quoted 15 lines · Jason Gunthorpe
Quoted 13 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct invalidation requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface to execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
Quoted 7 lines
Quoted 4 lines
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.
Yes, there is nothing inherently wrong with DEV_INVALIDATE, we could continue to use that as the API and automatically pick up the VIOMMU instance from the nesting domain to process the ATS.
The VMM needs a reliable place to send the CMDQ data, on ARM/AMD this needs to be an always available global-to-the-viommu thing. Intel needs to associate the virtual invalidation with the correct nesting domain as well.
So I original thought it would nice and simple to have a VIOMMU_INVALIDATE as well.
But.. If we need a nesting domain that is indentity (ie the S2) then when the VIOMMU is created then we'd also create an identity nesting domain as well. Functionally we could use that global nesting domain to deliver the DEV_INVALIDATE too.
It is a bit quirky, but it would be OK.
Quoted 2 lines
So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.
I would like to do this bit by bit. viommu is a big series on its own.
DEV_INVALIDATE is fine, it just can't do ATS invalidation.
We can add ATS invalidation after either as an enhancement as part of adding the VIOMMU either as DEV_INVALIDATE or VIOMMU_INVALIDATE (or both)
Jason
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 34 lines · Jason Gunthorpe
Quoted 16 lines · Nicolin Chen
Quoted 15 lines · Jason Gunthorpe
Quoted 13 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct invalidation requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface to execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
Quoted 7 lines
Quoted 4 lines
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.Yes, there is nothing inherently wrong with
DEV_INVALIDATE, we could continue to use that as the API and automatically pick up the VIOMMU instance from the nesting domain to process the ATS.The VMM needs a reliable place to send the CMDQ data, on ARM/AMD this needs to be an always available global-to-the-viommu thing. Intel needs to associate the virtual invalidation with the correct nesting domain as well.
Quoted 6 lines
So I original thought it would nice and simple to have a
VIOMMU_INVALIDATEas well.But.. If we need a nesting domain that is indentity (ie the S2) then when the VIOMMU is created then we'd also create an identity nesting domain as well.
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an arm_smmu_domain won't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?
Quoted 2 lines
Functionally we could use that global nesting domain to deliver the
DEV_INVALIDATEtoo.
If my narrative above is correct, the device is actually still attached to S2 domain via a proxy nested S1 domain. What cache do we need to invalidate except S2 mappings in this case?
Quoted 6 lines
Quoted 2 lines
So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I would like to do this bit by bit. viommu is a big series on its own.
DEV_INVALIDATEis fine, it just can't do ATS invalidation.
I am not very sure about AMD. Intel doesn't need DEV_INVALIDATE at this moment. SMMU only uses DEV_INVALIDATE for ATC and CD invalidations, which can be both shifted to VIOMMU_INVALIDATE.
Same question: any other case can we use the DEV_INVALIDATE for?
Quoted 3 lines
We can add ATS invalidation after either as an enhancement as part of adding the VIOMMU either as
DEV_INVALIDATEorVIOMMU_INVALIDATE(or both)
Yea, maybe step by step like this:
Part-1 VIOMMU_ALLOC and VIOMMU_ATTACH
Part-2 VIOMMU_SET/UNSET_VDEV_ID
Part-3 VIOMMU_INVALIDATE
Part-4 VQUEUE_ALLOC
...
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?
That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Quoted 6 lines
Quoted 2 lines
Functionally we could use that global nesting domain to deliver the
DEV_INVALIDATEtoo.If my narrative above is correct, the device is actually still attached to S2 domain via a proxy nested S1 domain. What cache do we need to invalidate except S2 mappings in this case?
qemu needs a reliable place to send the invalidation commands to (ie what ID to provide).
If we add IOMMU_VIOMMU_INVALIDATE then the ID is the viommu id.
If we enhance IOMMU_HWPT_INVALIDATE then the ID is the identity nesting domain.
Either case leads to the viommu object in the kernel.
I don't know if there is merit one way or the other. A more specific API surface is nice, but the two APIs are completely duplicating.
So maybe:
#define IOMMU_VIOMMU_INVALIDATE IOMMU_HWPT_INVALIDATE
As documentation and have the kernel just detect based on the type of the passed ID?
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I would like to do this bit by bit. viommu is a big series on its own.
DEV_INVALIDATEis fine, it just can't do ATS invalidation.I am not very sure about AMD.
AMD will need the same vRID -> pRID stuff and we want that to run on the VIOMMU
Quoted 1 line
Same question: any other case can we use the
DEV_INVALIDATEfor?
DEV_INVALIDATE was interesting before the viommu idea because userspace could process each invalidation command and when it reaches ATS it would invoke the correct DEV_INVALIDATE.
With viommu we expect ATS supporting drivers to support viommu and then to do vRID -> pRID in the other invalidation paths. In this case I don't see a reason to do DEV_INVALIDATE right now.
Quoted 11 lines
Quoted 3 lines
We can add ATS invalidation after either as an enhancement as part of adding the VIOMMU either as
DEV_INVALIDATEorVIOMMU_INVALIDATE(or both)Yea, maybe step by step like this:
Part-1
VIOMMU_ALLOCandVIOMMU_ATTACH
Part-2 VIOMMU_SET/UNSET_VDEV_ID
Part-3VIOMMU_INVALIDATE
Part-4VQUEUE_ALLOC
...
So we have this stuff still open:
- Identity STE with PASID (part 2b)
- IOMMU_GET_HW_INFO (part 3)
- IOMMU_HWPT_ALLOC_NEST_PARENT (part 3)
- IOMMU_HWPT_DATA_ARM_SMMUV3 (part 3)
- IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3
- VIOMMU_ALLOC, VIOMMU_ATTACH
- VIOMMU_INVALIDATE
- VIOMMU_SET/UNSET_VDEV_ID
- VQUEUE_ALLOC / vCMDQ
I feel like IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3 is a reasonable fit to part 3. Then part 4 would be VIOMMU_ALLOC -> VIOMMU_SET/UNSET_VDEV_ID which brings ATS support the API. vCMDQ hypervisor support would sit on top of that with just VQUEUE?
Jason
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 9 lines · Jason Gunthorpe
Quoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Yea. For vSTE=abort, likely we need a nested block domain too?
Quoted 10 lines
Quoted 6 lines
Quoted 2 lines
Functionally we could use that global nesting domain to deliver the
DEV_INVALIDATEtoo.If my narrative above is correct, the device is actually still attached to S2 domain via a proxy nested S1 domain. What cache do we need to invalidate except S2 mappings in this case?
qemu needs a reliable place to send the invalidation commands to (ie what ID to provide).
Quoted 6 lines
If we add
IOMMU_VIOMMU_INVALIDATEthen the ID is the viommu id.If we enhance
IOMMU_HWPT_INVALIDATEthen the ID is the identity nesting domain.Either case leads to the viommu object in the kernel.
Ooohh! I didn't connect the dots this far. Yes. This turns the IOMMU_HWPT_INVALIDATE back to the very first version supporting device cache flush. Though using IOMMU_HWPT_INVALIDATE feels a bit rule breaking now since it assumes the nested HWPT keeps a vdev_id lookup table somewhere in its associates...
Quoted 9 lines
I don't know if there is merit one way or the other. A more specific API surface is nice, but the two APIs are completely duplicating.
So maybe:
#define
IOMMU_VIOMMU_INVALIDATEIOMMU_HWPT_INVALIDATEAs documentation and have the kernel just detect based on the type of the passed ID?
Yea, the only difference is viommu_id v.s. hwpt_id that we can document.
Then in this case, we have two mostly identical uAPIs for the SMMU driver to use. Should we implement both?
Quoted 9 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I would like to do this bit by bit. viommu is a big series on its own.
DEV_INVALIDATEis fine, it just can't do ATS invalidation.I am not very sure about AMD.
Quoted 8 lines
AMD will need the same vRID -> pRID stuff and we want that to run on the VIOMMU
Quoted 1 line
Same question: any other case can we use the
DEV_INVALIDATEfor?
DEV_INVALIDATEwas interesting before the viommu idea because userspace could process each invalidation command and when it reaches ATS it would invoke the correctDEV_INVALIDATE.
Agreed. That helped a lot in VMM dispatching the invalidation requests.
Quoted 3 lines
With viommu we expect ATS supporting drivers to support viommu and then to do vRID -> pRID in the other invalidation paths. In this case I don't see a reason to do
DEV_INVALIDATEright now.
Yea. I guessed so.
Quoted 23 lines
Quoted 11 lines
Quoted 3 lines
We can add ATS invalidation after either as an enhancement as part of adding the VIOMMU either as
DEV_INVALIDATEorVIOMMU_INVALIDATE(or both)Yea, maybe step by step like this:
Part-1
VIOMMU_ALLOCandVIOMMU_ATTACH
Part-2 VIOMMU_SET/UNSET_VDEV_ID
Part-3VIOMMU_INVALIDATE
Part-4VQUEUE_ALLOC
...So we have this stuff still open:
- Identity STE with PASID (part 2b)
-IOMMU_GET_HW_INFO(part 3)
-IOMMU_HWPT_ALLOC_NEST_PARENT(part 3)
-IOMMU_HWPT_DATA_ARM_SMMUV3(part 3)
-IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3
-VIOMMU_ALLOC,VIOMMU_ATTACH
-VIOMMU_INVALIDATE
- VIOMMU_SET/UNSET_VDEV_ID
-VQUEUE_ALLOC/ vCMDQ
Quoted 3 lines
I feel like
IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3is a reasonable fit to part 3. Then part 4 would beVIOMMU_ALLOC-> VIOMMU_SET/UNSET_VDEV_ID which brings ATS support the API.
There is some conflict at passing in viommu_id/viommu v.s. parent hwpt_id/domain for a nested domain allocation. Do you think that should be addressed later in VIOMMU series v.s. part3?
More specifically, I have two drafts in my viommu series:87a659e65229 WAR: iommufd: Allow pt_it to carry viommu_id 7c5fd8f50bc9 WAR pass in viommu pointer to domain_alloc_user op
I know that these two only make sense with VIOMMU_ALOC. Yet, will there be a problem, if we establish nested domain allocation with parent domain/hwpt by part3, in the uAPI, and then change later? Will we end up with supporting two for backward compatibility?
Quoted 1 line
vCMDQ hypervisor support would sit on top of that with just VQUEUE?
Yea.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 8 lines · Nicolin Chen
Quoted 7 lines · Jason Gunthorpe
Quoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?
Quoted 4 lines
Quoted 2 lines
That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Yea. For vSTE=abort, likely we need a nested block domain too?
Sure, it is easy to do
Quoted 7 lines
Quoted 7 lines
I don't know if there is merit one way or the other. A more specific API surface is nice, but the two APIs are completely duplicating.
So maybe:
#define
IOMMU_VIOMMU_INVALIDATEIOMMU_HWPT_INVALIDATE
Quoted 8 lines
Quoted 2 lines
As documentation and have the kernel just detect based on the type of the passed ID?
Yea, the only difference is
viommu_idv.s.hwpt_idthat we can document.Then in this case, we have two mostly identical uAPIs for the SMMU driver to use. Should we implement both?
I suspect it will turn out nicely naturally, lets try and see
Quoted 27 lines
Quoted 23 lines
Quoted 11 lines
Quoted 3 lines
We can add ATS invalidation after either as an enhancement as part of adding the VIOMMU either as
DEV_INVALIDATEorVIOMMU_INVALIDATE(or both)Yea, maybe step by step like this:
Part-1
VIOMMU_ALLOCandVIOMMU_ATTACH
Part-2 VIOMMU_SET/UNSET_VDEV_ID
Part-3VIOMMU_INVALIDATE
Part-4VQUEUE_ALLOC
...So we have this stuff still open:
- Identity STE with PASID (part 2b)
-IOMMU_GET_HW_INFO(part 3)
-IOMMU_HWPT_ALLOC_NEST_PARENT(part 3)
-IOMMU_HWPT_DATA_ARM_SMMUV3(part 3)
-IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3
-VIOMMU_ALLOC,VIOMMU_ATTACH
-VIOMMU_INVALIDATE
- VIOMMU_SET/UNSET_VDEV_ID
-VQUEUE_ALLOC/ vCMDQQuoted 3 lines
I feel like
IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3is a reasonable fit to part 3. Then part 4 would beVIOMMU_ALLOC-> VIOMMU_SET/UNSET_VDEV_ID which brings ATS support the API.
Quoted 7 lines
There is some conflict at passing in viommu_id/viommu v.s. parent hwpt_id/domain for a nested domain allocation. Do you think that should be addressed later in VIOMMU series v.s. part3?
More specifically, I have two drafts in my viommu series:
87a659e65229WAR: iommufd: Allowpt_itto carryviommu_id7c5fd8f50bc9WAR pass in viommu pointer todomain_alloc_userop
It would be good for viommu to come with all the uAPI changes in one shot, so all the pt_ids should be updated to accept viommu to pass the S2 HWPT.
Then whatever driver changes are needed to make ATS work should come together too.
Quoted 4 lines
I know that these two only make sense with
VIOMMU_ALOC. Yet, will there be a problem, if we establish nested domain allocation with parent domain/hwpt by part3, in the uAPI, and then change later? Will we end up with supporting two for backward compatibility?
I think this is fairly minor compatability, let's see.
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
In reply to Jason GunthorpeQuoted 4 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMOn Tue, May 14, 2024 at 06:59:07PM -0700, Nicolin Chen wrote:
Quoted 9 lines
Quoted 5 lines
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
why does ATC invalidation need to know about VMID?
Or is above talking about beyond the discussion between DEV_INVALIDATE vs. VIOMMU_INVALIDATE?
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 10 lines · Kevin
Quoted 10 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMQuoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?
Quoted 5 lines
Quoted 3 lines
That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
why does ATC invalidation need to know about VMID?
ATC invalidation always requires a vRID to pRID translation and the VIOMMU will hold that translation.
On vCMDQ HW and on AMD HW the vRID to pRID translation is pushed into HW, and vCMDQ requires the VMID to do that.
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 18 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 11:01 PMQuoted 14 lines · Kevin
Quoted 13 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMQuoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Quoted 8 lines
Quoted 1 line
why does ATC invalidation need to know about VMID?
ATC invalidation always requires a vRID to pRID translation and the VIOMMU will hold that translation.
On vCMDQ HW and on AMD HW the vRID to pRID translation is pushed into HW, and vCMDQ requires the VMID to do that.
At a quick glance VMID and vRID->pRID translation are both configurations of a vintf.
My impression was that vintf->vmid is added to guest cmd when it's about iotlb invalidation.
then vintf->sid_slots is walked when handling a guest cmd for ATC invalidation.
I'm not sure why the latter one requires a valid VMID to do the walking except it's a implementation choice made by vCMDQ?
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 30 lines · Kevin
Quoted 18 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 11:01 PMQuoted 14 lines · Kevin
Quoted 13 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMQuoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Quoted 8 lines
Quoted 1 line
why does ATC invalidation need to know about VMID?
ATC invalidation always requires a vRID to pRID translation and the VIOMMU will hold that translation.
On vCMDQ HW and on AMD HW the vRID to pRID translation is pushed into HW, and vCMDQ requires the VMID to do that.
At a quick glance VMID and
vRID->pRIDtranslation are both configurations of a vintf.
Quoted 8 lines
My impression was that
vintf->vmidis added to guest cmd when it's about iotlb invalidation.then
vintf->sid_slotsis walked when handling a guest cmd for ATC invalidation.I'm not sure why the latter one requires a valid VMID to do the walking except it's a implementation choice made by vCMDQ?
Well, we haven't thought about a case of doing ATC invalidation via VINTF/VCMDQ without setting up a VMID, as "VMID" is a field in the VINTF_CONFIG register next to the Enable bit and must be set prior to enabling a VINTF, though your understanding of the HW work flow is probably accurate :)
And the narrative at the top was trying to describe the links:
[ device ] => [ proxy identity S1 ] => [ viommu [ shared S2 ] ]
v.s.
[ device ] => [ non-shareable S2 ]
So the first case can take advantage of VIOMMU_INVALIDATE v.s. the second case requires a DEV_INVALIDATE.
Another conclusion between the lines: since ARM SMMU will have the first case (with viommu), there is no longer any use of a DEV_INVALIDATE ioctl. So, we would likely drop it in the coming version.
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 42 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 11:26 AMQuoted 4 lines · Kevin
Quoted 4 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 11:01 PMOn Thu, May 23, 2024 at 06:19:59AM +0000, Tian, Kevin wrote:
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMQuoted 4 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a devicecan't
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 1 line
attach to an S2 domain but always an nested S1 domain, right?
That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
why does ATC invalidation need to know about VMID?
ATC invalidation always requires a vRID to pRID translation and the VIOMMU will hold that translation.
On vCMDQ HW and on AMD HW the vRID to pRID translation is pushed
into
Quoted 12 lines
Quoted 2 lines
HW, and vCMDQ requires the VMID to do that.
At a quick glance VMID and
vRID->pRIDtranslation are both configurations of a vintf.My impression was that
vintf->vmidis added to guest cmd when it's about iotlb invalidation.then
vintf->sid_slotsis walked when handling a guest cmd for ATC invalidation.
Quoted 8 lines
Quoted 2 lines
I'm not sure why the latter one requires a valid VMID to do the walking except it's a implementation choice made by vCMDQ?
Well, we haven't thought about a case of doing ATC invalidation via VINTF/VCMDQ without setting up a VMID, as "VMID" is a field in the
VINTF_CONFIGregister next to the Enable bit and must be set prior to enabling a VINTF, though your understanding of the HW work flow is probably accurate :)
Okay, that explains it. they are irrelevant in concept but come relevant due to that detail. 😊
Quoted 8 lines
And the narrative at the top was trying to describe the links:
[ device ] => [ proxy identity S1 ] => [ viommu [ shared S2 ] ]
v.s.
[ device ] => [ non-shareable S2 ]So the first case can take advantage of
VIOMMU_INVALIDATEv.s. the second case requires aDEV_INVALIDATE.
and one side-effect in the first case is to save one VMID for non-shareable S2 hence improves iotlb efficiency.
Quoted 8 lines
Another conclusion between the lines: since ARM SMMU will have the first case (with viommu), there is no longer any use of a
DEV_INVALIDATEioctl. So, we would likely drop it in the coming version.Thanks
Nicolin
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 16 lines · Kevin
Quoted 16 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines · Nicolin Chen
Quoted 4 lines
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a devicecan't
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
attach to an S2 domain but always an nested S1 domain, right?
That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
And the narrative at the top was trying to describe the links:
[ device ] => [ proxy identity S1 ] => [ viommu [ shared S2 ] ]
v.s.
[ device ] => [ non-shareable S2 ]
Quoted 5 lines
Quoted 2 lines
So the first case can take advantage of
VIOMMU_INVALIDATEv.s. the second case requires aDEV_INVALIDATE.and one side-effect in the first case is to save one VMID for non-shareable S2 hence improves iotlb efficiency.
Hmm, how is that?
VMID is currently stored in an S2 domain, actually. The viommu is a VMID holder to potentially decouple VMID from S2 domain, because VMID is per SMMU instance while S2 domain is shareable:
[ dev0 ] => [ S1 dom0 ] => [ viommu0 (VMID0) [ shared S2 ] ] [ dev1 ] => [ S1 dom1 ] => [ viommu1 (VMID1) [ shared S2 ] ]
By the way, we can also have (very likely our initial version):
[ dev0 ] => [ S1 dom0 ] => [ viommu0 [ non-sharable S2 dom0 (VMID0) ] ] [ dev1 ] => [ S1 dom1 ] => [ viommu1 [ non-sharable S2 dom1 (VMID1) ] ]
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 28 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 1:58 PMQuoted 4 lines · Kevin
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines · Nicolin Chen
Quoted 3 lines
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver
case,
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
arm_smmu_domainwon't have an smmu pointer, so a devicecan't
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
attach to an S2 domain but always an nested S1 domain, right?
That seems like a simple solution to the VMID lifetime, but it
means
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
the kernel has to decode more types of vSTE.
And the narrative at the top was trying to describe the links:
[ device ] => [ proxy identity S1 ] => [ viommu [ shared S2 ] ]
v.s.
[ device ] => [ non-shareable S2 ]Quoted 5 lines
Quoted 2 lines
So the first case can take advantage of
VIOMMU_INVALIDATEv.s. the second case requires aDEV_INVALIDATE.and one side-effect in the first case is to save one VMID for non-shareable S2 hence improves iotlb efficiency.
Quoted 7 lines
Hmm, how is that?
VMID is currently stored in an S2 domain, actually. The viommu is a VMID holder to potentially decouple VMID from S2 domain, because VMID is per SMMU instance while S2 domain is shareable:
[ dev0 ] => [ S1 dom0 ] => [ viommu0 (VMID0) [ shared S2 ] ] [ dev1 ] => [ S1 dom1 ] => [ viommu1 (VMID1) [ shared S2 ] ]
My point was based on Jason's example about 3 VMIDs:
hwpt_alloc(deva, nesting_parent=true) = shared_s2 viommu_alloc(deva, shared_s2) = viommu1 viommu_alloc(devb, shared_s2) = viommu2 hwpt_alloc(deva, viommu1, vste) = deva_vste hwpt_alloc(devb, viommu2, vste) = devb_vste attach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
for devc it could be:
hwpt_alloc(deva, viommu1, vproxy_s1) = devc_proxys1 attach(devc, devc_proxys1)
then devc will reuse VMID of viommu1 and we save one VMID.
Does that not work so we need create another viommu to hold the proxy identity s1 then still need a 3rd VMID?
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 11 lines · Kevin
My point was based on Jason's example about 3 VMIDs:
hwpt_alloc(deva, nesting_parent=true)=shared_s2viommu_alloc(deva, shared_s2)= viommu1viommu_alloc(devb, shared_s2)= viommu2hwpt_alloc(deva, viommu1, vste)=deva_vstehwpt_alloc(devb, viommu2, vste)=devb_vsteattach(deva, deva_vste)
attach(devb, devb_vste)
attach(devc, shared_s2)
Quoted 5 lines
for devc it could be:
hwpt_alloc(deva, viommu1, vproxy_s1)=devc_proxys1attach(devc, devc_proxys1)then devc will reuse VMID of viommu1 and we save one VMID.
I think that can work, at least I haven't thought of a reason why the non-vIOMMU device's VMID couldn't be shared with one of the vIOMMUs.
It is all quite a contrived case, I dont't expect people to want to do anything like this, it is just showing that the API is properly setup that it could be done. Userspace is not restricted to a single VIOMMU.
Quoted 2 lines
Does that not work so we need create another viommu to hold the proxy identity s1 then still need a 3rd VMID?
Yes, I think that can be OK.
Jason
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
In reply to Tian, KevinQuoted 30 lines · Kevin
Quoted 18 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 11:01 PMQuoted 14 lines · Kevin
Quoted 13 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, May 22, 2024 2:25 AMQuoted 5 lines · Nicolin Chen
So, you want a proxy S1 domain for a device to attach, in case of a stage-2 only setup, because an S2 domain will no longer has a VMID, since it's shared among viommus. In the SMMU driver case, an
arm_smmu_domainwon't have an smmu pointer, so a device can't attach to an S2 domain but always an nested S1 domain, right?That seems like a simple solution to the VMID lifetime, but it means the kernel has to decode more types of vSTE.
Quoted 8 lines
Quoted 1 line
why does ATC invalidation need to know about VMID?
ATC invalidation always requires a vRID to pRID translation and the VIOMMU will hold that translation.
On vCMDQ HW and on AMD HW the vRID to pRID translation is pushed into HW, and vCMDQ requires the VMID to do that.
At a quick glance VMID and
vRID->pRIDtranslation are both configurations of a vintf.
Quoted 8 lines
My impression was that
vintf->vmidis added to guest cmd when it's about iotlb invalidation.then
vintf->sid_slotsis walked when handling a guest cmd for ATC invalidation.I'm not sure why the latter one requires a valid VMID to do the walking except it's a implementation choice made by vCMDQ?
Yeah, that is probably right. And then in iommufd we are sort of doubling down by saying the VIOMMU object holds the S2 and the vRID->pRID as a bundle together.
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
In reply to Nicolin ChenQuoted 26 lines
From: Nicolin Chen <[email protected]>
Sent: Monday, May 13, 2024 12:39 PMQuoted 7 lines · Jason Gunthorpe
Quoted 6 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct
invalidation
Quoted 4 lines
Quoted 4 lines
requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface
to
Quoted 8 lines
Quoted 3 lines
execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
Quoted 6 lines
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.
I'm right about to ask how the nesting series is going. Per earlier discussion iirc the nesting series will go in before VCMDQ?
Re: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 26 lines · Kevin
Quoted 26 lines
From: Nicolin Chen <[email protected]>
Sent: Monday, May 13, 2024 12:39 PMQuoted 7 lines · Jason Gunthorpe
Quoted 6 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct
invalidation
Quoted 4 lines
Quoted 4 lines
requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface
to
Quoted 8 lines
Quoted 3 lines
execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
Quoted 8 lines
Quoted 5 lines
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I'm right about to ask how the nesting series is going. Per earlier discussion iirc the nesting series will go in before VCMDQ?
Yes. It still should. Yet we ended up with adding VIOMMU to the nested SMMU series too. A shared S2 domain/hwpt isn't exclusive for VCMDQ use case but also for regular nesting on a multi-SMMU setup. So, VIOMMU turns out to be the best object that we have at this moment to hold individual VMIDs for different physical SMMUs sharing a single S2 domain. Its virtual device ID lookup feature can also allow us to forget about DEV_INVALIDATE ioctl for now.
Jason listed all the tasks ahead in this thread too, using SMMU as an example:
Quoted 8 lines
So we have this stuff still open:
- Identity STE with PASID (part 2b)
-IOMMU_GET_HW_INFO(part 3)
-IOMMU_HWPT_ALLOC_NEST_PARENT(part 3)
-IOMMU_HWPT_DATA_ARM_SMMUV3(part 3)
-IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3
-VIOMMU_ALLOC,VIOMMU_ATTACH
-VIOMMU_INVALIDATE
By this series nesting setup is done. We need Baolu's solution or VQUEUE for fault reporting after that.
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
Quoted 43 lines
From: Nicolin Chen <[email protected]>
Sent: Thursday, May 23, 2024 2:10 PMQuoted 7 lines · Kevin
Quoted 7 lines
From: Nicolin Chen <[email protected]>
Sent: Monday, May 13, 2024 12:39 PMQuoted 3 lines · Jason Gunthorpe
Quoted 2 lines · Nicolin Chen
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by
iommufd
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The
ID
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
is used by ATC invalidation commands so SMMU HW can direct
invalidation
Quoted 3 lines
Quoted 3 lines
requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the
guest
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
system. NVIDIA's CMDQV extension for SMMUv3 provides a v-
interface
Quoted 10 lines
Quoted 10 lines
to
Quoted 8 lines
Quoted 3 lines
execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
Quoted 8 lines
Quoted 5 lines
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I'm right about to ask how the nesting series is going. Per earlier discussion iirc the nesting series will go in before VCMDQ?
Quoted 8 lines
Yes. It still should. Yet we ended up with adding VIOMMU to the nested SMMU series too. A shared S2 domain/hwpt isn't exclusive for VCMDQ use case but also for regular nesting on a multi-SMMU setup. So, VIOMMU turns out to be the best object that we have at this moment to hold individual VMIDs for different physical SMMUs sharing a single S2 domain. Its virtual device ID lookup feature can also allow us to forget about
DEV_INVALIDATEioctl for now.
Yeah, that makes sense. btw it's probably helpful to future reviews if you can try to include more explanations about the design tradeoff based on those discussions. Somehow it's not easy for me to catch up with those discussions being lacking of many contexts here. 😊
Quoted 12 lines
Jason listed all the tasks ahead in this thread too, using SMMU as an example:
Quoted 8 lines
So we have this stuff still open:
- Identity STE with PASID (part 2b)
-IOMMU_GET_HW_INFO(part 3)
-IOMMU_HWPT_ALLOC_NEST_PARENT(part 3)
-IOMMU_HWPT_DATA_ARM_SMMUV3(part 3)
-IOMMU_HWPT_INVALIDATE_DATA_ARM_SMMUV3
-VIOMMU_ALLOC,VIOMMU_ATTACH
-VIOMMU_INVALIDATE
Quoted 3 lines
By this series nesting setup is done. We need Baolu's solution or VQUEUE for fault reporting after that.
this is a clear plan.
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
In reply to Tian, KevinQuoted 26 lines · Kevin
Quoted 26 lines · Jason Gunthorpe
Quoted 7 lines · Nicolin Chen
Quoted 6 lines
Add a pair of ops to set and unet device's virtual ID that belongs to a viommu object. They will be used, in the following patch, by iommufd to support some HW-acceleration feature from the host level.
For instance, every device behind an ARM SMMU has a Stream ID. The ID is used by ATC invalidation commands so SMMU HW can direct
invalidation
Quoted 4 lines
Quoted 4 lines
requests to the corresponding PCI device where the ID belongs to. In a virtualization use case, a passthroughed device in the VM will have a virtuail Stream ID, used by the ATC invalidation commands in the guest system. NVIDIA's CMDQV extension for SMMUv3 provides a v-interface
to
Quoted 8 lines
Quoted 3 lines
execute the guest-level ATC invalidation commands directly, yet needs the HW to be aware of its virtual Stream ID so it can replace with its physical Stream ID.
I imagine using this as well for the ATC invalidation commands. It would be very easy and simplifying if the command fixup just extracted the vSID from the ATC invalidation and used an xarray to turn it into a pSID and then pushed the resulting command.
You mean the nested SMMU series right? Actually the
set_dev_idioctl was a part of that until we wanted to tryDEV_INVALIDATE.
Quoted 6 lines
Quoted 3 lines
So again, yes, it makes sense to me that we move viommu and the
set_dev_idto the nested series, and then dropDEV_INVALIDATE.I'm right about to ask how the nesting series is going. Per earlier discussion iirc the nesting series will go in before VCMDQ?
It has been sitting on my github, since it is now the N+1 series to merge I will post it in a few weeks. There are still some details yet to be typed in unfortunately.
Jason
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 07/14] iommufd: Add viommu set/unset_dev_id ops
In reply to Nicolin Cheninclude/linux/iommufd.h struct iommufd_viommu { · line 104
Quoted 12 lines · Nicolin Chen
include/linux/iommufd.h +4
-0@@ -94,9 +94,13 @@ struct iommufd_viommu {* struct iommufd_viommu_ops - viommu specific operations * @free: Free all driver-specific parts of an iommufd_viommu. The memory * of the entire viommu will be free-ed by iommufd core +* @set/unset_dev_id: set/unset a user space virtual id for a device */ struct iommufd_viommu_ops {void (*free)(struct iommufd_viommu *viommu); +int (*set_dev_id)(struct iommufd_viommu *viommu, +struct device *dev,u64 dev_id); +void (*unset_dev_id)(struct iommufd_viommu *viommu,struct device *dev);
Actually, looking at this more closely, why doesn't the core pass in dev_id to unset_dev_id? Not doing so seems like it will crease a bunch of unnecessary work for the driver.
Jason
RFC PATCH 8/14 iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Nicolin ChenIntroduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices while it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in their structures to bind them bidirectionally.
--- drivers/iommu/iommufd/device.c | 11 +++++ drivers/iommu/iommufd/iommufd_private.h | 10 +++++ drivers/iommu/iommufd/main.c | 2 + drivers/iommu/iommufd/viommu.c | 58 +++++++++++++++++++++++++ include/linux/iommufd.h | 2 + include/uapi/linux/iommufd.h | 20 +++++++++ 6 files changed, 103 insertions(+)
drivers/iommu/iommufd/device.c +11 -0
@@ -135,7 +135,16 @@ void iommufd_device_destroy(struct iommufd_object *obj) {struct iommufd_device *idev = container_of(obj, struct iommufd_device, obj); +struct iommufd_viommu *viommu; +unsigned long index; +xa_for_each (&idev->viommus, index, viommu) { +if (viommu->ops->unset_dev_id) + viommu->ops->unset_dev_id (viommu, idev->dev); +xa_erase (&viommu->idevs, idev->obj.id); +xa_erase (&idev->viommus, index); + } +xa_destroy (&idev->viommus);iommu_device_release_dma_owner (idev->dev);iommufd_put_group (idev->igroup);if (!iommufd_selftest_is_mock_dev (idev->dev))
@@ -216,6 +225,8 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,/* igroup refcount moves into iommufd_device */ idev->igroup = igroup; +xa_init_flags (&idev->viommus,XA_FLAGS_ALLOC1 ); +/* * If the caller fails after this success it must call * iommufd_unbind_device() which is safe since we hold this refcount.
drivers/iommu/iommufd/iommufd_private.h +10 -0
@@ -392,6 +392,7 @@ struct iommufd_device {struct list_head group_item;/* always the physical device */ struct device *dev; +struct xarray viommus;bool enforce_cache_coherency; };
@@ -424,8 +425,17 @@ void iopt_remove_access(struct io_pagetable *iopt, u32 iopt_access_list_id);void iommufd_access_destroy_object (struct iommufd_object *obj); +static inline struct iommufd_viommu * +iommufd_get_viommu (struct iommufd_ucmd *ucmd,u32 id) +{ +return container_of (iommufd_get_object (ucmd->ictx, id, +IOMMUFD_OBJ_VIOMMU ), + struct iommufd_viommu, obj); +} +int iommufd_viommu_alloc_ioctl (struct iommufd_ucmd *ucmd);void iommufd_viommu_destroy (struct iommufd_object *obj); +int iommufd_viommu_set_device_id (struct iommufd_ucmd *ucmd);#ifdef CONFIG_IOMMUFD_TEST int iommufd_test (struct iommufd_ucmd *ucmd);
drivers/iommu/iommufd/main.c +2 -0
@@ -381,6 +381,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { __reserved),IOCTL_OP (IOMMU_VIOMMU_ALLOC ,iommufd_viommu_alloc_ioctl ,struct iommu_viommu_alloc ,out_viommu_id ), +IOCTL_OP (IOMMU_VIOMMU_SET_DEV_ID ,iommufd_viommu_set_device_id , +struct iommu_viommu_set_dev_id ,id ), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif
drivers/iommu/iommufd/viommu.c +58 -0
67 lines not on this page · raw message
include/linux/iommufd.h +2 -0
@@ -10,6 +10,7 @@#include <linux/errno.h> #include <linux/err.h> #include <linux/refcount.h> +#include <linux/xarray.h> struct device ;struct iommufd_device ;
@@ -88,6 +89,7 @@ struct iommufd_viommu {const struct iommufd_viommu_ops *ops;unsigned int type; +struct xarray idevs; };/**
include/uapi/linux/iommufd.h +20 -0
@@ -51,6 +51,7 @@ enum {IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP ,IOMMUFD_CMD_HWPT_INVALIDATE ,IOMMUFD_CMD_VIOMMU_ALLOC , + IOMMUFD_CMD_VIOMMU_SET_DEV_ID, };/**
@@ -722,4 +723,23 @@ struct iommu_viommu_alloc { __u32 out_viommu_id; };#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC) + +/** +* struct iommu_viommu_set_dev_id - ioctl(IOMMU_VIOMMU_SET_DEV_ID) +* @size: sizeof(struct iommu_viommu_set_dev_id) +* @viommu_id: viommu ID to associate with the device to store its virtual ID +* @dev_id: device ID to set a device virtual ID +* @__reserved: Must be 0 +* @id: Device virtual ID +* +* Set a viommu-specific virtual ID of a device +*/ +struct iommu_viommu_set_dev_id { +__u32 size; +__u32 viommu_id; +__u32 dev_id; +__u32 __reserved; +__aligned_u64 id; +}; +#define IOMMU_VIOMMU_SET_DEV_ID _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_SET_DEV_ID)#endif
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 7 lines · Nicolin Chen
Introduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices while it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in their structures to bind them bidirectionally.
Since I would like to retain the dev_id, I think this is probably better done with an allocated struct per dev-id:
struct dev_id {
struct iommufd_device *idev;
struct iommufd_viommu *viommu;
u64 vdev_id;
u64 driver_private; // Ie the driver can store the pSID here
struct list_head idev_entry;
};drivers/iommu/iommufd/device.c void iommufd_device_destroy(struct iommufd_object *obj) · line 146
Quoted 13 lines
drivers/iommu/iommufd/device.c +8
-0@@ -135,7 +135,16 @@ void iommufd_device_destroy(struct iommufd_object *obj) {struct iommufd_device *idev = container_of(obj, struct iommufd_device, obj); +struct iommufd_viommu *viommu; +unsigned long index; +xa_for_each (&idev->viommus, index, viommu) { +if (viommu->ops->unset_dev_id) + viommu->ops->unset_dev_id (viommu, idev->dev); +xa_erase (&viommu->idevs, idev->obj.id); +xa_erase (&idev->viommus, index); + }
Then this turns into list_for_each(idev->viommu_vdevid_list)
Quoted 29 lines
drivers/iommu/iommufd/viommu.c +29
-0+int iommufd_viommu_set_device_id (struct iommufd_ucmd *ucmd) +{ +struct iommu_viommu_set_dev_id *cmd = ucmd->cmd; +unsigned int dev_id, viommu_id; +struct iommufd_viommu *viommu; +struct iommufd_device *idev; +int rc; + + idev =iommufd_get_device (ucmd, cmd->dev_id); +if (IS_ERR (idev)) +return PTR_ERR (idev); + dev_id = idev->obj.id; + + viommu =iommufd_get_viommu (ucmd, cmd->viommu_id); +if (IS_ERR (viommu)) { + rc =PTR_ERR (viommu); + goto out_put_idev; + } + +if (viommu->iommu_dev != idev->dev->iommu->iommu_dev) { + rc = -EINVAL ; + goto out_put_viommu; + } + +if (!viommu->ops->set_dev_id || !viommu->ops->unset_dev_id) { + rc = -EOPNOTSUPP ; + goto out_put_viommu; + } +
drivers/iommu/iommufd/viommu.c int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd) · line 145
Quoted 10 lines
drivers/iommu/iommufd/viommu.c +10
-0+ rc =xa_alloc (&idev->viommus, &viommu_id, viommu, +XA_LIMIT (viommu->obj.id, viommu->obj.id), +GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_put_viommu; + + rc =xa_alloc (&viommu->idevs, &dev_id, idev, +XA_LIMIT (dev_id, dev_id),GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_xa_erase_viommu;
Both of these are API mis-uses, you don't want an allocating xarray you just want to use xa_cmpxchg
Put an xarray in the viommu object and fill it with pointers to the struct dev_id thing above
The driver can piggyback on this xarray too if it wants, so we only need one.
xa_cmpchg to install the user requests vdev_id only if the vdev_id is already unused.
include/uapi/linux/iommufd.h enum { · line 55
Quoted 6 lines
include/uapi/linux/iommufd.h +1
-0@@ -51,6 +51,7 @@ enum {IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP ,IOMMUFD_CMD_HWPT_INVALIDATE ,IOMMUFD_CMD_VIOMMU_ALLOC , + IOMMUFD_CMD_VIOMMU_SET_DEV_ID, };
We almost certainly will need a REMOVE_DEV_ID so userspace can have sensible error handling.
Quoted 7 lines
include/uapi/linux/iommufd.h +7
-0+ +/** +* struct iommu_viommu_set_dev_id - ioctl(IOMMU_VIOMMU_SET_DEV_ID) +* @size: sizeof(struct iommu_viommu_set_dev_id) +* @viommu_id: viommu ID to associate with the device to store its virtual ID +* @dev_id: device ID to set a device virtual ID +* @__reserved: Must be 0
include/uapi/linux/iommufd.h struct iommu_viommu_alloc { · line 742
Quoted 10 lines
include/uapi/linux/iommufd.h +10
-0+* @id: Device virtual ID +* +* Set a viommu-specific virtual ID of a device +*/ +struct iommu_viommu_set_dev_id { +__u32 size; +__u32 viommu_id; +__u32 dev_id; +__u32 __reserved; +__aligned_u64 id;
I think I'd consistently call this vdev_id throughout the API
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 12 lines · Jason Gunthorpe
Quoted 7 lines · Nicolin Chen
Introduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices while it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in their structures to bind them bidirectionally.
Since I would like to retain the
dev_id, I think this is probably better done with an allocated struct per dev-id:
Quoted 7 lines
struct dev_id {
struct iommufd_device *idev;
struct iommufd_viommu *viommu;
u64 vdev_id;
u64 driver_private; // Ie the driver can store the pSID here
struct list_head idev_entry;
};Oh, I needed a better solution to store the HW slot number of a VINTF configuration that links a pSID and a vSID, which I hacked into struct arm_smmu_stream for now. So, with this struct dev_id, likely I can tie it to this structure.
For a driver, pSID is known with a device pointer, while likely no use to the iommufd core?
Also, I will address the other comments in your reply.
Thanks
Nicolin
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Jason GunthorpeQuoted 12 lines · Jason Gunthorpe
Quoted 7 lines · Nicolin Chen
Introduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices while it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in their structures to bind them bidirectionally.
Since I would like to retain the
dev_id, I think this is probably better done with an allocated struct per dev-id:
Quoted 7 lines
struct dev_id {
struct iommufd_device *idev;
struct iommufd_viommu *viommu;
u64 vdev_id;
u64 driver_private; // Ie the driver can store the pSID here
struct list_head idev_entry;
};I implemented it with a small tweak, to align with viommu_alloc and vqueue_alloc:
// core
struct iommufd_vdev_id {
struct iommufd_viommu *viommu;
struct device *dev;
u64 vdev_id;
struct list_head idev_item;
};
// driver
struct my_driver_vdev_id {
struct iommufd_vdev_id core;
unsigned int private_attrs;
};
static struct iommufd_vdev_id *
my_driver_set_vdev_id(struct iommufd_viommu *viommu,
struct device *dev, u64 id)
{
struct my_driver_vdev_id *my_vdev_id;
my_vdev_id = kzalloc(sizeof(*my_vdev_id), GFP_KERNEL);
.... /* set private_attrs */
return &my_driver_vdev_id->core;
}
static void my_driver_unset_vdev_id(struct iommufd_vdev_id *vdev_id)
{
struct my_driver_vdev_id *my_vdev_id =
container_of(vdev_id, struct my_driver_vdev_id, core);
.... /* unset private_attrs */
}Please let me know if you like it inverted as you wrote above.
Quoted 7 lines
Quoted 7 lines
drivers/iommu/iommufd/device.c +2
-0@@ -135,7 +135,16 @@ void iommufd_device_destroy(struct iommufd_object *obj) {struct iommufd_device *idev = container_of(obj, struct iommufd_device, obj); +struct iommufd_viommu *viommu; +unsigned long index;
Quoted 8 lines
drivers/iommu/iommufd/device.c void iommufd_device_destroy(struct iommufd_object *obj) · line 146
Quoted 6 lines
drivers/iommu/iommufd/device.c +6
-0+xa_for_each (&idev->viommus, index, viommu) { +if (viommu->ops->unset_dev_id) + viommu->ops->unset_dev_id (viommu, idev->dev); +xa_erase (&viommu->idevs, idev->obj.id); +xa_erase (&idev->viommus, index); + }Then this turns into
list_for_each(idev->viommu_vdevid_list)
Done.
Quoted 2 lines
Quoted 2 lines
drivers/iommu/iommufd/viommu.c +2
-0+int iommufd_viommu_set_device_id (struct iommufd_ucmd *ucmd) +{
...
Quoted 14 lines
drivers/iommu/iommufd/viommu.c int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd) · line 145
Quoted 10 lines
drivers/iommu/iommufd/viommu.c +10
-0+ rc =xa_alloc (&idev->viommus, &viommu_id, viommu, +XA_LIMIT (viommu->obj.id, viommu->obj.id), +GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_put_viommu; + + rc =xa_alloc (&viommu->idevs, &dev_id, idev, +XA_LIMIT (dev_id, dev_id),GFP_KERNEL_ACCOUNT ); +if (rc) + goto out_xa_erase_viommu;Both of these are API mis-uses, you don't want an allocating xarray you just want to use
xa_cmpxchg
Quoted 5 lines
Put an xarray in the viommu object and fill it with pointers to the struct
dev_idthing aboveThe driver can piggyback on this xarray too if it wants, so we only need one.
I also moved xa_cmpxchg to the driver, as I feel that the vdev_id here is very driver/iommu specific. There can be some complication if iommufd core handles this u64 vdev_id: most likely we will use this u64 vdev_id to index the xarray that takes an unsigned-long xa_index for a fast vdev_id-to-pdev_id lookup, while only a driver knows whether u64 vdev_id is compatible with unsigned long or not.
And, we have a list_head in the structure idev, so a device unbind will for-each the list and unset all the vdev_ids in it, meanwhile the viommu stays. I wonder if we need to add another list_head in the structure viommu, so a viommu tear down will for-each its list and unset all the vdev_ids on its side while a device (idev) stays. I don't see a use case of that though..any thought?
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 35 lines · Nicolin Chen
I implemented it with a small tweak, to align with
viommu_allocandvqueue_alloc:// core struct iommufd_vdev_id { struct iommufd_viommu *viommu; struct device *dev; u64 vdev_id; struct list_head idev_item; }; // driver struct my_driver_vdev_id { struct iommufd_vdev_id core; unsigned int private_attrs; }; static struct iommufd_vdev_id * my_driver_set_vdev_id(struct iommufd_viommu *viommu, struct device *dev, u64 id) { struct my_driver_vdev_id *my_vdev_id; my_vdev_id = kzalloc(sizeof(*my_vdev_id), GFP_KERNEL); .... /* set private_attrs */ return &my_driver_vdev_id->core; } static void my_driver_unset_vdev_id(struct iommufd_vdev_id *vdev_id) { struct my_driver_vdev_id *my_vdev_id = container_of(vdev_id, struct my_driver_vdev_id, core); .... /* unset private_attrs */ }
Quoted 1 line
Please let me know if you like it inverted as you wrote above.
Seems like a reasonable direction
Quoted 6 lines
I also moved
xa_cmpxchgto the driver, as I feel that thevdev_idhere is very driver/iommu specific. There can be some complication if iommufd core handles this u64vdev_id: most likely we will use this u64vdev_idto index the xarray that takes an unsigned-longxa_indexfor a fast vdev_id-to-pdev_id lookup, while only a driver knows whether u64vdev_idis compatible with unsigned long or not.
This seems like the most general part.. The core code should just have a check like:
if (vdevid >= ULONG_MAX) return -EINVAL;
And if someone wants to make 32 bit kernels support a 64bit vdevid then they can sort it out someday :) I think this is not a big issue as all iommus seem to have some kind of radix lookup for vdevid and want it to be small.
Matthew has been talking about support for 64bit indexes in maple/xarray or something for a bit so it might sort itself out.
Quoted 6 lines
And, we have a
list_headin the structure idev, so a device unbind will for-each the list and unset all thevdev_idsin it, meanwhile the viommu stays. I wonder if we need to add anotherlist_headin the structure viommu, so a viommu tear down will for-each its list and unset all thevdev_idson its side while a device (idev) stays. I don't see a use case of that though..any thought?
I think you need to support viommu teardown, at least from a correctness perspective. The API permits it. But isn't it just list_del everything in the xarray and that will clean it up enough?
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 8 lines · Jason Gunthorpe
Quoted 6 lines · Nicolin Chen
I also moved
xa_cmpxchgto the driver, as I feel that thevdev_idhere is very driver/iommu specific. There can be some complication if iommufd core handles this u64vdev_id: most likely we will use this u64vdev_idto index the xarray that takes an unsigned-longxa_indexfor a fast vdev_id-to-pdev_id lookup, while only a driver knows whether u64vdev_idis compatible with unsigned long or not.
Quoted 4 lines
This seems like the most general part.. The core code should just have a check like:
if (vdevid >= ULONG_MAX) return -EINVAL;
Ack.
Quoted 7 lines
And if someone wants to make 32 bit kernels support a 64bit vdevid then they can sort it out someday :) I think this is not a big issue as all iommus seem to have some kind of radix lookup for vdevid and want it to be small.
Matthew has been talking about support for 64bit indexes in maple/xarray or something for a bit so it might sort itself out.
OK. In that case, the core can do the xarray maintenance.
And then..
Quoted 10 lines
Quoted 6 lines
And, we have a
list_headin the structure idev, so a device unbind will for-each the list and unset all thevdev_idsin it, meanwhile the viommu stays. I wonder if we need to add anotherlist_headin the structure viommu, so a viommu tear down will for-each its list and unset all thevdev_idson its side while a device (idev) stays. I don't see a use case of that though..any thought?I think you need to support viommu teardown, at least from a correctness perspective. The API permits it. But isn't it just
list_deleverything in the xarray and that will clean it up enough?
... viommu tear down can xa_for_each to call unset_vdev_id().
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Nicolin ChenQuoted 7 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMIntroduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices
this is true...
Quoted 3 lines
while
it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in
...but why would one device link to multiple viommu instances?
Or is it referring to Tegra194 as arm-smmu-nvidia.c tries to support?
In any case a real example might be useful as this may not be a given knowledge to all folks.
btw there is a check in the following code:
+ if (viommu->iommu_dev != idev->dev->iommu->iommu_dev) {
+ rc = -EINVAL;
+ goto out_put_viommu;
+ }
I vaguely remember an earlier discussion about multiple vSMMU instances following the physical SMMU topology, but don't quite recall the exact reason.
What is the actual technical obstacle prohibiting one to put multiple VCMDQ's from different SMMU's into one vIOMMU instance?
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 8 lines · Kevin
Quoted 7 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMIntroduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices
Quoted 7 lines
this is true...
Quoted 3 lines
while
it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in...but why would one device link to multiple viommu instances?
That's a suggestion from Jason, IIRC, to avoid limiting a device to a single viommu, though I can't find out the source at this moment.
Jason, would you mind shed some light here?
Quoted 1 line
Or is it referring to Tegra194 as
arm-smmu-nvidia.ctries to support?
Not actual. It's an SMMUv2 driver, which is not in our plan for virtualization at this moment. And that driver is essentially a different "compatible" string as a unique SMMUv2 implementation.
Quoted 7 lines
btw there is a check in the following code:
drivers/iommu/iommufd/viommu.c +4
-0+if (viommu->iommu_dev != idev->dev->iommu->iommu_dev) { + rc = -EINVAL ; + goto out_put_viommu; + }
Quoted 6 lines
I vaguely remember an earlier discussion about multiple vSMMU instances following the physical SMMU topology, but don't quite recall the exact reason.
What is the actual technical obstacle prohibiting one to put multiple VCMDQ's from different SMMU's into one vIOMMU instance?
Because a VCMDQ passthrough involves a direct mmap of a HW MMIO page to the guest-level MMIO region. The MMIO page provides the read/write of queue's head and tail indexes.
With a single pSMMU and a single vSMMU, it's simply 1:1 mapping.
With a multi-pSMMU and a single vSMMU, the single vSMMU will see one guest-level MMIO region backed by multiple physical pages. Since we are talking about MMIO, technically it cannot select the corresponding MMIO page to the device, not to mention we don't really want VMM to involve, i.e. no VM exist, when using VCMDQ.
So, there must be some kind of multi-instanced carriers to hold those MMIO pages, by attaching devices behind different pSMMUs to corresponding carriers. And today we have VIOMMU as the carrier.
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 22 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 1:40 PMQuoted 7 lines · Kevin
btw there is a check in the following code:
drivers/iommu/iommufd/viommu.c +4
-0+if (viommu->iommu_dev != idev->dev->iommu->iommu_dev) { + rc = -EINVAL ; + goto out_put_viommu; + }Quoted 6 lines
I vaguely remember an earlier discussion about multiple vSMMU instances following the physical SMMU topology, but don't quite recall the exact reason.
What is the actual technical obstacle prohibiting one to put multiple VCMDQ's from different SMMU's into one vIOMMU instance?
Because a VCMDQ passthrough involves a direct mmap of a HW MMIO page to the guest-level MMIO region. The MMIO page provides the read/write of queue's head and tail indexes.
Quoted 7 lines
With a single pSMMU and a single vSMMU, it's simply 1:1 mapping.
With a multi-pSMMU and a single vSMMU, the single vSMMU will see one guest-level MMIO region backed by multiple physical pages. Since we are talking about MMIO, technically it cannot select the corresponding MMIO page to the device, not to mention we don't really want VMM to involve, i.e. no VM exist, when using VCMDQ.
can a vSMMU report to support multiple CMDQ's then there are several MMIO regions each mapped to a different backend VCMDQ?
but I guess even if it's supported there is still a problem describing the association between assigned devices and the CMDQ's of the single vIOMMU instance. On bare metal a feature of multiple CMDQ is more for load-balancing so there won't be a fixed association between CMDQ/device. But the fixed association exists if we mixes multiple VCMDQ's in a single vIOMMU instance then there may lack of a way in spec to describe it.
Quoted 11 lines
So, there must be some kind of multi-instanced carriers to hold those MMIO pages, by attaching devices behind different pSMMUs to corresponding carriers. And today we have VIOMMU as the carrier.
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 24 lines · Kevin
Quoted 24 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 1:40 PMQuoted 7 lines · Kevin
btw there is a check in the following code:
drivers/iommu/iommufd/viommu.c +4
-0+if (viommu->iommu_dev != idev->dev->iommu->iommu_dev) { + rc = -EINVAL ; + goto out_put_viommu; + }Quoted 6 lines
I vaguely remember an earlier discussion about multiple vSMMU instances following the physical SMMU topology, but don't quite recall the exact reason.
What is the actual technical obstacle prohibiting one to put multiple VCMDQ's from different SMMU's into one vIOMMU instance?
Because a VCMDQ passthrough involves a direct mmap of a HW MMIO page to the guest-level MMIO region. The MMIO page provides the read/write of queue's head and tail indexes.
With a single pSMMU and a single vSMMU, it's simply 1:1 mapping.
Quoted 8 lines
Quoted 5 lines
With a multi-pSMMU and a single vSMMU, the single vSMMU will see one guest-level MMIO region backed by multiple physical pages. Since we are talking about MMIO, technically it cannot select the corresponding MMIO page to the device, not to mention we don't really want VMM to involve, i.e. no VM exist, when using VCMDQ.
can a vSMMU report to support multiple CMDQ's then there are several MMIO regions each mapped to a different backend VCMDQ?
This is something I want to support in the API, regardless vCMDQ uses it or not..
Quoted 3 lines
but I guess even if it's supported there is still a problem describing the association between assigned devices and the CMDQ's of the single vIOMMU instance.
CMDQ should be linked to the VIOMMU instance only and not per-device, I think that is a very important property of the system.
This means if there are multiple pSMMU instances then we need a matching set of vSMMU instances so that the devices are grouped on the proper vSMMU instance so they are compatible with the vCMDQ.
Quoted 4 lines
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, May 24, 2024 9:19 PMQuoted 4 lines · Kevin
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Quoted 6 lines
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Yes this part is clear now regarding to VCMDQ.
But Nicoline said:
"
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
"
I don't think there is an arch limitation mandating that?
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 28 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, May 24, 2024 9:19 PMQuoted 4 lines · Kevin
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Quoted 6 lines
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Yes this part is clear now regarding to VCMDQ.
But Nicoline said:
"
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
"
Quoted 1 line
I don't think there is an arch limitation mandating that?
What I mean is for regular vSMMU. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<------ VMM ------->|<------ kernel ------>|
|-- viommu0 --|-- pSMMU0 --|
vSMMU--|-- viommu1 --|-- pSMMU1 --|--s2_hwpt
|-- viommu2 --|-- pSMMU2 --|And device would attach to:
|<---- guest ---->|<--- VMM --->|<- kernel ->|
|-- dev0 --|-- viommu0 --|-- pSMMU0 --|
vSMMU--|-- dev1 --|-- viommu1 --|-- pSMMU1 --|
|-- dev2 --|-- viommu2 --|-- pSMMU2 --|When trapping a device cache invalidation: it is straightforward by deciphering the virtual device ID to pick the viommu that the device is attached to.
When doing iotlb invalidation, a command may or may not contain an ASID (a domain ID, and nested domain in this case):
a) if a command doesn't have an ASID, VMM needs to broadcast the command to all viommus (i.e. pSMMUs)
b) if a command has an ASID, VMM needs to initially maintain an S1 HWPT list by linking an ASID when adding an HWPT entry to the list, by deciphering vSTE and its linked CD. Then it needs to go through the S1 list with the ASID in the command, and to find all corresponding HWPTs to issue/broadcast the command.
Thanks
Nicolin
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 39 lines · Nicolin Chen
Quoted 28 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, May 24, 2024 9:19 PMQuoted 4 lines · Kevin
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Quoted 6 lines
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Yes this part is clear now regarding to VCMDQ.
But Nicoline said:
"
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
"Quoted 1 line
I don't think there is an arch limitation mandating that?
What I mean is for regular vSMMU. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<------ VMM ------->|<------ kernel ------>| |-- viommu0 --|-- pSMMU0 --| vSMMU--|-- viommu1 --|-- pSMMU1 --|--s2_hwpt |-- viommu2 --|-- pSMMU2 --|
Quoted 5 lines
And device would attach to:
|<---- guest ---->|<--- VMM --->|<- kernel ->| |-- dev0 --|-- viommu0 --|-- pSMMU0 --| vSMMU--|-- dev1 --|-- viommu1 --|-- pSMMU1 --| |-- dev2 --|-- viommu2 --|-- pSMMU2 --|
I accidentally sent a duplicated one.. Please ignore this reply and check the other one. Thanks!
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Nicolin ChenQuoted 43 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 4:23 AMQuoted 28 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, May 24, 2024 9:19 PMQuoted 4 lines · Kevin
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Quoted 6 lines
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Yes this part is clear now regarding to VCMDQ.
But Nicoline said:
"
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
"Quoted 1 line
I don't think there is an arch limitation mandating that?
What I mean is for regular vSMMU. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<------ VMM ------->|<------ kernel ------>| |-- viommu0 --|-- pSMMU0 --| vSMMU--|-- viommu1 --|-- pSMMU1 --|--s2_hwpt |-- viommu2 --|-- pSMMU2 --|And device would attach to:
Quoted 8 lines
|<---- guest ---->|<--- VMM --->|<- kernel ->| |-- dev0 --|-- viommu0 --|-- pSMMU0 --| vSMMU--|-- dev1 --|-- viommu1 --|-- pSMMU1 --| |-- dev2 --|-- viommu2 --|-- pSMMU2 --|When trapping a device cache invalidation: it is straightforward by deciphering the virtual device ID to pick the viommu that the device is attached to.
I understand how above works.
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Quoted 13 lines
When doing iotlb invalidation, a command may or may not contain an ASID (a domain ID, and nested domain in this case):
a) if a command doesn't have an ASID, VMM needs to broadcast the command to all viommus (i.e. pSMMUs)
b) if a command has an ASID, VMM needs to initially maintain an S1 HWPT list by linking an ASID when adding an HWPT entry to the list, by deciphering vSTE and its linked CD. Then it needs to go through the S1 list with the ASID in the command, and to find all corresponding HWPTs to issue/broadcast the command.Thanks
Nicolin
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 23 lines · Kevin
Quoted 12 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 4:23 AMWhat I mean is for regular vSMMU. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<------ VMM ------->|<------ kernel ------>| |-- viommu0 --|-- pSMMU0 --| vSMMU--|-- viommu1 --|-- pSMMU1 --|--s2_hwpt |-- viommu2 --|-- pSMMU2 --|And device would attach to:
Quoted 8 lines
|<---- guest ---->|<--- VMM --->|<- kernel ->| |-- dev0 --|-- viommu0 --|-- pSMMU0 --| vSMMU--|-- dev1 --|-- viommu1 --|-- pSMMU1 --| |-- dev2 --|-- viommu2 --|-- pSMMU2 --|When trapping a device cache invalidation: it is straightforward by deciphering the virtual device ID to pick the viommu that the device is attached to.
I understand how above works.
Quoted 7 lines
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared s2_hwpt:
|-- viommu0 (VMIDx) --|-- pSMMU0 --|
vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt
|-- viommu2 (VMIDz) --|-- pSMMU2 --|Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 32 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 28 lines · Kevin
Quoted 12 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 4:23 AMWhat I mean is for regular vSMMU. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<------ VMM ------->|<------ kernel ------>| |-- viommu0 --|-- pSMMU0 --| vSMMU--|-- viommu1 --|-- pSMMU1 --|--s2_hwpt |-- viommu2 --|-- pSMMU2 --|And device would attach to:
Quoted 8 lines
|<---- guest ---->|<--- VMM --->|<- kernel ->| |-- dev0 --|-- viommu0 --|-- pSMMU0 --| vSMMU--|-- dev1 --|-- viommu1 --|-- pSMMU1 --| |-- dev2 --|-- viommu2 --|-- pSMMU2 --|When trapping a device cache invalidation: it is straightforward by deciphering the virtual device ID to pick the viommu that the device is attached to.
I understand how above works.
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
Quoted 9 lines
Quoted 2 lines
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
so it's really an implementation choice that you want a same viommu topology scheme w/ or w/o VCMDQ.
we all know there are some constraints of copying the physical topology, e.g. hotplugging a device or migration. for VCMDQ it's clearly an acceptable tradeoff for performance. w/o VCMDQ I'm not sure whether you want to keep more flexibility for the user. 😊
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 18 lines · Kevin
Quoted 8 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 5 lines · Kevin
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
Quoted 9 lines
Quoted 2 lines
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|
Quoted 2 lines
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
Well, possibly. But everything previously in a viommu would have to be a list (for number of VMIDs) in the kernel level: not only a VMID list, but also a 2D virtual ID lists, something like:
struct xarray vdev_ids[num_of_vmid]; // per-IOMMU vID to pID lookup
And a driver in this case would be difficult to get a complete concept of a viommu object since it's core object and shared by all kernel-level IOMMU instances. If a driver wants to extend a viommu object for some additional feature, e.g. VINTF in this series, it would likely have to create another per-driver object and again another list of this kind of objects in struct viommu.
At the end of day, we have to duplicate it one way or another for the amount of physical IOMMUs. And it seems to cleaner by doing it with multiple viommu objects.
Quoted 7 lines
so it's really an implementation choice that you want a same viommu topology scheme w/ or w/o VCMDQ.
we all know there are some constraints of copying the physical topology, e.g. hotplugging a device or migration. for VCMDQ it's clearly an acceptable tradeoff for performance. w/o VCMDQ I'm not sure whether you want to keep more flexibility for the user. 😊
Oh. With regular nested SMMU, there is only one virtual SMMU in the guest VM. No need of copying physical topology. Just the VMM needs to allocate three viommus to add them to a list of its own.
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 22 lines
From: Nicolin Chen <[email protected]>
Sent: Thursday, May 30, 2024 8:59 AMQuoted 18 lines · Kevin
Quoted 17 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 7 lines · Kevin
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|
Quoted 8 lines
Quoted 2 lines
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
Well, possibly. But everything previously in a viommu would have to be a list (for number of VMIDs) in the kernel level: not only a VMID list, but also a 2D virtual ID lists, something like:
struct xarray vdev_ids[num_of_vmid]; // per-IOMMU vID to pID lookup
ah does it mean that dev ID space on ARM is local to SMMU?
It's not the case on x86 platforms where the RID is platform-wise.
Quoted 15 lines
And a driver in this case would be difficult to get a complete concept of a viommu object since it's core object and shared by all kernel-level IOMMU instances. If a driver wants to extend a viommu object for some additional feature, e.g. VINTF in this series, it would likely have to create another per-driver object and again another list of this kind of objects in struct viommu.
At the end of day, we have to duplicate it one way or another for the amount of physical IOMMUs. And it seems to cleaner by doing it with multiple viommu objects.
Quoted 3 lines
so it's really an implementation choice that you want a same viommu topology scheme w/ or w/o VCMDQ.
Quoted 9 lines
Quoted 4 lines
we all know there are some constraints of copying the physical topology, e.g. hotplugging a device or migration. for VCMDQ it's clearly an acceptable tradeoff for performance. w/o VCMDQ I'm not sure whether you want to keep more flexibility for the user. 😊
Oh. With regular nested SMMU, there is only one virtual SMMU in the guest VM. No need of copying physical topology. Just the VMM needs to allocate three viommus to add them to a list of its own.
Okay I missed this point. Then the number of viommus is really about the contract between the vmm and the kernel, which is invisible to the guest or the admin who launches the Qemu.
but wait, isn't there another problem - does the VMM have the
permission to enumerate the topology of physical SMMUs? Or probably
the VMM only needs to know the number of relevant SMMUs for
assigned devices and such info can be indirectly composed by extending GET_HW_INFO...
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 28 lines · Kevin
Quoted 28 lines
From: Nicolin Chen <[email protected]>
Sent: Thursday, May 30, 2024 8:59 AMQuoted 18 lines · Kevin
Quoted 8 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 5 lines · Kevin
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
Quoted 9 lines
Quoted 2 lines
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|Quoted 2 lines
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
Well, possibly. But everything previously in a viommu would have to be a list (for number of VMIDs) in the kernel level: not only a VMID list, but also a 2D virtual ID lists, something like:
Quoted 5 lines
Quoted 1 line
struct xarray vdev_ids[num_of_vmid]; // per-IOMMU vID to pID lookup
ah does it mean that dev ID space on ARM is local to SMMU?
It's not the case on x86 platforms where the RID is platform-wise.
Actually I had a second thought after I replied. Yea, we only support PCI devices at this moment, so their RIDs come from BDF numbers, and then should be platform-wise as you pointed out:
|<-------VMM-------->|<--------------- kernel ------------>| vRID_a --| |-- VMIDx / SMMU0 -- pRID_A vRID_b --| => vSMMU => viommu => |-- VMIDy / SMMU1 -- pRID_B vRID_c --| |-- VMIDz / SMMU2 -- pRID_C
# x/y/z can be identical, while a/b/c and A/B/C must be unique.
So likely a single lookup list can be enough. That still can't avoid the list of per-pIOMMU objects for some driver feature though. So, I think having a per-pIOMMU viommu also adds a bit of flexibility for the kernel.
Overall, indeed an implementation choice, as you mentioned :)
Quoted 19 lines
Quoted 19 lines
And a driver in this case would be difficult to get a complete concept of a viommu object since it's core object and shared by all kernel-level IOMMU instances. If a driver wants to extend a viommu object for some additional feature, e.g. VINTF in this series, it would likely have to create another per-driver object and again another list of this kind of objects in struct viommu.
At the end of day, we have to duplicate it one way or another for the amount of physical IOMMUs. And it seems to cleaner by doing it with multiple viommu objects.
Quoted 7 lines
so it's really an implementation choice that you want a same viommu topology scheme w/ or w/o VCMDQ.
we all know there are some constraints of copying the physical topology, e.g. hotplugging a device or migration. for VCMDQ it's clearly an acceptable tradeoff for performance. w/o VCMDQ I'm not sure whether you want to keep more flexibility for the user. 😊
Quoted 8 lines
Quoted 4 lines
Oh. With regular nested SMMU, there is only one virtual SMMU in the guest VM. No need of copying physical topology. Just the VMM needs to allocate three viommus to add them to a list of its own.
Okay I missed this point. Then the number of viommus is really about the contract between the vmm and the kernel, which is invisible to the guest or the admin who launches the Qemu.
Yes. Everything should be behind the scene, since VMM can trap and select, unlike VCMDQ doing direct MMIO to the HW without a chance of VM Exits.
Quoted 4 lines
but wait, isn't there another problem - does the VMM have the
permission to enumerate the topology of physical SMMUs? Or probably
the VMM only needs to know the number of relevant SMMUs for
assigned devices and such info can be indirectly composed by extendingGET_HW_INFO...
I think VMM already has some kinda permission reading the number of IOMMUs from "/sys/class/iommu"?
That being said, in a regular nesting case w/o VCMDQ, there is no need to instantiate all vSMMUs to the number of pSMMUs unless there is at least one device behind each pSMMU attaches.
So, the current implementation allocates an s2_hwpt/viommu only on demand, when the first device from a physical SMMU attaches, meaning there'll be only one viommu in the list until the other first device from another pSMMU attaches. And the actual attach logical always tries attaching a device to the existing viommus from the list, and only allocates a new viommu (or s2_hwpt) when all of them failed. FWIW, host-kernel/driver has a full control against these attaches.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Nicolin ChenQuoted 19 lines · Nicolin Chen
Quoted 18 lines · Kevin
Quoted 17 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 7 lines · Kevin
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|
Quoted 8 lines
Quoted 2 lines
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
Well, possibly. But everything previously in a viommu would have to be a list (for number of VMIDs) in the kernel level: not only a VMID list, but also a 2D virtual ID lists, something like:
struct xarray vdev_ids[num_of_vmid]; // per-IOMMU vID to pID lookup
I feel it makes most sense that ARM (and maybe everyone) just have a viommu per piommu.
The main argument against is we haven't made it efficient for the VMM to support multiple piommus. It has to do a system call per piommu each time it processes the cmdq.
But, on the other hand, if you care about invalidation efficiency it is kind of silly not to expose the piommus to the guest so that the invalidation scope can be appropriately narrowed. Replicating all ASID invalidations to all piommus doesn't make alot of sense if the guest can know that only one piommu actually needs invalidation.
Quoted 6 lines
And a driver in this case would be difficult to get a complete concept of a viommu object since it's core object and shared by all kernel-level IOMMU instances. If a driver wants to extend a viommu object for some additional feature, e.g. VINTF in this series, it would likely have to create another per-driver object and again another list of this kind of objects in struct viommu.
Right, we need some kind of per-piommu object because we have per-piommu data.
Quoted 3 lines
Oh. With regular nested SMMU, there is only one virtual SMMU in the guest VM. No need of copying physical topology. Just the VMM needs to allocate three viommus to add them to a list of its own.
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts, if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 36 lines · Jason Gunthorpe
Quoted 19 lines · Nicolin Chen
Quoted 18 lines · Kevin
Quoted 17 lines
From: Nicolin Chen <[email protected]>
Sent: Wednesday, May 29, 2024 11:21 AMQuoted 7 lines · Kevin
My question is why that option is chosen instead of going with 1:1 mapping between vSMMU and viommu i.e. letting the kernel to figure out which pSMMU should be sent an invalidation cmd to, as how VT-d is virtualized.
I want to know whether doing so is simply to be compatible with what VCMDQ requires, or due to another untold reason.
Because we use viommu as a VMID holder for SMMU. So a pSMMU must have its own viommu to store its VMID for a shared
s2_hwpt:|-- viommu0 (VMIDx) --|-- pSMMU0 --| vSMMU--|-- viommu1 (VMIDy) --|-- pSMMU1 --|--s2_hwpt |-- viommu2 (VMIDz) --|-- pSMMU2 --|Quoted 8 lines
Quoted 2 lines
there are other options, e.g. you can have one viommu holding multiple VMIDs each associating to a pSMMU.
Well, possibly. But everything previously in a viommu would have to be a list (for number of VMIDs) in the kernel level: not only a VMID list, but also a 2D virtual ID lists, something like:
struct xarray vdev_ids[num_of_vmid]; // per-IOMMU vID to pID lookup
I feel it makes most sense that ARM (and maybe everyone) just have a viommu per piommu.
The main argument against is we haven't made it efficient for the VMM to support multiple piommus. It has to do a system call per piommu each time it processes the cmdq.
Quoted 5 lines
But, on the other hand, if you care about invalidation efficiency it is kind of silly not to expose the piommus to the guest so that the invalidation scope can be appropriately narrowed. Replicating all ASID invalidations to all piommus doesn't make alot of sense if the guest can know that only one piommu actually needs invalidation.
Yea, that'd be pretty slow, though a broadcast would be still inevitable when an invalidation only has an address range w/o an ASID, CMD_TLBI_NH_VAA for example.
In fact, there should always be a dispatcher (v.s. broadcast):
- in the one-viommu-per-pIOMMU case (#1), it's in the VMM
- in the one-viommu-per-vIOMMU case (#2), it's in the kernel
One of them has to take the role to burn some CPUs for-eaching the hwpt list to identify the iommu to forward. The design #1, simply makes the kernel easier.
The design #2, on the other hand, would not only require some lists and new objects that we just discussed, yet also pair of VIOMMU_SET/UNSET_HWPT_ID ioctls, though it also makes sense as we choose IOMMU_VIOMMU_INVALIDATE over IOMMU_DEV_INVALIDATE by adding VIOMMU_SET/UNSET_VDEV_ID?
Quoted 10 lines
Quoted 6 lines
And a driver in this case would be difficult to get a complete concept of a viommu object since it's core object and shared by all kernel-level IOMMU instances. If a driver wants to extend a viommu object for some additional feature, e.g. VINTF in this series, it would likely have to create another per-driver object and again another list of this kind of objects in struct viommu.
Right, we need some kind of per-piommu object because we have per-piommu data.
Quoted 8 lines
Quoted 3 lines
Oh. With regular nested SMMU, there is only one virtual SMMU in the guest VM. No need of copying physical topology. Just the VMM needs to allocate three viommus to add them to a list of its own.
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 10 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 7 lines · Jason Gunthorpe
Quoted 5 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Quoted 8 lines
Quoted 5 lines
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Thanks for clarifying. That also means you'd prefer putting the command dispatcher in VMM, which is what we have at this moment.
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 11 lines · Nicolin Chen
Quoted 10 lines · Jason Gunthorpe
Quoted 8 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Thanks for clarifying. That also means you'd prefer putting the command dispatcher in VMM, which is what we have at this moment.
Unless someone knows a reason why we should strive hard to have only a single vSMMU and accept some invalidation inefficiency?
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 18 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, June 7, 2024 8:27 AMQuoted 14 lines · Nicolin Chen
Quoted 13 lines · Jason Gunthorpe
Quoted 10 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Thanks for clarifying. That also means you'd prefer putting the command dispatcher in VMM, which is what we have at this moment.
Unless someone knows a reason why we should strive hard to have only a single vSMMU and accept some invalidation inefficiency?
migration? a single vSMMU provides better compatibility between src/dest...
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 24 lines · Kevin
Quoted 24 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, June 7, 2024 8:27 AMQuoted 19 lines · Nicolin Chen
Quoted 7 lines · Jason Gunthorpe
Quoted 5 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Quoted 8 lines
Quoted 5 lines
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Thanks for clarifying. That also means you'd prefer putting the command dispatcher in VMM, which is what we have at this moment.
Quoted 6 lines
Quoted 3 lines
Unless someone knows a reason why we should strive hard to have only a single vSMMU and accept some invalidation inefficiency?
migration? a single vSMMU provides better compatibility between src/dest...
Maybe, though I think we can safely split a single pSMMU into multiple vSMMUs using the IOMMUFD vIOMMU interface. So if your machine model has two vSMMUs and your physical HW has less we can still make that work.
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 32 lines · Jason Gunthorpe
Quoted 24 lines · Kevin
Quoted 24 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, June 7, 2024 8:27 AMQuoted 19 lines · Nicolin Chen
Quoted 7 lines · Jason Gunthorpe
Quoted 5 lines · Nicolin Chen
Quoted 4 lines
I understand the appeal of doing this has been to minimize qemu changes in its ACPI parts if we tackle that instead maybe we should just not implement viommu to multiple piommu. It is somewhat complicated.
Quoted 8 lines
Quoted 5 lines
Would you please clarify that suggestion "not implement viommu to multiple piommu"?
For regular nesting (SMMU), we are still doing one vSMMU in the VMM, though VCMDQ case would be an exception....
This is what I mean, always do multiple vSMMU if there are multiple physical pSMMUs. Don't replicate any virtual commands across pSMMUs.
Thanks for clarifying. That also means you'd prefer putting the command dispatcher in VMM, which is what we have at this moment.
Quoted 6 lines
Quoted 3 lines
Unless someone knows a reason why we should strive hard to have only a single vSMMU and accept some invalidation inefficiency?
migration? a single vSMMU provides better compatibility between src/dest...
Quoted 7 lines
Maybe, though I think we can safely split a single pSMMU into multiple vSMMUs using the IOMMUFD vIOMMU interface. So if your machine model has two vSMMUs and your physical HW has less we can still make that work.
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
I think the invalidation efficiency is actually solvable. So, basically viommu_invalidate would receive a whole batch of cmds and dispatch them to different pSMMUs (nested_domains/devices). We already have a vdev_id table for devices, yet we just need a new vasid table for nested_domains. Right?
The immediate benefit is that VMMs won't need to duplicate each other's dispatcher pieces, and likely helps migrations as Kevin pointed out.
With that being said, it would make the kernel design a bit more complicated. And the VMM still has to separate the commands for passthrough devices (HW iotlb) from commands for emulated devices (emulated iotlb), unless we further split the topology at the VM level to have a dedicated vSMMU for all passthrough devices -- then VMM could just forward its entire cmdq to the kernel without deciphering every command (likely?).
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 8 lines · Nicolin Chen
Quoted 2 lines
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
I think the invalidation efficiency is actually solvable. So, basically
viommu_invalidatewould receive a whole batch of cmds and dispatch them to different pSMMUs (nested_domains/devices). We already have avdev_idtable for devices, yet we just need a new vasid table fornested_domains. Right?
You can't know the ASID usage of the hypervisor from the VM, unless you also inspect the CD table memory in the guest. That seems like something we should try hard to avoid.
Quoted 7 lines
With that being said, it would make the kernel design a bit more complicated. And the VMM still has to separate the commands for passthrough devices (HW iotlb) from commands for emulated devices (emulated iotlb), unless we further split the topology at the VM level to have a dedicated vSMMU for all passthrough devices -- then VMM could just forward its entire cmdq to the kernel without deciphering every command (likely?).
I would not include the emulated devices in a shared SMMU.. For the same reason, we should try hard to avoid inspecting the page table memory.
If a viommu is needed for emulated then virtio-iommu may be more appropriate..
That said I'm sure someone will want to do this, so as long as it is possible in the VMM, as slow as it may be, then it is fine.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 11 lines · Jason Gunthorpe
Quoted 8 lines · Nicolin Chen
Quoted 2 lines
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
I think the invalidation efficiency is actually solvable. So, basically
viommu_invalidatewould receive a whole batch of cmds and dispatch them to different pSMMUs (nested_domains/devices). We already have avdev_idtable for devices, yet we just need a new vasid table fornested_domains. Right?
Quoted 3 lines
You can't know the ASID usage of the hypervisor from the VM, unless you also inspect the CD table memory in the guest. That seems like something we should try hard to avoid.
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.
Doing in the other way by moving it to the kernel, we'd just need a pair of new ioctls and use them when VMM traps CFGI_CD cmds, so kernel driver instead of VMM user driver manages the links between ASIDs to nested domains. Either a master ASID or SVA ASIDs can be linked to the same nested_domain that's allocated per vSTE.
Quoted 11 lines
Quoted 7 lines
With that being said, it would make the kernel design a bit more complicated. And the VMM still has to separate the commands for passthrough devices (HW iotlb) from commands for emulated devices (emulated iotlb), unless we further split the topology at the VM level to have a dedicated vSMMU for all passthrough devices -- then VMM could just forward its entire cmdq to the kernel without deciphering every command (likely?).
I would not include the emulated devices in a shared SMMU.. For the same reason, we should try hard to avoid inspecting the page table memory.
I wouldn't like the idea of attaching emulated devices to a shared vSMMU. Yet, mind elaborating why this would inspect the page table memory? Or do you mean we should avoid VMM inspecting user tables?
Quoted 5 lines
If a viommu is needed for emulated then virtio-iommu may be more appropriate..
That said I'm sure someone will want to do this, so as long as it is possible in the VMM, as slow as it may be, then it is fine.
Eric hasn't replied my previous query regarding how to design this, yet I guess the same. And looks like Intel is doing so for emulated devices, since there is only one intel_iommu instance in a VM.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 12 lines · Nicolin Chen
Quoted 11 lines · Jason Gunthorpe
Quoted 8 lines · Nicolin Chen
Quoted 2 lines
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
I think the invalidation efficiency is actually solvable. So, basically
viommu_invalidatewould receive a whole batch of cmds and dispatch them to different pSMMUs (nested_domains/devices). We already have avdev_idtable for devices, yet we just need a new vasid table fornested_domains. Right?
Quoted 7 lines
Quoted 3 lines
You can't know the ASID usage of the hypervisor from the VM, unless you also inspect the CD table memory in the guest. That seems like something we should try hard to avoid.
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.
No, there should be no CD table decoding and no linking ASID to anything by the VMM.
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
The s1_hwpt is derived only from the vSTE and nothing more. It would be fine for all the devices to have their own s1_hwpts with their own vSTE's inside it.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
With that being said, it would make the kernel design a bit more complicated. And the VMM still has to separate the commands for passthrough devices (HW iotlb) from commands for emulated devices (emulated iotlb), unless we further split the topology at the VM level to have a dedicated vSMMU for all passthrough devices -- then VMM could just forward its entire cmdq to the kernel without deciphering every command (likely?).
Quoted 7 lines
Quoted 3 lines
I would not include the emulated devices in a shared SMMU.. For the same reason, we should try hard to avoid inspecting the page table memory.
I wouldn't like the idea of attaching emulated devices to a shared vSMMU. Yet, mind elaborating why this would inspect the page table memory? Or do you mean we should avoid VMM inspecting user tables?
Emulated devices can't use the HW page table walker in the SMMU since they won't get a clean CD linkage they can use. They have to manually walk the page tables and convert them into an IOAS. It is a big PITA, best to be avoided.
Quoted 9 lines
Quoted 5 lines
If a viommu is needed for emulated then virtio-iommu may be more appropriate..
That said I'm sure someone will want to do this, so as long as it is possible in the VMM, as slow as it may be, then it is fine.
Eric hasn't replied my previous query regarding how to design this, yet I guess the same. And looks like Intel is doing so for emulated devices, since there is only one
intel_iommuinstance in a VM.
Yes, Intel has long has this code to build VFIO containers from page table walks.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 21 lines · Jason Gunthorpe
Quoted 12 lines · Nicolin Chen
Quoted 11 lines · Jason Gunthorpe
Quoted 8 lines · Nicolin Chen
Quoted 2 lines
IOTLB efficiency will suffer though when splitting 1p -> 2v while invalidation performance will suffer when joining 2p -> 1v.
I think the invalidation efficiency is actually solvable. So, basically
viommu_invalidatewould receive a whole batch of cmds and dispatch them to different pSMMUs (nested_domains/devices). We already have avdev_idtable for devices, yet we just need a new vasid table fornested_domains. Right?Quoted 7 lines
Quoted 3 lines
You can't know the ASID usage of the hypervisor from the VM, unless you also inspect the CD table memory in the guest. That seems like something we should try hard to avoid.
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.
Quoted 5 lines
No, there should be no CD table decoding and no linking ASID to anything by the VMM.
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
But a guest-level TLBI command usually has only ASID available to know which pSMMU to dispatch the command. Without an ASID lookup table, how could VMM then dispatch a command to the corresponding pSMMU?
Quoted 16 lines
The
s1_hwptis derived only from the vSTE and nothing more. It would be fine for all the devices to have their owns1_hwptswith their own vSTE's inside it.Quoted 12 lines
Quoted 11 lines
Quoted 7 lines
With that being said, it would make the kernel design a bit more complicated. And the VMM still has to separate the commands for passthrough devices (HW iotlb) from commands for emulated devices (emulated iotlb), unless we further split the topology at the VM level to have a dedicated vSMMU for all passthrough devices -- then VMM could just forward its entire cmdq to the kernel without deciphering every command (likely?).
I would not include the emulated devices in a shared SMMU.. For the same reason, we should try hard to avoid inspecting the page table memory.
Quoted 8 lines
Quoted 3 lines
I wouldn't like the idea of attaching emulated devices to a shared vSMMU. Yet, mind elaborating why this would inspect the page table memory? Or do you mean we should avoid VMM inspecting user tables?
Emulated devices can't use the HW page table walker in the SMMU since they won't get a clean CD linkage they can use. They have to manually walk the page tables and convert them into an IOAS. It is a big PITA, best to be avoided.
Oh..the mainline QEMU smmu code already has that:
https://github.com/qemu/qemu/blob/master/hw/arm/smmu-common.c#L522
Surely, it's a pathway that passthrough devices shouldn't run into.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 7 lines · Nicolin Chen
Quoted 7 lines
Quoted 3 lines
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.No, there should be no CD table decoding and no linking ASID to anything by the VMM.
Quoted 7 lines
Quoted 2 lines
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
But a guest-level TLBI command usually has only ASID available to know which pSMMU to dispatch the command. Without an ASID lookup table, how could VMM then dispatch a command to the corresponding pSMMU?
It can broadcast. The ARM architecture does not expect a N:1 mapping of SMMUs. This is why I think it is not such a good idea..
Yes the VMM could walk the CD tables too and build up a bitmap of what ASIDs are being used by what pSMMUs, and that would be fine for the VMM to do, but I wouldn't necessarily recommend it :)
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 12 lines · Jason Gunthorpe
Quoted 10 lines · Nicolin Chen
Quoted 9 lines
Quoted 3 lines
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.No, there should be no CD table decoding and no linking ASID to anything by the VMM.
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
Quoted 7 lines
Quoted 4 lines
But a guest-level TLBI command usually has only ASID available to know which pSMMU to dispatch the command. Without an ASID lookup table, how could VMM then dispatch a command to the corresponding pSMMU?
It can broadcast. The ARM architecture does not expect a N:1 mapping of SMMUs. This is why I think it is not such a good idea..
Hmm, I thought we had an agreed idea that we shouldn't broadcast a TLBI (except global NH_ALL/VAA) for invalidation performance?
Quoted 3 lines
Yes the VMM could walk the CD tables too and build up a bitmap of what ASIDs are being used by what pSMMUs, and that would be fine for the VMM to do, but I wouldn't necessarily recommend it :)
CD table walkthrough would be always done only by VMM, while the lookup table could be created/maintained by the kernel. I feel a vasid table could make sense since we maintain the vdev_id table in the kernel space too.
Anyway, it is still an implementation choice, as Kevin remarked.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 18 lines · Nicolin Chen
Quoted 17 lines · Jason Gunthorpe
Quoted 14 lines · Nicolin Chen
Quoted 9 lines
Quoted 3 lines
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.No, there should be no CD table decoding and no linking ASID to anything by the VMM.
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
But a guest-level TLBI command usually has only ASID available to know which pSMMU to dispatch the command. Without an ASID lookup table, how could VMM then dispatch a command to the corresponding pSMMU?
Quoted 5 lines
Quoted 2 lines
It can broadcast. The ARM architecture does not expect a N:1 mapping of SMMUs. This is why I think it is not such a good idea..
Hmm, I thought we had an agreed idea that we shouldn't broadcast a TLBI (except global NH_ALL/VAA) for invalidation performance?
I wouldn't say agree, there are just lots of different trade offs to be made here. You can reduce broadcast by parsing the CD table from the VMM. You can reduce broadcast with multiple vSMMUs.
VMM needs to pick a design. I favour multiple vSMMUs.
Quoted 4 lines
CD table walkthrough would be always done only by VMM, while the lookup table could be created/maintained by the kernel. I feel a vasid table could make sense since we maintain the
vdev_idtable in the kernel space too.
I'm not convinced we should put such a micro optimization in the kernel. If the VMM cares about performance then split the vSMMU, otherwise lets just put all the mess in the VMM and give it the tools to manage the invalidation distribution.
In the long run things like vCMDQ are going to force the choice to multi-smmu, which is why I don't see too much value with investing in optimizing the single vSMMU case. The optimization can be done later if someone does have a use case.
Jason
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
Quoted 22 lines · Jason Gunthorpe
Quoted 21 lines · Nicolin Chen
Quoted 19 lines · Jason Gunthorpe
Quoted 7 lines · Nicolin Chen
Quoted 7 lines
Quoted 3 lines
Actually, even now as we put a dispatcher in VMM, VMM still does decode the CD table to link ASID to
s1_hwpt. Otherwise, it could only broadcast a TLBI cmd to all pSMMUs.No, there should be no CD table decoding and no linking ASID to anything by the VMM.
Quoted 7 lines
Quoted 2 lines
The ARM architecture is clean, the ASID can remain private to the VM, there is no reason for the VMM to understand it.
But a guest-level TLBI command usually has only ASID available to know which pSMMU to dispatch the command. Without an ASID lookup table, how could VMM then dispatch a command to the corresponding pSMMU?
It can broadcast. The ARM architecture does not expect a N:1 mapping of SMMUs. This is why I think it is not such a good idea..
Quoted 8 lines
Quoted 2 lines
Hmm, I thought we had an agreed idea that we shouldn't broadcast a TLBI (except global NH_ALL/VAA) for invalidation performance?
I wouldn't say agree, there are just lots of different trade offs to be made here. You can reduce broadcast by parsing the CD table from the VMM. You can reduce broadcast with multiple vSMMUs.
VMM needs to pick a design. I favour multiple vSMMUs.
Yea, having multiple vSMMUs for nesting too seems to be a cleaner design. The thing is that we have to put a certain complexity in the VMM, and it should be more efficient by having it at the boot stage (creating multi-vSMMUs/PCIs and IORT nodes) v.s. runtime (trappings and distributing at every command).
Quoted 10 lines
Quoted 4 lines
CD table walkthrough would be always done only by VMM, while the lookup table could be created/maintained by the kernel. I feel a vasid table could make sense since we maintain the
vdev_idtable in the kernel space too.I'm not convinced we should put such a micro optimization in the kernel. If the VMM cares about performance then split the vSMMU, otherwise lets just put all the mess in the VMM and give it the tools to manage the invalidation distribution.
Quoted 4 lines
In the long run things like vCMDQ are going to force the choice to multi-smmu, which is why I don't see too much value with investing in optimizing the single vSMMU case. The optimization can be done later if someone does have a use case.
I see. That makes sense to me.
Nicolin
Re: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Tian, KevinQuoted 28 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Friday, May 24, 2024 9:19 PMQuoted 4 lines · Kevin
I'm curious to learn the real reason of that design. Is it because you want to do certain load-balance between viommu's or due to other reasons in the kernel smmuv3 driver which e.g. cannot support a viommu spanning multiple pSMMU?
Quoted 6 lines
Yeah, there is no concept of support for a SMMUv3 instance where it's command Q's can only work on a subset of devices.
My expectation was that VIOMMU would be 1:1 with physical iommu instances, I think AMD needs this too??
Yes this part is clear now regarding to VCMDQ.
But Nicoline said:
"
One step back, even without VCMDQ feature, a multi-pSMMU setup will have multiple viommus (with our latest design) being added to a viommu list of a single vSMMU's. Yet, vSMMU in this case always traps regular SMMU CMDQ, so it can do viommu selection or even broadcast (if it has to).
"
Quoted 1 line
I don't think there is an arch limitation mandating that?
What I mean is for regular a nested SMMU case. Without VCMDQ, a regular vSMMU on a multi-pSMMU setup will look like (e.g. three devices behind different SMMUs):
|<---- guest ---->|<--------- VMM -------->|<- kernel ->|
|-- dev0 --|-- viommu0 (s2_hwpt0) --|-- pSMMU0 --|
vSMMU--|-- dev1 --|-- viommu1 (s2_hwpt0) --|-- pSMMU1 --|
|-- dev2 --|-- viommu2 (s2_hwpt0) --|-- pSMMU2 --|When trapping a device cache invalidation: it is straightforward by deciphering the virtual device ID to pick the viommu that the device is attached to. So, only one pSMMU would receive the user invalidation request.
When doing iotlb invalidation, a command may or may not contain an ASID (a domain ID, and nested domain in this case):
a) if a command doesn't have an ASID, VMM needs to broadcast the command to all viommus (i.e. pSMMUs)
b) if a command has an ASID, VMM needs to initially maintain an S1 HWPT list by linking an ASID when adding an HWPT entry to the list, by deciphering vSTE and its linked CD. Then it needs to go through the S1 list with the ASID in the command, and to find all corresponding HWPTs to issue/broadcast the command.
Thanks
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 08/14] iommufd: Add IOMMU_VIOMMU_SET_DEV_ID ioctl
In reply to Nicolin ChenQuoted 15 lines · Nicolin Chen
Quoted 14 lines · Kevin
Quoted 7 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMIntroduce a new ioctl to set a per-viommu device virtual id that should be linked to the physical device id (or just a struct device pointer).
Since a viommu (user space IOMMU instance) can have multiple devices
this is true...
Quoted 3 lines
while
it's not ideal to confine a device to one single user space IOMMU instance either, these two shouldn't just do a 1:1 mapping. Add two xarrays in
Quoted 7 lines
Quoted 1 line
...but why would one device link to multiple viommu instances?
That's a suggestion from Jason, IIRC, to avoid limiting a device to a single viommu, though I can't find out the source at this moment.
Jason, would you mind shed some light here?
We could probably do it either way, it just doesn't seem like there is a strong reason to limit a device to a single viommu even if in practice that is how everyone will use it.
Jason
RFC PATCH 9/14 iommufd/selftest: Add IOMMU_VIOMMU_SET_DEV_ID test coverage
In reply to Nicolin ChenAdd an xarray to store the array of virtual ids to mock_devs, to cover the new IOMMU_VIOMMU_SET_DEV_ID ioctl.
--- drivers/iommu/iommufd/selftest.c | 50 +++++++++++++++++++ tools/testing/selftests/iommu/iommufd.c | 14 ++++++ tools/testing/selftests/iommu/iommufd_utils.h | 21 ++++++++ 3 files changed, 85 insertions(+)
drivers/iommu/iommufd/selftest.c +50 -0
@@ -139,6 +139,7 @@ struct mock_dev {struct device dev;unsigned long flags;int id; +unsigned int id_user; };struct selftest_obj {
@@ -516,6 +517,53 @@ static struct iommu_device *mock_probe_device(struct device *dev)struct mock_viommu {struct iommufd_viommu core; +struct xarray ids; +}; + +static void mock_viommu_free (struct iommufd_viommu *viommu) +{ + struct mock_viommu *mv = container_of(viommu, struct mock_viommu, core); +struct device *dev; +unsigned long index; + +xa_for_each (&mv->ids, index, dev) +xa_erase (&mv->ids, index); +xa_destroy (&mv->ids); +} + +static int mock_viommu_set_dev_id (struct iommufd_viommu *viommu, +struct device *dev,u64 dev_id) +{ + struct mock_viommu *mv = container_of(viommu, struct mock_viommu, core); + struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); +u32 id = (u32 )dev_id; +int rc; + +if (dev_id >UINT_MAX ) +return -EINVAL ; +if (mdev->id_user >0 ) +return -EBUSY ; + rc =xa_alloc (&mv->ids, &id, dev,XA_LIMIT (id, id),GFP_KERNEL ); +if (rc) +return rc; + mdev->id_user = (unsigned int )dev_id; +return 0 ; +} + +static void mock_viommu_unset_dev_id (struct iommufd_viommu *viommu, +struct device *dev) +{ + struct mock_viommu *mv = container_of(viommu, struct mock_viommu, core); + struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); + +WARN_ON (dev !=xa_erase (&mv->ids, mdev->id_user)); + mdev->id_user =0 ; +} + +static const struct iommufd_viommu_ops mock_viommu_ops = { + .free = mock_viommu_free, + .set_dev_id = mock_viommu_set_dev_id, + .unset_dev_id = mock_viommu_unset_dev_id, }; static struct iommufd_viommu *mock_viommu_alloc(struct device *dev,
@@ -527,6 +575,8 @@ static struct iommufd_viommu *mock_viommu_alloc(struct device *dev, mv =iommufd_viommu_alloc (mock_viommu, core);if (!mv)return ERR_PTR (-ENOMEM ); + mv->core.ops = &mock_viommu_ops; +xa_init_flags (&mv->ids,XA_FLAGS_ALLOC1 );return &mv->core; }
tools/testing/selftests/iommu/iommufd.c +14 -0
@@ -271,6 +271,9 @@ TEST_F(iommufd_ioas, viommu)uint32_t dev_id = self->device_id;uint32_t viommu_id =0 ;uint32_t hwpt_id =0 ; +uint32_t device2; +uint32_t stdev2; +uint32_t hwpt2;if (dev_id) {test_err_viommu_alloc (ENOENT , dev_id, hwpt_id, &viommu_id);
@@ -282,10 +285,21 @@ TEST_F(iommufd_ioas, viommu)IOMMU_HWPT_ALLOC_NEST_PARENT , &hwpt_id);test_cmd_viommu_alloc (dev_id, hwpt_id, &viommu_id); +test_err_viommu_set_dev_id (EINVAL , dev_id, viommu_id,1ULL <<32 ); +test_cmd_viommu_set_dev_id (dev_id, viommu_id,0x99 ); +test_err_viommu_set_dev_id (EBUSY , dev_id, viommu_id,0x99 ); + +test_cmd_mock_domain (self->ioas_id, &stdev2, &hwpt2, &device2); +test_err_viommu_set_dev_id (EBUSY , device2, viommu_id,0x99 ); +test_cmd_viommu_set_dev_id (device2, viommu_id,0xaa ); +test_err_viommu_set_dev_id (EBUSY , device2, viommu_id,0xaa ); +test_ioctl_destroy (stdev2); +test_ioctl_destroy (viommu_id);test_ioctl_destroy (hwpt_id); }else {test_err_viommu_alloc (ENOENT , dev_id, hwpt_id, &viommu_id); +test_err_viommu_set_dev_id (ENOENT , dev_id, viommu_id,99 ); } }
tools/testing/selftests/iommu/iommufd_utils.h +21 -0
@@ -710,3 +710,24 @@ static int _test_cmd_viommu_alloc(int fd, __u32 device_id, __u32 hwpt_id,#define test_err_viommu_alloc (_errno, device_id, hwpt_id, viommu_id) \ EXPECT_ERRNO(_errno, _test_cmd_viommu_alloc(self->fd, device_id, \ hwpt_id, 0, viommu_id)) + +static int _test_cmd_viommu_set_dev_id (int fd,__u32 device_id, +__u32 viommu_id,__u64 virtual_id) +{ +struct iommu_viommu_set_dev_id cmd = { + .size =sizeof (cmd), + .dev_id = device_id, + .viommu_id = viommu_id, + .id = virtual_id, + }; + +return ioctl (fd,IOMMU_VIOMMU_SET_DEV_ID , &cmd); +} + +#define test_cmd_viommu_set_dev_id (device_id, viommu_id, virtual_id) \ + ASSERT_EQ(0, _test_cmd_viommu_set_dev_id(self->fd, device_id, \ + viommu_id, virtual_id)) +#define test_err_viommu_set_dev_id (_errno, device_id, viommu_id, virtual_id) \ + EXPECT_ERRNO(_errno, \ + _test_cmd_viommu_set_dev_id(self->fd, device_id, \ + viommu_id, virtual_id))
Signature · 1 line
2.43.0
RFC PATCH 10/14 iommufd/selftest: Add IOMMU_TEST_OP_MV_CHECK_DEV_ID
In reply to Nicolin ChenThis allows verifying the ids xarray of struct mock_viommu, and confirming the correctness of an IOMMU_VIOMMU_SET_DEV_ID call.
--- drivers/iommu/iommufd/iommufd_test.h | 5 +++ drivers/iommu/iommufd/selftest.c | 32 +++++++++++++++++++ tools/testing/selftests/iommu/iommufd.c | 7 ++++ tools/testing/selftests/iommu/iommufd_utils.h | 24 ++++++++++++++ 4 files changed, 68 insertions(+)
drivers/iommu/iommufd/iommufd_test.h +5 -0
@@ -22,6 +22,7 @@ enum {IOMMU_TEST_OP_MOCK_DOMAIN_FLAGS ,IOMMU_TEST_OP_DIRTY ,IOMMU_TEST_OP_MD_CHECK_IOTLB , + IOMMU_TEST_OP_MV_CHECK_DEVID, }; enum {
@@ -127,6 +128,10 @@ struct iommu_test_cmd {__u32 id;__u32 iotlb; } check_iotlb; +struct { +__u32 idev_id; +__u32 dev_id; + } check_dev_id; };__u32 last; };
drivers/iommu/iommufd/selftest.c +32 -0
@@ -999,6 +999,34 @@ static int iommufd_test_md_check_iotlb(struct iommufd_ucmd *ucmd,return rc; } +static int iommufd_test_mv_check_dev_id (struct iommufd_ucmd *ucmd, +u32 viommu_id,unsigned int idev_id, +u32 dev_id) +{ +struct iommufd_device *idev; +struct mock_viommu *mv; +int rc =0 ; + + mv =container_of (iommufd_get_viommu (ucmd, viommu_id), + struct mock_viommu, core); +if (IS_ERR (mv)) +return PTR_ERR (mv); + + idev =iommufd_get_device (ucmd, idev_id); +if (IS_ERR (idev)) { + rc =PTR_ERR (idev); + goto out_put_viommu; + } + +if (idev->dev !=xa_load (&mv->ids, dev_id)) + rc = -EINVAL ; + +iommufd_put_object (ucmd->ictx, &idev->obj); +out_put_viommu: +iommufd_put_object (ucmd->ictx, &mv->core.obj); +return rc; +} +struct selftest_access {struct iommufd_access *access;struct file *file;
@@ -1484,6 +1512,10 @@ int iommufd_test(struct iommufd_ucmd *ucmd)return iommufd_test_md_check_iotlb (ucmd, cmd->id, cmd->check_iotlb.id, cmd->check_iotlb.iotlb); +case IOMMU_TEST_OP_MV_CHECK_DEVID : +return iommufd_test_mv_check_dev_id (ucmd, cmd->id, + cmd->check_dev_id.idev_id, + cmd->check_dev_id.dev_id);case IOMMU_TEST_OP_CREATE_ACCESS :return iommufd_test_create_access (ucmd, cmd->id, cmd->create_access.flags);
tools/testing/selftests/iommu/iommufd.c +7 -0
@@ -288,14 +288,21 @@ TEST_F(iommufd_ioas, viommu)test_err_viommu_set_dev_id (EINVAL , dev_id, viommu_id,1ULL <<32 );test_cmd_viommu_set_dev_id (dev_id, viommu_id,0x99 );test_err_viommu_set_dev_id (EBUSY , dev_id, viommu_id,0x99 ); +test_cmd_viommu_check_dev_id (viommu_id, dev_id,0x99 );test_cmd_mock_domain (self->ioas_id, &stdev2, &hwpt2, &device2);test_err_viommu_set_dev_id (EBUSY , device2, viommu_id,0x99 );test_cmd_viommu_set_dev_id (device2, viommu_id,0xaa );test_err_viommu_set_dev_id (EBUSY , device2, viommu_id,0xaa ); +test_cmd_viommu_check_dev_id (viommu_id, dev_id,0x99 ); +test_cmd_viommu_check_dev_id (viommu_id, device2,0xaa ); +test_ioctl_destroy (stdev2); +test_cmd_viommu_check_dev_id (viommu_id, dev_id,0x99 ); +test_err_viommu_check_dev_id (ENOENT , viommu_id, device2,0xaa );test_ioctl_destroy (viommu_id); +test_err_viommu_check_dev_id (ENOENT , viommu_id, dev_id,0x99 );test_ioctl_destroy (hwpt_id); }else {test_err_viommu_alloc (ENOENT , dev_id, hwpt_id, &viommu_id);
tools/testing/selftests/iommu/iommufd_utils.h +24 -0
@@ -731,3 +731,27 @@ static int _test_cmd_viommu_set_dev_id(int fd, __u32 device_id,EXPECT_ERRNO (_errno, \_test_cmd_viommu_set_dev_id (self->fd, device_id, \ viommu_id, virtual_id)) + +static int _test_cmd_viommu_check_dev_id (int fd,__u32 viommu_id, +__u32 device_id,__u64 virtual_id) +{ +struct iommu_test_cmd test_cmd = { + .size =sizeof (test_cmd), + .op =IOMMU_TEST_OP_MV_CHECK_DEVID , + .id = viommu_id, + .check_dev_id = { + .idev_id = device_id, + .dev_id = virtual_id, + }, + }; +return ioctl (fd,_IOMMU_TEST_CMD (IOMMU_TEST_OP_MV_CHECK_DEVID ), + &test_cmd); +} +#define test_cmd_viommu_check_dev_id (viommu_id, device_id, expected) \ + ASSERT_EQ(0, _test_cmd_viommu_check_dev_id(self->fd, viommu_id, \ + device_id, expected)) + +#define test_err_viommu_check_dev_id (_errno, viommu_id, device_id, expected) \ + EXPECT_ERRNO(_errno, \ + _test_cmd_viommu_check_dev_id(self->fd, viommu_id, \ + device_id, expected))
Signature · 1 line
2.43.0
RFC PATCH 11/14 iommufd: Add struct iommufd_vqueue and its related viommu ops
In reply to Nicolin ChenInroduce a new core structure and its allocator iommufd_vqueue_alloc().
This can be used for a viommu to allocate a HW-accelerated queue, e.g. NVIDIA's virtual command queue and AMD vIOMMU's command buffer.
Also add a pair of viommu ops for iommufd to forward user space ioctls to IOMMU drivers.
--- drivers/iommu/iommufd/viommu.c | 1 + include/linux/iommu.h | 1 + include/linux/iommufd.h | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+)
drivers/iommu/iommufd/viommu.c +1 -0
@@ -19,6 +19,7 @@ }viommu_struct_alloc (viommu); +viommu_struct_alloc (vqueue);void iommufd_viommu_destroy (struct iommufd_object *obj) {
include/linux/iommu.h +1 -0
@@ -146,6 +146,7 @@ struct iopf_queue { };struct iommufd_viommu ; +struct iommufd_vqueue ;/* iommu fault flags */ #define IOMMU_FAULT_READ 0x0
include/linux/iommufd.h +27 -0
@@ -20,6 +20,7 @@ struct iommufd_access;struct iommufd_hwpt_paging ;struct file ;struct iommu_group ; +struct iommu_user_data ;enum iommufd_object_type {IOMMUFD_OBJ_NONE ,
@@ -97,12 +98,27 @@ struct iommufd_viommu {* @free: Free all driver-specific parts of an iommufd_viommu. The memory * of the entire viommu will be free-ed by iommufd core * @set/unset_dev_id: set/unset a user space virtual id for a device +* @vqueue_alloc: Allocate an iommufd_vqueue as a user space command queue for a +* @viommu instance. Queue specific @user_data must be defined in +* the include/uapi/linux/iommufd.h header. +* @vqueue_free: Free all driver-specific parts of an iommufd_vqueue. The memory +* of the iommufd_vqueue will be free-ed by iommufd core */ struct iommufd_viommu_ops {void (*free)(struct iommufd_viommu *viommu);int (*set_dev_id)(struct iommufd_viommu *viommu,struct device *dev,u64 dev_id);void (*unset_dev_id)(struct iommufd_viommu *viommu,struct device *dev); +struct iommufd_vqueue *(*vqueue_alloc)( +struct iommufd_viommu *viommu, +const struct iommu_user_data *user_data); +void (*vqueue_free)(struct iommufd_vqueue *vqueue); +}; + +struct iommufd_vqueue { +struct iommufd_object obj; +struct iommufd_ctx *ictx; +struct iommufd_viommu *viommu; };#if IS_ENABLED (CONFIG_IOMMUFD )
@@ -123,6 +139,7 @@ int iommufd_vfio_compat_ioas_create(struct iommufd_ctx *ictx);int iommufd_vfio_compat_set_no_iommu (struct iommufd_ctx *ictx);struct iommufd_viommu *_iommufd_viommu_alloc (size_t size); +struct iommufd_vqueue *_iommufd_vqueue_alloc (size_t size);#else /* !CONFIG_IOMMUFD */ static inline struct iommufd_ctx *iommufd_ctx_from_file (struct file *file) {
@@ -168,6 +185,11 @@ static inline struct iommufd_viommu *_iommufd_viommu_alloc(size_t size) {return NULL ; } + +static inline struct iommufd_vqueue *_iommufd_vqueue_alloc (size_t size) +{ +return NULL ; +}#endif /* CONFIG_IOMMUFD */ /*
@@ -179,4 +201,9 @@ static inline struct iommufd_viommu *_iommufd_viommu_alloc(size_t size) BUILD_BUG_ON_ZERO(offsetof( \ struct drv_struct, member))), \ struct drv_struct, member) +#define iommufd_vqueue_alloc (drv_struct, member) \ + container_of(_iommufd_vqueue_alloc(sizeof(struct drv_struct) + \ + BUILD_BUG_ON_ZERO(offsetof( \ + struct drv_struct, member))), \ + struct drv_struct, member)#endif
Signature · 1 line
2.43.0
RFC PATCH 12/14 iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
In reply to Nicolin ChenIntroduce a new IOMMUFD_OBJ_VQUEU to represent a virtual command queue instance. And add a new ioctl for user space to allocate it.
As an initial version, ddd IOMMU_VQUEUE_DATA_TEGRA241_CMDQV to the enum iommu_vqueue_data_type and the corresponding iommu_vqueue_tegra241_cmdqv data structure.
--- drivers/iommu/iommufd/iommufd_private.h | 2 + drivers/iommu/iommufd/main.c | 6 +++ drivers/iommu/iommufd/viommu.c | 72 +++++++++++++++++++++++++ include/linux/iommufd.h | 1 + include/uapi/linux/iommufd.h | 48 +++++++++++++++++ 5 files changed, 129 insertions(+)
drivers/iommu/iommufd/iommufd_private.h +2 -0
@@ -436,6 +436,8 @@ iommufd_get_viommu(struct iommufd_ucmd *ucmd, u32 id)int iommufd_viommu_alloc_ioctl (struct iommufd_ucmd *ucmd);void iommufd_viommu_destroy (struct iommufd_object *obj);int iommufd_viommu_set_device_id (struct iommufd_ucmd *ucmd); +int iommufd_vqueue_alloc_ioctl (struct iommufd_ucmd *ucmd); +void iommufd_vqueue_destroy (struct iommufd_object *obj);#ifdef CONFIG_IOMMUFD_TEST int iommufd_test (struct iommufd_ucmd *ucmd);
drivers/iommu/iommufd/main.c +6 -0
@@ -324,6 +324,7 @@ union ucmd_buffer {struct iommu_ioas_alloc alloc;struct iommu_ioas_allow_iovas allow_iovas;struct iommu_viommu_alloc viommu; +struct iommu_vqueue_alloc vqueue;struct iommu_ioas_copy ioas_copy;struct iommu_ioas_iova_ranges iova_ranges;struct iommu_ioas_map map;
@@ -383,6 +384,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { struct iommu_viommu_alloc, out_viommu_id),IOCTL_OP (IOMMU_VIOMMU_SET_DEV_ID ,iommufd_viommu_set_device_id ,struct iommu_viommu_set_dev_id ,id ), +IOCTL_OP (IOMMU_VQUEUE_ALLOC ,iommufd_vqueue_alloc_ioctl , +struct iommu_vqueue_alloc ,data_uptr ), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif
@@ -518,6 +521,9 @@ static const struct iommufd_object_ops iommufd_object_ops[] = { [IOMMUFD_OBJ_VIOMMU ] = { .destroy = iommufd_viommu_destroy, }, + [IOMMUFD_OBJ_VQUEUE ] = { + .destroy = iommufd_vqueue_destroy, + }, #ifdef CONFIG_IOMMUFD_TEST [IOMMUFD_OBJ_SELFTEST ] = { .destroy = iommufd_selftest_destroy,
drivers/iommu/iommufd/viommu.c +72 -0
75 lines not on this page · raw message
include/linux/iommufd.h +1 -0
@@ -31,6 +31,7 @@ enum iommufd_object_type {IOMMUFD_OBJ_IOAS ,IOMMUFD_OBJ_ACCESS ,IOMMUFD_OBJ_VIOMMU , +IOMMUFD_OBJ_VQUEUE , #ifdef CONFIG_IOMMUFD_TEST IOMMUFD_OBJ_SELFTEST, #endif
include/uapi/linux/iommufd.h +48 -0
58 lines not on this page · raw message
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 11 lines · Nicolin Chen
include/uapi/linux/iommufd.h +11
-0+/** +* struct iommu_vqueue_alloc - ioctl(IOMMU_VQUEUE_ALLOC) +* @size: sizeof(struct iommu_vqueue_alloc) +* @flags: Must be 0 +* @viommu_id: viommu ID to associate the virtual queue with +* @out_vqueue_id: The ID of the new virtual queue +* @data_type: One of enum iommu_vqueue_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* +* Allocate an virtual queue object for driver-specific HW-accelerated queue
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 10 lines
include/uapi/linux/iommufd.h +10
-0+*/ + +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;
Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate data_uptr is an IPA.
Jason
Re: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 19 lines · Jason Gunthorpe
Quoted 17 lines · Nicolin Chen
include/uapi/linux/iommufd.h +17
-0+/** +* struct iommu_vqueue_alloc - ioctl(IOMMU_VQUEUE_ALLOC) +* @size: sizeof(struct iommu_vqueue_alloc) +* @flags: Must be 0 +* @viommu_id: viommu ID to associate the virtual queue with +* @out_vqueue_id: The ID of the new virtual queue +* @data_type: One of enum iommu_vqueue_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* +* Allocate an virtual queue object for driver-specific HW-accelerated queue +*/ + +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id;
Quoted 8 lines
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 4 lines
include/uapi/linux/iommufd.h +4
-0+__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.
Ack.
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 29 lines · Nicolin Chen
Quoted 19 lines · Jason Gunthorpe
Quoted 17 lines · Nicolin Chen
include/uapi/linux/iommufd.h +17
-0+/** +* struct iommu_vqueue_alloc - ioctl(IOMMU_VQUEUE_ALLOC) +* @size: sizeof(struct iommu_vqueue_alloc) +* @flags: Must be 0 +* @viommu_id: viommu ID to associate the virtual queue with +* @out_vqueue_id: The ID of the new virtual queue +* @data_type: One of enum iommu_vqueue_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* +* Allocate an virtual queue object for driver-specific HW-accelerated queue +*/ + +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id;Quoted 8 lines
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 4 lines
include/uapi/linux/iommufd.h +4
-0+__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.
Quoted 1 line
Ack.
To be clear, add a flag someday, no change needed
Jason
Tian, Kevin
maintainerRE: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
In reply to Jason GunthorpeQuoted 17 lines
From: Jason Gunthorpe <[email protected]>
Sent: Sunday, May 12, 2024 11:02 PMQuoted 11 lines · Nicolin Chen
+/**
+ * structiommu_vqueue_alloc-ioctl(IOMMU_VQUEUE_ALLOC)
+ * @size:sizeof(struct iommu_vqueue_alloc)
+ * @flags: Must be 0
+ * @viommu_id: viommu ID to associate the virtual queue with
+ * @out_vqueue_id: The ID of the new virtual queue
+ * @data_type: One of enumiommu_vqueue_data_type
+ * @data_len: Length of the type specific data
+ * @data_uptr: User pointer to the type specific data
+ *
+ * Allocate an virtual queue object for driver-specific HW-acceleratedqueue
Quoted 15 lines
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 10 lines
+ */
include/uapi/linux/iommufd.h +9
-0+ +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.
Presumably each driver will create its own type data which can include any IPA field as vcmdq_base in this patch?
Re: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 33 lines · Kevin
Quoted 17 lines
From: Jason Gunthorpe <[email protected]>
Sent: Sunday, May 12, 2024 11:02 PMQuoted 11 lines · Nicolin Chen
+/**
+ * structiommu_vqueue_alloc-ioctl(IOMMU_VQUEUE_ALLOC)
+ * @size:sizeof(struct iommu_vqueue_alloc)
+ * @flags: Must be 0
+ * @viommu_id: viommu ID to associate the virtual queue with
+ * @out_vqueue_id: The ID of the new virtual queue
+ * @data_type: One of enumiommu_vqueue_data_type
+ * @data_len: Length of the type specific data
+ * @data_uptr: User pointer to the type specific data
+ *
+ * Allocate an virtual queue object for driver-specific HW-acceleratedqueue
Quoted 15 lines
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 10 lines
+ */
include/uapi/linux/iommufd.h +9
-0+ +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.
Quoted 2 lines
Presumably each driver will create its own type data which can include any IPA field as
vcmdq_basein this patch?
You mean putting a base address field in this common vqueue structure? Hmm, I think we could, assuming every queue must have a set of base and size info in the guest level.
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 37 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 12:42 PMQuoted 33 lines · Kevin
Quoted 32 lines
From: Jason Gunthorpe <[email protected]>
Sent: Sunday, May 12, 2024 11:02 PMQuoted 11 lines · Nicolin Chen
+/**
+ * structiommu_vqueue_alloc-ioctl(IOMMU_VQUEUE_ALLOC)
+ * @size:sizeof(struct iommu_vqueue_alloc)
+ * @flags: Must be 0
+ * @viommu_id: viommu ID to associate the virtual queue with
+ * @out_vqueue_id: The ID of the new virtual queue
+ * @data_type: One of enumiommu_vqueue_data_type
+ * @data_len: Length of the type specific data
+ * @data_uptr: User pointer to the type specific data
+ *
+ * Allocate an virtual queue object for driver-specific HW-acceleratedqueue
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 10 lines
+ */
include/uapi/linux/iommufd.h +9
-0+ +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.
Quoted 7 lines
Quoted 2 lines
Presumably each driver will create its own type data which can include any IPA field as
vcmdq_basein this patch?You mean putting a base address field in this common vqueue structure? Hmm, I think we could, assuming every queue must have a set of base and size info in the guest level.
We could, but my original point was just that it's confusing to change the meaning of data_uptr. Let's stick it to be driver defined data and any driver-specific IPA field is defined in that data.
Of course if we think the base address is common enough it can be moved to the common vqueue structure too.
Re: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
Quoted 43 lines · Kevin
External email: Use caution opening links or attachments
Quoted 40 lines
From: Nicolin Chen <[email protected]>
Sent: Friday, May 24, 2024 12:42 PMQuoted 35 lines · Kevin
Quoted 17 lines
From: Jason Gunthorpe <[email protected]>
Sent: Sunday, May 12, 2024 11:02 PMQuoted 11 lines · Nicolin Chen
+/**
+ * structiommu_vqueue_alloc-ioctl(IOMMU_VQUEUE_ALLOC)
+ * @size:sizeof(struct iommu_vqueue_alloc)
+ * @flags: Must be 0
+ * @viommu_id: viommu ID to associate the virtual queue with
+ * @out_vqueue_id: The ID of the new virtual queue
+ * @data_type: One of enumiommu_vqueue_data_type
+ * @data_len: Length of the type specific data
+ * @data_uptr: User pointer to the type specific data
+ *
+ * Allocate an virtual queue object for driver-specific HW-acceleratedqueue
Quoted 15 lines
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 789
Quoted 10 lines
+ */
include/uapi/linux/iommufd.h +9
-0+ +struct iommu_vqueue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 out_vqueue_id; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr;Some of the iommus will want an IPA here not a user pointer. I think it is fine API wise, we'd just add a flag to indicate
data_uptris an IPA.Presumably each driver will create its own type data which can include any IPA field as
vcmdq_basein this patch?
Quoted 8 lines
Quoted 4 lines
You mean putting a base address field in this common vqueue structure? Hmm, I think we could, assuming every queue must have a set of base and size info in the guest level.
We could, but my original point was just that it's confusing to change the meaning of
data_uptr. Let's stick it to be driver defined data and any driver-specific IPA field is defined in that data.
Oh, that's copied from IOMMU_HWPT_ALLOC:
* @data_uptr: User pointer to the type specific data
And it actually makes sense to me to be "type specific" since a driver (AMD VIOMMU for example) might have two different vqueue types (invalidation queue v.s. fault queue)?
Thanks
Nicolin
Tian, Kevin
maintainerRE: [PATCH RFCv1 12/14] iommufd: Add IOMMUFD_OBJ_VQUEUE and IOMMUFD_CMD_VQUEUE_ALLOC
In reply to Nicolin ChenQuoted 13 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMinclude/uapi/linux/iommufd.h +3
-0+ +/** +* struct iommu_vqueue_tegra241_cmdqv - NVIDIA Tegra241's Virtual Command Queue
+ * for its CMDQV Extension for ARM SMMUv3
+ * (IOMMU_VQUEUE_DATA_TEGRA241_CMDQV)
+ * @vcmdq_id: logical ID of a virtual command queue in the VIOMMU instance
+ * @vcmdq_log2size: (1 << @vcmdq_log2size) will be the size of the vcmdq
+ * @vcmdq_base: guest physical address (IPA) to the vcmdq base address
+ */
include/uapi/linux/iommufd.h struct iommu_viommu_set_dev_id { · line 759
Quoted 5 lines
include/uapi/linux/iommufd.h +5
-0+struct iommu_vqueue_tegra241_cmdqv { +__u32 vcmdq_id; +__u32 vcmdq_log2size; +__aligned_u64 vcmdq_base; +};
Is there restriction that log2size cannot exceed 12?
According to patch14:
+ q_base = arm_smmu_domain_ipa_to_pa(vintf->s2_domain, arg.vcmdq_base);
+ vcmdq->cmdq.q.q_base = q_base & VCMDQ_ADDR;
+ vcmdq->cmdq.q.q_base |= arg.vcmdq_log2size;
It only converts the IPA to HPA for the starting page, assuming continuous host pages backing a guest cmd queue including multiple pages. but what guarantees it?
RFC PATCH 13/14 iommufd: Add mmap infrastructure
In reply to Nicolin ChenAdd for sharing the kernel page with user space. This allows to pass through HW resource (VCMDQ MMIO pages for example) to user space VMM and guest OS. Use vma->vm_pgoff as the carrier of a viommu_id.
--- drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ include/linux/iommufd.h | 4 ++++ 2 files changed, 44 insertions(+)
drivers/iommu/iommufd/main.c +40 -0
@@ -16,6 +16,7 @@#include <linux/mutex.h> #include <linux/bug.h> #include <uapi/linux/iommufd.h> +#include <linux/iommu.h> #include <linux/iommufd.h> #include "io_pagetable.h"
@@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd,return ret; } +static int iommufd_fops_mmap (struct file *filp,struct vm_area_struct *vma) +{ +struct iommufd_ctx *ictx = filp->private_data; +size_t size = vma->vm_end - vma->vm_start; +u32 viommu_id = (u32 )vma->vm_pgoff; +struct iommufd_viommu *viommu; +unsigned long pfn; +int rc; + +if (size >PAGE_SIZE ) +return -EINVAL ; + + viommu =container_of (iommufd_get_object (ictx, viommu_id, +IOMMUFD_OBJ_VIOMMU ), + struct iommufd_viommu, obj); +if (IS_ERR (viommu)) +return PTR_ERR (viommu); + +if (!viommu->ops->get_mmap_pfn) { + rc = -EOPNOTSUPP ; + goto out_put_viommu; + } + + pfn = viommu->ops->get_mmap_pfn (viommu, size); +if (!pfn) { + rc = -ENOMEM ; + goto out_put_viommu; + } + + vma->vm_pgoff =0 ; + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot); +vm_flags_set (vma,VM_IO |VM_PFNMAP |VM_DONTEXPAND |VM_DONTDUMP ); + rc =remap_pfn_range (vma, vma->vm_start, pfn, size, vma->vm_page_prot); +out_put_viommu: +iommufd_put_object (ictx, &viommu->obj); +return rc; +} +static const struct file_operations iommufd_fops = { .owner =THIS_MODULE , .open = iommufd_fops_open, .release = iommufd_fops_release, .unlocked_ioctl = iommufd_fops_ioctl, + .mmap = iommufd_fops_mmap, };/**
include/linux/iommufd.h +4 -0
@@ -104,6 +104,8 @@ struct iommufd_viommu {* the include/uapi/linux/iommufd.h header. * @vqueue_free: Free all driver-specific parts of an iommufd_vqueue. The memory * of the iommufd_vqueue will be free-ed by iommufd core +* @get_mmap_pfn: Return the PFN of a viommu given a finite size, for user space +* to mmap the page(s). */ struct iommufd_viommu_ops {void (*free)(struct iommufd_viommu *viommu);
@@ -114,6 +116,8 @@ struct iommufd_viommu_ops {struct iommufd_viommu *viommu, const struct iommu_user_data *user_data);void (*vqueue_free)(struct iommufd_vqueue *vqueue); +unsigned long (*get_mmap_pfn)(struct iommufd_viommu *viommu, +size_t pgsize); };struct iommufd_vqueue {
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerRe: [PATCH RFCv1 13/14] iommufd: Add mmap infrastructure
Quoted 23 lines · Nicolin Chen
Add for sharing the kernel page with user space. This allows to pass through HW resource (VCMDQ MMIO pages for example) to user space VMM and guest OS. Use
vma->vm_pgoffas the carrier of aviommu_id.Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ include/linux/iommufd.h | 4 ++++ 2 files changed, 44 insertions(+)drivers/iommu/iommufd/main.c +1
-0@@ -16,6 +16,7 @@#include <linux/mutex.h> #include <linux/bug.h> #include <uapi/linux/iommufd.h> +#include <linux/iommu.h> #include <linux/iommufd.h> #include "io_pagetable.h"
drivers/iommu/iommufd/main.c static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd, · line 435
Quoted 8 lines
drivers/iommu/iommufd/main.c +5
-0@@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd,return ret; } +static int iommufd_fops_mmap (struct file *filp,struct vm_area_struct *vma) +{ +struct iommufd_ctx *ictx = filp->private_data; +size_t size = vma->vm_end - vma->vm_start; +u32 viommu_id = (u32 )vma->vm_pgoff;
Don't do mmaps this way, it doesn't scale well for future things.
The pgoff/length should *always* come from the kernel as some 'mmap_offset' output. I usually call this the mmap cookie.
In this case have the mmap cookie for the tegra doorbell return in the viommu's driver data struct, then userspace just passes the opaque cookie to mmap to get the correct tegra doorbell.
The core code has some simple xarray/maple tree to allocate cookies and dispatch them to the correct mmap callback. Usually I'd say to provide a mmap callback pointer when allocating the cookie.
Also look at the RDMA Code around mmap there is a bunch of VMA validations needed. Ie we must insist on VM_SHARED and check permissions, etc.
Jason
Re: [PATCH RFCv1 13/14] iommufd: Add mmap infrastructure
Quoted 42 lines · Jason Gunthorpe
Quoted 23 lines · Nicolin Chen
Add for sharing the kernel page with user space. This allows to pass through HW resource (VCMDQ MMIO pages for example) to user space VMM and guest OS. Use
vma->vm_pgoffas the carrier of aviommu_id.Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ include/linux/iommufd.h | 4 ++++ 2 files changed, 44 insertions(+)drivers/iommu/iommufd/main.c +1
-0@@ -16,6 +16,7 @@#include <linux/mutex.h> #include <linux/bug.h> #include <uapi/linux/iommufd.h> +#include <linux/iommu.h> #include <linux/iommufd.h> #include "io_pagetable.h" drivers/iommu/iommufd/main.c static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd, · line 435
Quoted 8 lines
drivers/iommu/iommufd/main.c +5
-0@@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd,return ret; } +static int iommufd_fops_mmap (struct file *filp,struct vm_area_struct *vma) +{ +struct iommufd_ctx *ictx = filp->private_data; +size_t size = vma->vm_end - vma->vm_start; +u32 viommu_id = (u32 )vma->vm_pgoff;Don't do mmaps this way, it doesn't scale well for future things.
The pgoff/length should *always* come from the kernel as some '
mmap_offset' output. I usually call this the mmap cookie.In this case have the mmap cookie for the tegra doorbell return in the viommu's driver data struct, then userspace just passes the opaque cookie to mmap to get the correct tegra doorbell.
Quoted 7 lines
The core code has some simple xarray/maple tree to allocate cookies and dispatch them to the correct mmap callback. Usually I'd say to provide a mmap callback pointer when allocating the cookie.
Also look at the RDMA Code around mmap there is a bunch of VMA validations needed. Ie we must insist on
VM_SHAREDand check permissions, etc.
Yea, the vm_pgoff as a carrier is a bit of hack, as mentioned in the cover-letter. Let me revisit the whole thing and study from RDMA code also.
Thanks
Nicolin
RFC PATCH 14/14 iommu/tegra241-cmdqv: Add user-space use support
In reply to Nicolin ChenAdd the support via VIOMMU infrastructure for virtualization use case.
This basically allows VMM to allocate VINTFs (as a viommu object) and assign VCMDQs to it. A VINTF's MMIO page0 can be mmap'd to user space for VM to access directly without VMEXIT and corresponding hypercall.
As an initial version, the number of VCMDQs per VINTF is fixed to two.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 19 ++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 19 ++ .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 284 +++++++++++++++++- 3 files changed, 317 insertions(+), 5 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +19 -0
@@ -17,6 +17,7 @@#include <linux/err.h> #include <linux/interrupt.h> #include <linux/io-pgtable.h> +#include <linux/iommufd.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/msi.h>
@@ -3077,6 +3078,23 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid)arm_smmu_sva_remove_dev_pasid (domain, dev, pasid); } +static struct iommufd_viommu *arm_smmu_viommu_alloc (struct device *dev, +unsigned int viommu_type, +struct iommu_domain *domain) +{ +struct arm_smmu_domain *smmu_domain =to_smmu_domain_devices (domain); +struct arm_smmu_master *master =dev_iommu_priv_get (dev); + +if (!master || !master->smmu) +return ERR_PTR (-ENODEV ); + +if (master->smmu->tegra241_cmdqv && + viommu_type ==IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV ) +return tegra241_cmdqv_viommu_alloc ( + master->smmu->tegra241_cmdqv, smmu_domain); +return ERR_PTR (-EOPNOTSUPP ); +} +static struct iommu_ops arm_smmu_ops = { .identity_domain = &arm_smmu_identity_domain, .blocked_domain = &arm_smmu_blocked_domain,
@@ -3091,6 +3109,7 @@ static struct iommu_ops arm_smmu_ops = { .remove_dev_pasid = arm_smmu_remove_dev_pasid, .dev_enable_feat = arm_smmu_dev_enable_feature, .dev_disable_feat = arm_smmu_dev_disable_feature, + .viommu_alloc = arm_smmu_viommu_alloc, .page_response = arm_smmu_page_response, .def_domain_type = arm_smmu_def_domain_type, .pgsize_bitmap = -1UL, /* Restricted during device attach */
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +19 -0
@@ -701,6 +701,7 @@ struct arm_smmu_device {struct arm_smmu_stream {u32 id; +u32 cmdqv_sid_slot;struct arm_smmu_master *master;struct rb_node node; };
@@ -776,6 +777,14 @@ int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, unsigned long prod_off, unsigned long cons_off, size_t dwords, const char *name); +static inline phys_addr_t +arm_smmu_domain_ipa_to_pa (struct arm_smmu_domain *smmu_domain,u64 ipa) +{ +if (WARN_ON_ONCE (smmu_domain->stage !=ARM_SMMU_DOMAIN_S2 )) +return 0 ; +return iommu_iova_to_phys (&smmu_domain->domain, ipa); +} +#ifdef CONFIG_ARM_SMMU_V3_SVA bool arm_smmu_sva_supported (struct arm_smmu_device *smmu);bool arm_smmu_master_sva_supported (struct arm_smmu_master *master);
@@ -838,6 +847,9 @@ tegra241_cmdqv_acpi_probe(struct arm_smmu_device *smmu, int id);int tegra241_cmdqv_device_reset (struct arm_smmu_device *smmu);struct arm_smmu_cmdq *tegra241_cmdqv_get_cmdq (struct arm_smmu_device *smmu,u64 *cmds,int n); +struct iommufd_viommu * +tegra241_cmdqv_viommu_alloc (struct tegra241_cmdqv *cmdqv, +struct arm_smmu_domain *smmu_domain);#else /* CONFIG_TEGRA241_CMDQV */ static inline struct tegra241_cmdqv *tegra241_cmdqv_acpi_probe (struct arm_smmu_device *smmu,int id)
@@ -855,6 +867,13 @@ tegra241_cmdqv_get_cmdq(struct arm_smmu_device *smmu, u64 *cmds, int n) {return NULL ; } + +static inline struct iommufd_viommu * +tegra241_cmdqv_viommu_alloc (struct tegra241_cmdqv *cmdqv, +struct arm_smmu_domain *smmu_domain); +{ +return -ENODEV ; +}#endif /* CONFIG_TEGRA241_CMDQV */ #endif /* _ARM_SMMU_V3_H */
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +279 -5
387 lines not on this page · raw message
Signature · 1 line
2.43.0
Tian, Kevin
maintainerQuoted 10 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMThis is an experimental RFC series for VIOMMU infrastructure, using NVIDIA Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed by an underlying IOMMU's HW-accelerated feature for virtualizaion: for example, NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
Quoted 6 lines
VQUEUE obj is used to represent a virtual command queue (buffer) backed by
an underlying IOMMU command queue to passthrough for VMs to use directly:
for example, NVIDIA's Virtual Command Queue and AMD's Command Buffer.
is VCMDQ more accurate? AMD also supports fault queue passthrough then VQUEUE sounds broader than a cmd queue...
Jason Gunthorpe
maintainerQuoted 17 lines · Kevin
Quoted 10 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMThis is an experimental RFC series for VIOMMU infrastructure, using NVIDIA Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed by an underlying IOMMU's HW-accelerated feature for virtualizaion: for example, NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
Quoted 6 lines
VQUEUE obj is used to represent a virtual command queue (buffer) backed by
an underlying IOMMU command queue to passthrough for VMs to use directly:
for example, NVIDIA's Virtual Command Queue and AMD's Command Buffer.
Quoted 2 lines
is VCMDQ more accurate? AMD also supports fault queue passthrough then VQUEUE sounds broader than a cmd queue...
Is there a reason VQUEUE couldn't handle the fault/etc queues too? The only difference is direction, there is still a doorbell/etc.
Jason
Quoted 18 lines · Jason Gunthorpe
Quoted 17 lines · Kevin
Quoted 16 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMThis is an experimental RFC series for VIOMMU infrastructure, using NVIDIA Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed by an underlying IOMMU's HW-accelerated feature for virtualizaion: for example, NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
VQUEUE obj is used to represent a virtual command queue (buffer) backed by
an underlying IOMMU command queue to passthrough for VMs to use directly:
for example, NVIDIA's Virtual Command Queue and AMD's Command Buffer.
Quoted 5 lines
Quoted 2 lines
is VCMDQ more accurate? AMD also supports fault queue passthrough then VQUEUE sounds broader than a cmd queue...
Is there a reason VQUEUE couldn't handle the fault/etc queues too? The only difference is direction, there is still a doorbell/etc.
Yea, SMMU also has Event Queue and PRI queue. Though I haven't got time to sit down to look at Baolu's work closely, the uAPI seems to be a unified one for all IOMMUs. And though I have no intention to be against that design, yet maybe there could be an alternative in a somewhat HW specific language as we do for invalidation? Or not worth it?
Thanks
Nicolin
Jason Gunthorpe
maintainerQuoted 25 lines · Nicolin Chen
Quoted 18 lines · Jason Gunthorpe
Quoted 17 lines · Kevin
Quoted 16 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMThis is an experimental RFC series for VIOMMU infrastructure, using NVIDIA Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed by an underlying IOMMU's HW-accelerated feature for virtualizaion: for example, NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
VQUEUE obj is used to represent a virtual command queue (buffer) backed by
an underlying IOMMU command queue to passthrough for VMs to use directly:
for example, NVIDIA's Virtual Command Queue and AMD's Command Buffer.Quoted 5 lines
Quoted 2 lines
is VCMDQ more accurate? AMD also supports fault queue passthrough then VQUEUE sounds broader than a cmd queue...
Is there a reason VQUEUE couldn't handle the fault/etc queues too? The only difference is direction, there is still a doorbell/etc.
Quoted 6 lines
Yea, SMMU also has Event Queue and PRI queue. Though I haven't got time to sit down to look at Baolu's work closely, the uAPI seems to be a unified one for all IOMMUs. And though I have no intention to be against that design, yet maybe there could be an alternative in a somewhat HW specific language as we do for invalidation? Or not worth it?
I was thinking not worth it, I expect a gain here is to do as AMD has done and make the HW dma the queues directly to guest memory.
IMHO the primary issue with the queues is DOS, as having any shared queue across VMs is dangerous in that way. Allowing each VIOMMU to have its own private queue and own flow control helps with that.
Jason
Tian, Kevin
maintainerQuoted 19 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 7:29 AMQuoted 6 lines · Nicolin Chen
Quoted 5 lines · Jason Gunthorpe
Quoted 4 lines · Kevin
Quoted 4 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, April 13, 2024 11:47 AMThis is an experimental RFC series for VIOMMU infrastructure, using
NVIDIA
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Tegra241 (Grace) CMDQV as a test instance.
VIOMMU obj is used to represent a virtual interface (iommu) backed
by an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
underlying IOMMU's HW-accelerated feature for virtualizaion: for
example,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
NVIDIA's VINTF (v-interface for CMDQV) and AMD"s vIOMMU.
Quoted 15 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
VQUEUE obj is used to represent a virtual command queue (buffer)
backed
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
by
an underlying IOMMU command queue to passthrough for VMs touse
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
directly:
for example, NVIDIA's Virtual Command Queue and AMD's CommandBuffer.
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
is VCMDQ more accurate? AMD also supports fault queue passthrough then VQUEUE sounds broader than a cmd queue...
Is there a reason VQUEUE couldn't handle the fault/etc queues too? The only difference is direction, there is still a doorbell/etc.
No reason. the description made it specific to a cmd queue which led me the impression that we may want to create a separate fault queue.
Quoted 8 lines
Quoted 7 lines
Yea, SMMU also has Event Queue and PRI queue. Though I haven't got time to sit down to look at Baolu's work closely, the uAPI seems to be a unified one for all IOMMUs. And though I have no intention to be against that design, yet maybe there could be an alternative in a somewhat HW specific language as we do for invalidation? Or not worth it?
Quoted 7 lines
I was thinking not worth it, I expect a gain here is to do as AMD has done and make the HW dma the queues directly to guest memory.
IMHO the primary issue with the queues is DOS, as having any shared queue across VMs is dangerous in that way. Allowing each VIOMMU to have its own private queue and own flow control helps with that.
and also shorter delivering path with less data copy?
Quoted 13 lines · Kevin
Quoted 13 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 7:29 AMQuoted 6 lines · Nicolin Chen
Yea, SMMU also has Event Queue and PRI queue. Though I haven't got time to sit down to look at Baolu's work closely, the uAPI seems to be a unified one for all IOMMUs. And though I have no intention to be against that design, yet maybe there could be an alternative in a somewhat HW specific language as we do for invalidation? Or not worth it?
I was thinking not worth it, I expect a gain here is to do as AMD has done and make the HW dma the queues directly to guest memory.
Quoted 6 lines
Quoted 4 lines
IMHO the primary issue with the queues is DOS, as having any shared queue across VMs is dangerous in that way. Allowing each VIOMMU to have its own private queue and own flow control helps with that.
and also shorter delivering path with less data copy?
Should I interpret that as a yes for fault report via VQUEUE?
We only have AMD that can HW dma the events to the guest queue memory. Others all need a backward translation of (at least) a physical dev ID to a virtual dev ID. This is now doable in the kernel by the ongoing vdev_id design by the way. So kernel then can write the guest memory directly to report events?
Thanks
Nicolin
Jason Gunthorpe
maintainerQuoted 21 lines · Nicolin Chen
Quoted 13 lines · Kevin
Quoted 13 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, May 23, 2024 7:29 AMQuoted 6 lines · Nicolin Chen
Yea, SMMU also has Event Queue and PRI queue. Though I haven't got time to sit down to look at Baolu's work closely, the uAPI seems to be a unified one for all IOMMUs. And though I have no intention to be against that design, yet maybe there could be an alternative in a somewhat HW specific language as we do for invalidation? Or not worth it?
I was thinking not worth it, I expect a gain here is to do as AMD has done and make the HW dma the queues directly to guest memory.
Quoted 6 lines
Quoted 4 lines
IMHO the primary issue with the queues is DOS, as having any shared queue across VMs is dangerous in that way. Allowing each VIOMMU to have its own private queue and own flow control helps with that.
and also shorter delivering path with less data copy?
Quoted 7 lines
Should I interpret that as a yes for fault report via VQUEUE?
We only have AMD that can HW dma the events to the guest queue memory. Others all need a backward translation of (at least) a physical dev ID to a virtual dev ID. This is now doable in the kernel by the ongoing
vdev_iddesign by the way. So kernel then can write the guest memory directly to report events?
I don't think we should get into kernel doing direct access at this point, lets focus on basic functionality before we get to microoptimizations like that.
So long as the API could support doing something like that it could be done after benchmarking/etc.
Jason