iommufd: Add vIOMMU infrastructure (Part-3: vEVENTQ)
Subsystems (5)
v4 cover iommufd: Add vIOMMU infrastructure (Part-3: vEVENTQ)
As the vIOMMU infrastructure series part-3, this introduces a new vEVENTQ object. The existing FAULT object provides a nice notification pathway to the user space with a queue already, so let vEVENTQ reuse that.
Mimicing the HWPT structure, add a common EVENTQ structure to support its
derivatives: IOMMUFD_OBJ_FAULT (existing) and IOMMUFD_OBJ_VEVENTQ (new).
An IOMMUFD_CMD_VEVENTQ_ALLOC is introduced to allocate vEVENTQ object for vIOMMUs. One vIOMMU can have multiple vEVENTQs in different types but can not support multiple vEVENTQs in the same type.
The forwarding part is fairly simple but might need to replace a physical device ID with a virtual device ID in a driver-level event data structure. So, this also adds some helpers for drivers to use.
As usual, this series comes with the selftest coverage for this new ioctl and with a real world use case in the ARM SMMUv3 driver.
This is on Github:
https://github.com/nicolinc/iommufd/commits/iommufd_veventq-v4
Testing with RMR patches for MSI:
https://github.com/nicolinc/iommufd/commits/iommufd_veventq-v4-with-rmr
Paring QEMU branch for testing:
https://github.com/nicolinc/qemu/commits/wip/for_iommufd_veventq-v4
Changelog
v4
* Rename "vIRQ" to "vEVENTQ"
* Use flexible array in struct iommufd_vevent
* Add the new ioctl command to union ucmd_buffer
* Fix the alphabetical order in union ucmd_buffer too
* Rename _TYPE_NONE to _TYPE_DEFAULT aligning with vIOMMU naming
v3
https://lore.kernel.org/all/[email protected]/
* Rebase on Will's for-joerg/arm-smmu/updates for arm_smmu_event series
* Add "Reviewed-by" lines from Kevin
* Fix typos in comments, kdocs, and jump tags
* Add a patch to sort struct iommufd_ioctl_op
* Update iommufd's userpsace-api documentation
* Update uAPI kdoc to quote SMMUv3 offical spec
* Drop the unused workqueue in struct iommufd_virq
* Drop might_sleep() in iommufd_viommu_report_irq() helper
* Add missing "break" in iommufd_viommu_get_vdev_id() helper
* Shrink the scope of the vmaster's read lock in SMMUv3 driver
* Pass in two arguments to iommufd_eventq_virq_handler() helper
* Move "!ops || !ops->read" validation into iommufd_eventq_init()
* Move "fault->ictx = ictx" closer to iommufd_ctx_get(fault->ictx)
* Update commit message for arm_smmu_attach_prepare/commit_vmaster()
* Keep "iommufd_fault" as-is and rename "iommufd_eventq_virq" to just "iommufd_virq"
v2
https://lore.kernel.org/all/[email protected]/
* Rebase on v6.13-rc1
* Add IOPF and vIRQ in iommufd.rst (userspace-api)
* Add a proper locking in iommufd_event_virq_destroy
* Add iommufd_event_virq_abort with a lockdep_assert_held
* Rename "EVENT_*" to "EVENTQ_*" to describe the objects better
* Reorganize flows in iommufd_eventq_virq_alloc for abort() to work
* Adde struct arm_smmu_vmaster to store vSID upon attaching to a nested domain, calling a newly added iommufd_viommu_get_vdev_id helper
* Adde an arm_vmaster_report_event helper in arm-smmu-v3-iommufd file to simplify the routine in arm_smmu_handle_evt() of the main driver
v1
https://lore.kernel.org/all/[email protected]/
Thanks!
Nicolin
Nicolin Chen (14):
iommufd: Keep IOCTL list in an alphabetical order iommufd/fault: Add an iommufd_fault_init() helper iommufd/fault: Move iommufd_fault_iopf_handler() to header
iommufd: Abstract an iommufd_eventq from iommufd_fault
iommufd: Rename fault.c to eventq.c
iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC iommufd/viommu: Add iommufd_viommu_get_vdev_id helper iommufd/viommu: Add iommufd_viommu_report_event helper iommufd/selftest: Require vdev_id when attaching to a nested domain iommufd/selftest: Add IOMMU_TEST_OP_TRIGGER_VEVENT for vEVENTQ
coverage
iommufd/selftest: Add IOMMU_VEVENTQ_ALLOC test coverage
Documentation: userspace-api: iommufd: Update FAULT and VEVENTQ iommu/arm-smmu-v3: Introduce struct arm_smmu_vmaster iommu/arm-smmu-v3: Report events that belong to devices attached to
vIOMMU
drivers/iommu/iommufd/Makefile | 2 +-
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 30 ++
drivers/iommu/iommufd/iommufd_private.h | 116 ++++++-
drivers/iommu/iommufd/iommufd_test.h | 10 +
include/linux/iommufd.h | 22 ++
include/uapi/linux/iommufd.h | 46 +++
tools/testing/selftests/iommu/iommufd_utils.h | 65 ++++
.../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 65 ++++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 90 ++++--
drivers/iommu/iommufd/driver.c | 60 ++++
drivers/iommu/iommufd/{fault.c => eventq.c} | 298 ++++++++++++++----
drivers/iommu/iommufd/hw_pagetable.c | 6 +-
drivers/iommu/iommufd/main.c | 23 +-
drivers/iommu/iommufd/selftest.c | 53 ++++
drivers/iommu/iommufd/viommu.c | 2 +
tools/testing/selftests/iommu/iommufd.c | 27 ++
.../selftests/iommu/iommufd_fail_nth.c | 7 +
Documentation/userspace-api/iommufd.rst | 16 +
18 files changed, 820 insertions(+), 118 deletions(-)
rename drivers/iommu/iommufd/{fault.c => eventq.c} (55%)base-commit: e94dc6ddda8dd3770879a132d577accd2cce25f9
Signature · 1 line
2.43.0
PATCH v4 1/14 iommufd: Keep IOCTL list in an alphabetical order
Move VDEVICE upward to keep the order. Also run clang-format for the same coding style at line wrappings. No functional change.
--- drivers/iommu/iommufd/main.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/iommu/iommufd/main.c +7 -9
@@ -307,9 +307,9 @@ union ucmd_buffer {struct iommu_ioas_map map;struct iommu_ioas_unmap unmap;struct iommu_option option; +struct iommu_vdevice_alloc vdev;struct iommu_vfio_ioas vfio_ioas;struct iommu_viommu_alloc viommu; -struct iommu_vdevice_alloc vdev;#ifdef CONFIG_IOMMUFD_TEST struct iommu_test_cmd test;#endif
@@ -333,8 +333,8 @@ struct iommufd_ioctl_op { }static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { IOCTL_OP(IOMMU_DESTROY, iommufd_destroy, struct iommu_destroy, id), - IOCTL_OP(IOMMU_FAULT_QUEUE_ALLOC, iommufd_fault_alloc, struct iommu_fault_alloc, - out_fault_fd), +IOCTL_OP (IOMMU_FAULT_QUEUE_ALLOC , iommufd_fault_alloc, + struct iommu_fault_alloc, out_fault_fd), IOCTL_OP(IOMMU_GET_HW_INFO, iommufd_get_hw_info, struct iommu_hw_info, __reserved), IOCTL_OP(IOMMU_HWPT_ALLOC, iommufd_hwpt_alloc, struct iommu_hwpt_alloc,
@@ -355,20 +355,18 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { src_iova),IOCTL_OP (IOMMU_IOAS_IOVA_RANGES ,iommufd_ioas_iova_ranges ,struct iommu_ioas_iova_ranges ,out_iova_alignment ), -IOCTL_OP (IOMMU_IOAS_MAP ,iommufd_ioas_map ,struct iommu_ioas_map , -iova ), +IOCTL_OP (IOMMU_IOAS_MAP ,iommufd_ioas_map ,struct iommu_ioas_map ,iova ),IOCTL_OP (IOMMU_IOAS_MAP_FILE ,iommufd_ioas_map_file ,struct iommu_ioas_map_file ,iova ),IOCTL_OP (IOMMU_IOAS_UNMAP ,iommufd_ioas_unmap ,struct iommu_ioas_unmap ,length ), -IOCTL_OP (IOMMU_OPTION ,iommufd_option ,struct iommu_option , -val64 ), +IOCTL_OP (IOMMU_OPTION ,iommufd_option ,struct iommu_option ,val64 ), +IOCTL_OP (IOMMU_VDEVICE_ALLOC ,iommufd_vdevice_alloc_ioctl , +struct iommu_vdevice_alloc ,virt_id ),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 ), -IOCTL_OP (IOMMU_VDEVICE_ALLOC ,iommufd_vdevice_alloc_ioctl , -struct iommu_vdevice_alloc ,virt_id ), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif
Signature · 1 line
2.43.0
Re: [PATCH v4 01/14] iommufd: Keep IOCTL list in an alphabetical order
Quoted 7 lines · Nicolin Chen
Move VDEVICE upward to keep the order. Also run clang-format for the same coding style at line wrappings. No functional change.
Signed-off-by Nicolin Chen<[email protected]>--- drivers/iommu/iommufd/main.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
PATCH v4 2/14 iommufd/fault: Add an iommufd_fault_init() helper
In reply to Nicolin ChenThe infrastructure of a fault object will be shared with a new vEVENTQ object in a following change. Add a helper for a vEVENTQ allocator to call it too.
Reorder the iommufd_ctx_get and refcount_inc, to keep them symmetrical with the iommufd_fault_fops_release().
Since the new vEVENTQ doesn't need "response", leave the xa_init_flags in its original location.
--- drivers/iommu/iommufd/fault.c | 48 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-)
drivers/iommu/iommufd/fault.c +28 -20
@@ -367,11 +367,35 @@ static const struct file_operations iommufd_fault_fops = { .release = iommufd_fault_fops_release, }; +static int iommufd_fault_init (struct iommufd_fault *fault,char *name, +struct iommufd_ctx *ictx) +{ +struct file *filep; +int fdno; + +mutex_init (&fault->mutex); +INIT_LIST_HEAD (&fault->deliver); +init_waitqueue_head (&fault->wait_queue); + + filep =anon_inode_getfile (name, &iommufd_fault_fops, fault,O_RDWR ); +if (IS_ERR (filep)) +return PTR_ERR (filep); + + fault->ictx = ictx; +iommufd_ctx_get (fault->ictx); + fault->filep = filep; +refcount_inc (&fault->obj.users); + + fdno =get_unused_fd_flags (O_CLOEXEC ); +if (fdno <0 ) +fput (filep); +return fdno; +} +int iommufd_fault_alloc (struct iommufd_ucmd *ucmd) {struct iommu_fault_alloc *cmd = ucmd->cmd;struct iommufd_fault *fault; -struct file *filep;int fdno;int rc;
@@ -382,27 +406,12 @@ int iommufd_fault_alloc(struct iommufd_ucmd *ucmd)if (IS_ERR (fault))return PTR_ERR (fault); - fault->ictx = ucmd->ictx; -INIT_LIST_HEAD (&fault->deliver);xa_init_flags (&fault->response,XA_FLAGS_ALLOC1 ); -mutex_init (&fault->mutex); -init_waitqueue_head (&fault->wait_queue); - - filep =anon_inode_getfile ("[iommufd-pgfault]" , &iommufd_fault_fops, - fault,O_RDWR ); -if (IS_ERR (filep)) { - rc =PTR_ERR (filep); - goto out_abort; - } -refcount_inc (&fault->obj.users); -iommufd_ctx_get (fault->ictx); - fault->filep = filep; - - fdno =get_unused_fd_flags (O_CLOEXEC ); + fdno =iommufd_fault_init (fault,"[iommufd-pgfault]" , ucmd->ictx);if (fdno <0 ) { rc = fdno; - goto out_fput; + goto out_abort; } cmd->out_fault_id = fault->obj.id;
@@ -418,8 +427,7 @@ int iommufd_fault_alloc(struct iommufd_ucmd *ucmd)return 0 ; out_put_fdno:put_unused_fd (fdno); -out_fput: -fput (filep); +fput (fault->filep); out_abort:iommufd_object_abort_and_destroy (ucmd->ictx, &fault->obj);
Signature · 1 line
2.43.0
Re: [PATCH v4 02/14] iommufd/fault: Add an iommufd_fault_init() helper
Quoted 7 lines · Nicolin Chen
The infrastructure of a fault object will be shared with a new vEVENTQ object in a following change. Add a helper for a vEVENTQ allocator to call it too.
Reorder the
iommufd_ctx_getandrefcount_inc, to keep them symmetrical with theiommufd_fault_fops_release().
Quoted 8 lines
Since the new vEVENTQ doesn't need "response", leave the
xa_init_flagsin its original location.Reviewed-by Kevin Tian<[email protected]>Signed-off-by Nicolin Chen<[email protected]>--- drivers/iommu/iommufd/fault.c | 48 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-)
PATCH v4 3/14 iommufd/fault: Move iommufd_fault_iopf_handler() to header
In reply to Nicolin ChenThe new vEVENTQ object will need a similar function for drivers to report the vIOMMU related events. Split the common part out to a smaller helper, and place it in the header so that CONFIG_IOMMUFD_DRIVER_CORE can include that in the driver.c file for drivers to use.
Then keep iommufd_fault_iopf_handler() in the header too, since it's quite simple after all.
--- drivers/iommu/iommufd/iommufd_private.h | 20 +++++++++++++++++++- drivers/iommu/iommufd/fault.c | 17 ----------------- 2 files changed, 19 insertions(+), 18 deletions(-)
drivers/iommu/iommufd/iommufd_private.h +19 -1
@@ -451,6 +451,17 @@ struct iommufd_fault {struct wait_queue_head wait_queue; }; +static inline int iommufd_fault_notify (struct iommufd_fault *fault, +struct list_head *new_fault) +{ +mutex_lock (&fault->mutex); +list_add_tail (new_fault, &fault->deliver); +mutex_unlock (&fault->mutex); + +wake_up_interruptible (&fault->wait_queue); +return 0 ; +} +struct iommufd_attach_handle {struct iommu_attach_handle handle;struct iommufd_device *idev;
@@ -469,7 +480,14 @@ iommufd_get_fault(struct iommufd_ucmd *ucmd, u32 id)int iommufd_fault_alloc (struct iommufd_ucmd *ucmd);void iommufd_fault_destroy (struct iommufd_object *obj); -int iommufd_fault_iopf_handler (struct iopf_group *group); + +static inline int iommufd_fault_iopf_handler (struct iopf_group *group) +{ +struct iommufd_hw_pagetable *hwpt = + group->attach_handle->domain->fault_data; + +return iommufd_fault_notify (hwpt->fault, &group->node); +}int iommufd_fault_domain_attach_dev (struct iommufd_hw_pagetable *hwpt,struct iommufd_device *idev);
drivers/iommu/iommufd/fault.c +0 -17
@@ -433,20 +433,3 @@ int iommufd_fault_alloc(struct iommufd_ucmd *ucmd)return rc; } - -int iommufd_fault_iopf_handler (struct iopf_group *group) -{ -struct iommufd_hw_pagetable *hwpt; -struct iommufd_fault *fault; - - hwpt = group->attach_handle->domain->fault_data; - fault = hwpt->fault; - -mutex_lock (&fault->mutex); -list_add_tail (&group->node, &fault->deliver); -mutex_unlock (&fault->mutex); - -wake_up_interruptible (&fault->wait_queue); - -return 0 ; -}
Signature · 1 line
2.43.0
Re: [PATCH v4 03/14] iommufd/fault: Move iommufd_fault_iopf_handler() to header
Quoted 8 lines · Nicolin Chen
The new vEVENTQ object will need a similar function for drivers to report the vIOMMU related events. Split the common part out to a smaller helper, and place it in the header so that
CONFIG_IOMMUFD_DRIVER_COREcan include that in thedriver.cfile for drivers to use.Then keep
iommufd_fault_iopf_handler()in the header too, since it's quite simple after all.
Quoted 6 lines
Reviewed-by Kevin Tian<[email protected]>Signed-off-by Nicolin Chen<[email protected]>--- drivers/iommu/iommufd/iommufd_private.h | 20 +++++++++++++++++++- drivers/iommu/iommufd/fault.c | 17 ----------------- 2 files changed, 19 insertions(+), 18 deletions(-)
PATCH v4 4/14 iommufd: Abstract an iommufd_eventq from iommufd_fault
In reply to Nicolin ChenThe fault object was designed exclusively for hwpt's IO page faults (PRI). But its queue implementation can be reused for other purposes too, such as hardware IRQ and event injections to user space.
Meanwhile, a fault object holds a list of faults. So it's more accurate to call it a "fault queue". Combining the reusing idea above, abstract a new iommufd_eventq as a common structure embedded into struct iommufd_fault, similar to hwpt_paging holding a common hwpt.
Add a common iommufd_eventq_ops and iommufd_eventq_init to prepare for an IOMMUFD_OBJ_VEVENTQ (vIOMMU Event Queue).
Also, add missing xa_destroy and mutex_destroy in iommufd_fault_destroy().
--- drivers/iommu/iommufd/iommufd_private.h | 52 ++++++--- drivers/iommu/iommufd/fault.c | 142 +++++++++++++++--------- drivers/iommu/iommufd/hw_pagetable.c | 6 +- 3 files changed, 130 insertions(+), 70 deletions(-)
drivers/iommu/iommufd/iommufd_private.h +36 -16
@@ -18,6 +18,7 @@ struct iommu_domain;struct iommu_group ;struct iommu_option ;struct iommufd_device ; +struct iommufd_eventq ;struct iommufd_ctx {struct file *file;
@@ -433,32 +434,35 @@ void iopt_remove_access(struct io_pagetable *iopt, u32 iopt_access_list_id);void iommufd_access_destroy_object (struct iommufd_object *obj); -/* -* An iommufd_fault object represents an interface to deliver I/O page faults -* to the user space. These objects are created/destroyed by the user space and -* associated with hardware page table objects during page-table allocation. -*/ -struct iommufd_fault { +struct iommufd_eventq_ops { +ssize_t (*read)(struct iommufd_eventq *eventq,char __user *buf, +size_t count,loff_t *ppos);/* Mandatory op */ +ssize_t (*write)(struct iommufd_eventq *eventq,const char __user *buf, +size_t count,loff_t *ppos);/* Optional op */ +}; + +struct iommufd_eventq {struct iommufd_object obj;struct iommufd_ctx *ictx;struct file *filep; -/* The lists of outstanding faults protected by below mutex. */ +const struct iommufd_eventq_ops *ops; + +/* The lists of outstanding events protected by below mutex. */ struct mutex mutex;struct list_head deliver; -struct xarray response;struct wait_queue_head wait_queue; }; -static inline int iommufd_fault_notify (struct iommufd_fault *fault, -struct list_head *new_fault) +static inline int iommufd_eventq_notify (struct iommufd_eventq *eventq, +struct list_head *new_event) { -mutex_lock (&fault->mutex); -list_add_tail (new_fault, &fault->deliver); -mutex_unlock (&fault->mutex); +mutex_lock (&eventq->mutex); +list_add_tail (new_event, &eventq->deliver); +mutex_unlock (&eventq->mutex); -wake_up_interruptible (&fault->wait_queue); +wake_up_interruptible (&eventq->wait_queue);return 0 ; }
@@ -470,12 +474,28 @@ struct iommufd_attach_handle {/* Convert an iommu attach handle to iommufd handle. */ #define to_iommufd_handle (hdl) container_of(hdl, struct iommufd_attach_handle, handle) +/* +* An iommufd_fault object represents an interface to deliver I/O page faults +* to the user space. These objects are created/destroyed by the user space and +* associated with hardware page table objects during page-table allocation. +*/ +struct iommufd_fault { +struct iommufd_eventq common; +struct xarray response; +}; + +static inline struct iommufd_fault * +eventq_to_fault (struct iommufd_eventq *eventq) +{ + return container_of(eventq, struct iommufd_fault, common); +} +static inline struct iommufd_fault *iommufd_get_fault (struct iommufd_ucmd *ucmd,u32 id) {return container_of (iommufd_get_object (ucmd->ictx, id,IOMMUFD_OBJ_FAULT ), - struct iommufd_fault, obj); + struct iommufd_fault, common.obj); }int iommufd_fault_alloc (struct iommufd_ucmd *ucmd);
@@ -486,7 +506,7 @@ static inline int iommufd_fault_iopf_handler(struct iopf_group *group)struct iommufd_hw_pagetable *hwpt = group->attach_handle->domain->fault_data; -return iommufd_fault_notify (hwpt->fault, &group->node); +return iommufd_eventq_notify (&hwpt->fault->common, &group->node); } int iommufd_fault_domain_attach_dev(struct iommufd_hw_pagetable *hwpt,
drivers/iommu/iommufd/fault.c +91 -51
270 lines not on this page · raw message
drivers/iommu/iommufd/hw_pagetable.c +3 -3
@@ -14,7 +14,7 @@ static void __iommufd_hwpt_destroy(struct iommufd_hw_pagetable *hwpt)iommu_domain_free (hwpt->domain);if (hwpt->fault) -refcount_dec (&hwpt->fault->obj.users); +refcount_dec (&hwpt->fault->common.obj.users); }void iommufd_hwpt_paging_destroy (struct iommufd_object *obj)
@@ -403,8 +403,8 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd) hwpt->fault = fault; hwpt->domain->iopf_handler = iommufd_fault_iopf_handler; hwpt->domain->fault_data = hwpt; -refcount_inc (&fault->obj.users); -iommufd_put_object (ucmd->ictx, &fault->obj); +refcount_inc (&fault->common.obj.users); +iommufd_put_object (ucmd->ictx, &fault->common.obj); } cmd->out_hwpt_id = hwpt->obj.id;
Signature · 1 line
2.43.0
Re: [PATCH v4 04/14] iommufd: Abstract an iommufd_eventq from iommufd_fault
Quoted 12 lines · Nicolin Chen
The fault object was designed exclusively for hwpt's IO page faults (PRI). But its queue implementation can be reused for other purposes too, such as hardware IRQ and event injections to user space.
Meanwhile, a fault object holds a list of faults. So it's more accurate to call it a "fault queue". Combining the reusing idea above, abstract a new
iommufd_eventqas a common structure embedded into structiommufd_fault, similar tohwpt_pagingholding a common hwpt.Add a common
iommufd_eventq_opsandiommufd_eventq_initto prepare for anIOMMUFD_OBJ_VEVENTQ(vIOMMU Event Queue).
Quoted 8 lines
Also, add missing
xa_destroyandmutex_destroyiniommufd_fault_destroy().Signed-off-by Nicolin Chen<[email protected]>--- drivers/iommu/iommufd/iommufd_private.h | 52 ++++++--- drivers/iommu/iommufd/fault.c | 142 +++++++++++++++--------- drivers/iommu/iommufd/hw_pagetable.c | 6 +- 3 files changed, 130 insertions(+), 70 deletions(-)
PATCH v4 5/14 iommufd: Rename fault.c to eventq.c
In reply to Nicolin ChenRename the file, aligning with the new eventq object.
---
drivers/iommu/iommufd/Makefile | 2 +-
drivers/iommu/iommufd/{fault.c => eventq.c} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename drivers/iommu/iommufd/{fault.c => eventq.c} (100%)drivers/iommu/iommufd/Makefile +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only iommufd-y := \ device.o \ - fault.o \ + eventq.o \ hw_pagetable.o \ io_pagetable.o \ ioas.o \
drivers/iommu/iommufd/eventq.c renamed from drivers/iommu/iommufd/fault.c +0 -0
Signature · 1 line
2.43.0
Re: [PATCH v4 05/14] iommufd: Rename fault.c to eventq.c
Quoted 9 lines · Nicolin Chen
Rename the file, aligning with the new eventq object.
Reviewed-by Kevin Tian<[email protected]>Signed-off-by Nicolin Chen<[email protected]>--- drivers/iommu/iommufd/Makefile | 2 +- drivers/iommu/iommufd/{fault.c => eventq.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-)rename
drivers/iommu/iommufd/{fault.c=>eventq.c} (100%)
PATCH v4 6/14 iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC
In reply to Nicolin ChenIntroduce a new IOMMUFD_OBJ_VEVENTQ object for vIOMMU Event Queue that provides user space (VMM) another FD to read the vIOMMU Events.
Allow a vIOMMU object to allocate vEVENTQs, with a condition that each vIOMMU can only have one single vEVENTQ per type.
Add iommufd_veventq_alloc() with iommufd_veventq_ops for the new ioctl.
--- drivers/iommu/iommufd/iommufd_private.h | 58 +++++++++++ include/linux/iommufd.h | 3 + include/uapi/linux/iommufd.h | 31 ++++++ drivers/iommu/iommufd/eventq.c | 129 ++++++++++++++++++++++++ drivers/iommu/iommufd/main.c | 7 ++ drivers/iommu/iommufd/viommu.c | 2 + 6 files changed, 230 insertions(+)
drivers/iommu/iommufd/iommufd_private.h +58 -0
@@ -547,6 +547,50 @@ static inline int iommufd_hwpt_replace_device(struct iommufd_device *idev,return iommu_group_replace_domain (idev->igroup->group, hwpt->domain); } +/* +* An iommufd_veventq object represents an interface to deliver vIOMMU events to +* the user space. It is created/destroyed by the user space and associated with +* vIOMMU object(s) during the allocations. +*/ +struct iommufd_veventq { +struct iommufd_eventq common; +struct iommufd_viommu *viommu; +struct list_head node;/* for iommufd_viommu::veventqs */ + +unsigned int type; +}; + +static inline struct iommufd_veventq * +eventq_to_veventq (struct iommufd_eventq *eventq) +{ + return container_of(eventq, struct iommufd_veventq, common); +} + +static inline struct iommufd_veventq * +iommufd_get_veventq (struct iommufd_ucmd *ucmd,u32 id) +{ +return container_of (iommufd_get_object (ucmd->ictx, id, +IOMMUFD_OBJ_VEVENTQ ), + struct iommufd_veventq, common.obj); +} + +int iommufd_veventq_alloc (struct iommufd_ucmd *ucmd); +void iommufd_veventq_destroy (struct iommufd_object *obj); +void iommufd_veventq_abort (struct iommufd_object *obj); + +/* An iommufd_vevent represents a vIOMMU event in an iommufd_veventq */ +struct iommufd_vevent { +struct list_head node;/* for iommufd_eventq::deliver */ +ssize_t data_len; + u64 event_data[] __counted_by(data_len); +}; + +static inline int iommufd_vevent_handler (struct iommufd_veventq *veventq, +struct iommufd_vevent *vevent) +{ +return iommufd_eventq_notify (&veventq->common, &vevent->node); +} +static inline struct iommufd_viommu *iommufd_get_viommu (struct iommufd_ucmd *ucmd,u32 id) {
@@ -555,6 +599,20 @@ iommufd_get_viommu(struct iommufd_ucmd *ucmd, u32 id) struct iommufd_viommu, obj); } +static inline struct iommufd_veventq * +iommufd_viommu_find_veventq (struct iommufd_viommu *viommu,u32 type) +{ +struct iommufd_veventq *veventq, *next; + +lockdep_assert_held (&viommu->veventqs_rwsem); + +list_for_each_entry_safe (veventq, next, &viommu->veventqs, node) { +if (veventq->type == type) +return veventq; + } +return NULL ; +} +int iommufd_viommu_alloc_ioctl (struct iommufd_ucmd *ucmd);void iommufd_viommu_destroy (struct iommufd_object *obj);int iommufd_vdevice_alloc_ioctl (struct iommufd_ucmd *ucmd);
include/linux/iommufd.h +3 -0
@@ -34,6 +34,7 @@ enum iommufd_object_type {IOMMUFD_OBJ_FAULT ,IOMMUFD_OBJ_VIOMMU ,IOMMUFD_OBJ_VDEVICE , +IOMMUFD_OBJ_VEVENTQ , #ifdef CONFIG_IOMMUFD_TEST IOMMUFD_OBJ_SELFTEST, #endif
@@ -93,6 +94,8 @@ struct iommufd_viommu {const struct iommufd_viommu_ops *ops;struct xarray vdevs; +struct list_head veventqs; +struct rw_semaphore veventqs_rwsem;unsigned int type; };
include/uapi/linux/iommufd.h +31 -0
@@ -55,6 +55,7 @@ enum {IOMMUFD_CMD_VIOMMU_ALLOC =0x90 ,IOMMUFD_CMD_VDEVICE_ALLOC =0x91 ,IOMMUFD_CMD_IOAS_CHANGE_PROCESS =0x92 , + IOMMUFD_CMD_VEVENTQ_ALLOC = 0x93, };/**
@@ -1012,4 +1013,34 @@ struct iommu_ioas_change_process {#define IOMMU_IOAS_CHANGE_PROCESS \ _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_CHANGE_PROCESS) +/** +* enum iommu_veventq_type - Virtual Event Queue Type +* @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +*/ +enum iommu_veventq_type { +IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +}; + +/** +* struct iommu_veventq_alloc - ioctl(IOMMU_VEVENTQ_ALLOC) +* @size: sizeof(struct iommu_veventq_alloc) +* @flags: Must be 0 +* @viommu: virtual IOMMU ID to associate the vEVENTQ with +* @type: Type of the vEVENTQ. Must be defined in enum iommu_veventq_type +* @out_veventq_id: The ID of the new vEVENTQ +* @out_veventq_fd: The fd of the new vEVENTQ. User space must close the +* successfully returned fd after using it +* +* Explicitly allocate a virtual event queue interface for a vIOMMU. A vIOMMU +* can have multiple FDs for different types, but is confined to one per @type. +*/ +struct iommu_veventq_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 out_veventq_id; +__u32 out_veventq_fd; +}; +#define IOMMU_VEVENTQ_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VEVENTQ_ALLOC)#endif
drivers/iommu/iommufd/eventq.c +129 -0
138 lines not on this page · raw message
drivers/iommu/iommufd/main.c +7 -0
@@ -310,6 +310,7 @@ union ucmd_buffer {struct iommu_vdevice_alloc vdev;struct iommu_vfio_ioas vfio_ioas;struct iommu_viommu_alloc viommu; +struct iommu_veventq_alloc veventq;#ifdef CONFIG_IOMMUFD_TEST struct iommu_test_cmd test;#endif
@@ -367,6 +368,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_VEVENTQ_ALLOC ,iommufd_veventq_alloc , +struct iommu_veventq_alloc ,out_veventq_fd ), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif
@@ -502,6 +505,10 @@ static const struct iommufd_object_ops iommufd_object_ops[] = { [IOMMUFD_OBJ_FAULT] = { .destroy = iommufd_fault_destroy, }, + [IOMMUFD_OBJ_VEVENTQ] = { + .destroy = iommufd_veventq_destroy, + .abort = iommufd_veventq_abort, + }, [IOMMUFD_OBJ_VIOMMU] = { .destroy = iommufd_viommu_destroy, },
drivers/iommu/iommufd/viommu.c +2 -0
@@ -59,6 +59,8 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd) viommu->ictx = ucmd->ictx; viommu->hwpt = hwpt_paging;refcount_inc (&viommu->hwpt->common.obj.users); +INIT_LIST_HEAD (&viommu->veventqs); +init_rwsem (&viommu->veventqs_rwsem);/* * It is the most likely case that a physical IOMMU is unpluggable. A * pluggable IOMMU instance (if exists) is responsible for refcounting
Signature · 1 line
2.43.0
Re: [PATCH v4 06/14] iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC
Quoted 9 lines · Nicolin Chen
Introduce a new
IOMMUFD_OBJ_VEVENTQobject for vIOMMU Event Queue that provides user space (VMM) another FD to read the vIOMMU Events.Allow a vIOMMU object to allocate vEVENTQs, with a condition that each vIOMMU can only have one single vEVENTQ per type.
Add
iommufd_veventq_alloc()withiommufd_veventq_opsfor the new ioctl.Signed-off-by Nicolin Chen<[email protected]>
Quoted 8 lines
--- drivers/iommu/iommufd/iommufd_private.h | 58 +++++++++++ include/linux/iommufd.h | 3 + include/uapi/linux/iommufd.h | 31 ++++++ drivers/iommu/iommufd/eventq.c | 129 ++++++++++++++++++++++++ drivers/iommu/iommufd/main.c | 7 ++ drivers/iommu/iommufd/viommu.c | 2 + 6 files changed, 230 insertions(+)
PATCH v4 7/14 iommufd/viommu: Add iommufd_viommu_get_vdev_id helper
In reply to Nicolin ChenThis is a reverse search v.s. iommufd_viommu_find_dev, as drivers may want to convert a struct device pointer (physical) to its virtual device ID for an event injection to the user space VM.
Again, this avoids exposing more core structures to the drivers, than the iommufd_viommu alone.
--- include/linux/iommufd.h | 8 ++++++++ drivers/iommu/iommufd/driver.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+)
include/linux/iommufd.h +8 -0
@@ -190,6 +190,8 @@ struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, enum iommufd_object_type type);struct device *iommufd_viommu_find_dev (struct iommufd_viommu *viommu,unsigned long vdev_id); +unsigned long iommufd_viommu_get_vdev_id (struct iommufd_viommu *viommu, +struct device *dev);#else /* !CONFIG_IOMMUFD_DRIVER_CORE */ static inline struct iommufd_object * _iommufd_object_alloc(struct iommufd_ctx *ictx, size_t size,
@@ -203,6 +205,12 @@ iommufd_viommu_find_dev(struct iommufd_viommu *viommu, unsigned long vdev_id) {return NULL ; } + +static inline unsigned long +iommufd_viommu_get_vdev_id (struct iommufd_viommu *viommu,struct device *dev) +{ +return 0 ; +}#endif /* CONFIG_IOMMUFD_DRIVER_CORE */ /*
drivers/iommu/iommufd/driver.c +20 -0
@@ -49,5 +49,25 @@ struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu, }EXPORT_SYMBOL_NS_GPL (iommufd_viommu_find_dev,"IOMMUFD" ); +/* Return 0 if device is not associated to the vIOMMU */ +unsigned long iommufd_viommu_get_vdev_id (struct iommufd_viommu *viommu, +struct device *dev) +{ +struct iommufd_vdevice *vdev; +unsigned long vdev_id =0 ; +unsigned long index; + +xa_lock (&viommu->vdevs); +xa_for_each (&viommu->vdevs, index, vdev) { +if (vdev && vdev->dev == dev) { + vdev_id = (unsigned long )vdev->id; +break ; + } + } +xa_unlock (&viommu->vdevs); +return vdev_id; +} +EXPORT_SYMBOL_NS_GPL (iommufd_viommu_get_vdev_id,"IOMMUFD" ); +MODULE_DESCRIPTION ("iommufd code shared with builtin modules" );MODULE_LICENSE ("GPL" );
Signature · 1 line
2.43.0
Re: [PATCH v4 07/14] iommufd/viommu: Add iommufd_viommu_get_vdev_id helper
Quoted 4 lines · Nicolin Chen
This is a reverse search v.s.
iommufd_viommu_find_dev, as drivers may want to convert a struct device pointer (physical) to its virtual device ID for an event injection to the user space VM.
Quoted 8 lines
Again, this avoids exposing more core structures to the drivers, than the
iommufd_viommualone.Signed-off-by Nicolin Chen<[email protected]>--- include/linux/iommufd.h | 8 ++++++++ drivers/iommu/iommufd/driver.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+)
PATCH v4 8/14 iommufd/viommu: Add iommufd_viommu_report_event helper
In reply to Nicolin ChenSimilar to iommu_report_device_fault, this allows IOMMU drivers to report vIOMMU events from threaded IRQ handlers to user space hypervisors.
--- include/linux/iommufd.h | 11 ++++++++++ drivers/iommu/iommufd/driver.c | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+)
include/linux/iommufd.h +11 -0
@@ -11,6 +11,7 @@#include <linux/refcount.h> #include <linux/types.h> #include <linux/xarray.h> +#include <uapi/linux/iommufd.h> struct device ;struct file ;
@@ -192,6 +193,9 @@ struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu, unsigned long vdev_id);unsigned long iommufd_viommu_get_vdev_id (struct iommufd_viommu *viommu,struct device *dev); +int iommufd_viommu_report_event (struct iommufd_viommu *viommu, +enum iommu_veventq_type type,void *event_data, +size_t data_len);#else /* !CONFIG_IOMMUFD_DRIVER_CORE */ static inline struct iommufd_object * _iommufd_object_alloc(struct iommufd_ctx *ictx, size_t size,
@@ -211,6 +215,13 @@ iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, struct device *dev) {return 0 ; } + +static inline int iommufd_viommu_report_event (struct iommufd_viommu *viommu, +enum iommu_veventq_type type, +void *event_data,size_t data_len) +{ +return -EOPNOTSUPP ; +}#endif /* CONFIG_IOMMUFD_DRIVER_CORE */ /*
drivers/iommu/iommufd/driver.c +40 -0
@@ -69,5 +69,45 @@ unsigned long iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, }EXPORT_SYMBOL_NS_GPL (iommufd_viommu_get_vdev_id,"IOMMUFD" ); +/* +* Typically called in driver's threaded IRQ handler. +* The @type and @event_data must be defined in include/uapi/linux/iommufd.h +*/ +int iommufd_viommu_report_event (struct iommufd_viommu *viommu, +enum iommu_veventq_type type,void *event_data, +size_t data_len) +{ +struct iommufd_veventq *veventq; +struct iommufd_vevent *vevent; +int rc =0 ; + +if (!viommu) +return -ENODEV ; +if (WARN_ON_ONCE (!data_len || !event_data)) +return -EINVAL ; + +down_read (&viommu->veventqs_rwsem); + + veventq =iommufd_viommu_find_veventq (viommu, type); +if (!veventq) { + rc = -EOPNOTSUPP ; + goto out_unlock_veventqs; + } + + vevent =kmalloc (struct_size (vevent, event_data, data_len),GFP_KERNEL ); +if (!vevent) { + rc = -ENOMEM ; + goto out_unlock_veventqs; + } +memcpy (vevent->event_data, event_data, data_len); + vevent->data_len = data_len; + +iommufd_vevent_handler (veventq, vevent); +out_unlock_veventqs: +up_read (&viommu->veventqs_rwsem); +return rc; +} +EXPORT_SYMBOL_NS_GPL (iommufd_viommu_report_event,"IOMMUFD" ); +MODULE_DESCRIPTION ("iommufd code shared with builtin modules" );MODULE_LICENSE ("GPL" );
Signature · 1 line
2.43.0
Re: [PATCH v4 08/14] iommufd/viommu: Add iommufd_viommu_report_event helper
Quoted 8 lines · Nicolin Chen
Similar to
iommu_report_device_fault, this allows IOMMU drivers to report vIOMMU events from threaded IRQ handlers to user space hypervisors.Signed-off-by Nicolin Chen<[email protected]>--- include/linux/iommufd.h | 11 ++++++++++ drivers/iommu/iommufd/driver.c | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+)
PATCH v4 9/14 iommufd/selftest: Require vdev_id when attaching to a nested domain
In reply to Nicolin ChenWhen attaching a device to a vIOMMU-based nested domain, vdev_id must be present. Add a piece of code hard-requesting it, preparing for a vEVENTQ support in the following patch. Then, update the TEST_F.
A HWPT-based nested domain will return a NULL new_viommu, thus no such a vDEVICE requirement.
--- drivers/iommu/iommufd/selftest.c | 23 +++++++++++++++++++++++ tools/testing/selftests/iommu/iommufd.c | 5 +++++ 2 files changed, 28 insertions(+)
drivers/iommu/iommufd/selftest.c +23 -0
@@ -161,7 +161,10 @@ enum selftest_obj_type {struct mock_dev {struct device dev; +struct mock_viommu *viommu; +struct rw_semaphore viommu_rwsem;unsigned long flags; +unsigned long vdev_id;int id;u32 cache[MOCK_DEV_CACHE_NUM ]; };
@@ -193,10 +196,29 @@ static int mock_domain_nop_attach(struct iommu_domain *domain, struct device *dev) {struct mock_dev *mdev =to_mock_dev (dev); +struct mock_viommu *new_viommu =NULL ; +unsigned long vdev_id =0 ;if (domain->dirty_ops && (mdev->flags &MOCK_FLAGS_DEVICE_NO_DIRTY ))return -EINVAL ; +iommu_group_mutex_assert (dev); +if (domain->type ==IOMMU_DOMAIN_NESTED ) { + new_viommu =to_mock_nested (domain)->mock_viommu; +if (new_viommu) { + vdev_id =iommufd_viommu_get_vdev_id (&new_viommu->core, + dev); +if (!vdev_id) +return -ENOENT ; + } + } +if (new_viommu != mdev->viommu) { +down_write (&mdev->viommu_rwsem); + mdev->viommu = new_viommu; + mdev->vdev_id = vdev_id; +up_write (&mdev->viommu_rwsem); + } +return 0 ; }
@@ -861,6 +883,7 @@ static struct mock_dev *mock_dev_create(unsigned long dev_flags)if (!mdev)return ERR_PTR (-ENOMEM ); +init_rwsem (&mdev->viommu_rwsem);device_initialize (&mdev->dev); mdev->flags = dev_flags; mdev->dev.release = mock_dev_release;
tools/testing/selftests/iommu/iommufd.c +5 -0
@@ -2736,6 +2736,7 @@ TEST_F(iommufd_viommu, viommu_alloc_nested_iopf)uint32_t iopf_hwpt_id;uint32_t fault_id;uint32_t fault_fd; +uint32_t vdev_id;if (self->device_id) {test_ioctl_fault_alloc (&fault_id, &fault_fd);
@@ -2752,6 +2753,10 @@ TEST_F(iommufd_viommu, viommu_alloc_nested_iopf) &iopf_hwpt_id,IOMMU_HWPT_DATA_SELFTEST , &data, sizeof(data)); +/* Must allocate vdevice before attaching to a nested hwpt */ +test_err_mock_domain_replace (ENOENT , self->stdev_id, + iopf_hwpt_id); +test_cmd_vdevice_alloc (viommu_id, dev_id,0x99 , &vdev_id);test_cmd_mock_domain_replace (self->stdev_id, iopf_hwpt_id);EXPECT_ERRNO (EBUSY ,_test_ioctl_destroy (self->fd, iopf_hwpt_id));
Signature · 1 line
2.43.0
PATCH v4 10/14 iommufd/selftest: Add IOMMU_TEST_OP_TRIGGER_VEVENT for vEVENTQ coverage
In reply to Nicolin ChenThe handler will get vDEVICE object from the given mdev and convert it to its per-vIOMMU virtual ID to mimic a real IOMMU driver.
--- drivers/iommu/iommufd/iommufd_test.h | 10 ++++++++++ drivers/iommu/iommufd/selftest.c | 30 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+)
drivers/iommu/iommufd/iommufd_test.h +10 -0
@@ -24,6 +24,7 @@ enum {IOMMU_TEST_OP_MD_CHECK_IOTLB ,IOMMU_TEST_OP_TRIGGER_IOPF ,IOMMU_TEST_OP_DEV_CHECK_CACHE , + IOMMU_TEST_OP_TRIGGER_VEVENT, }; enum {
@@ -145,6 +146,9 @@ struct iommu_test_cmd {__u32 id;__u32 cache; } check_dev_cache; +struct { +__u32 dev_id; + } trigger_vevent; };__u32 last; };
@@ -212,4 +216,10 @@ struct iommu_viommu_invalidate_selftest { __u32 cache_id; }; +#define IOMMU_VEVENTQ_TYPE_SELFTEST 0xbeefbeef + +struct iommu_viommu_event_selftest { +__u32 virt_id; +}; +#endif
drivers/iommu/iommufd/selftest.c +30 -0
@@ -1631,6 +1631,34 @@ static int iommufd_test_trigger_iopf(struct iommufd_ucmd *ucmd,return 0 ; } +static int iommufd_test_trigger_vevent (struct iommufd_ucmd *ucmd, +struct iommu_test_cmd *cmd) +{ +struct iommu_viommu_event_selftest test = {}; +struct iommufd_device *idev; +struct mock_dev *mdev; +int rc = -ENOENT ; + + idev =iommufd_get_device (ucmd, cmd->trigger_vevent.dev_id); +if (IS_ERR (idev)) +return PTR_ERR (idev); + mdev =to_mock_dev (idev->dev); + +down_read (&mdev->viommu_rwsem); +if (!mdev->viommu || !mdev->vdev_id) + goto out_unlock; + + test.virt_id = mdev->vdev_id; + rc =iommufd_viommu_report_event (&mdev->viommu->core, +IOMMU_VEVENTQ_TYPE_SELFTEST , &test, +sizeof (test)); +out_unlock: +up_read (&mdev->viommu_rwsem); +iommufd_put_object (ucmd->ictx, &idev->obj); + +return rc; +} +void iommufd_selftest_destroy (struct iommufd_object *obj) {struct selftest_obj *sobj =to_selftest_obj (obj);
@@ -1712,6 +1740,8 @@ int iommufd_test(struct iommufd_ucmd *ucmd) cmd->dirty.flags);case IOMMU_TEST_OP_TRIGGER_IOPF :return iommufd_test_trigger_iopf (ucmd, cmd); +case IOMMU_TEST_OP_TRIGGER_VEVENT : +return iommufd_test_trigger_vevent (ucmd, cmd);default :return -EOPNOTSUPP ; }
Signature · 1 line
2.43.0
PATCH v4 11/14 iommufd/selftest: Add IOMMU_VEVENTQ_ALLOC test coverage
In reply to Nicolin ChenTrigger a vEVENT by feeding an idev ID and validating the returned output virt_id whether it equals to the value that was set to the vDEVICE.
--- tools/testing/selftests/iommu/iommufd_utils.h | 65 +++++++++++++++++++ tools/testing/selftests/iommu/iommufd.c | 22 +++++++ .../selftests/iommu/iommufd_fail_nth.c | 7 ++ 3 files changed, 94 insertions(+)
tools/testing/selftests/iommu/iommufd_utils.h +65 -0
@@ -9,6 +9,7 @@#include <sys/ioctl.h> #include <stdint.h> #include <assert.h> +#include <poll.h> #include "../kselftest_harness.h" #include "../../../../drivers/iommu/iommufd/iommufd_test.h"
@@ -936,3 +937,67 @@ static int _test_cmd_vdevice_alloc(int fd, __u32 viommu_id, __u32 idev_id,EXPECT_ERRNO (_errno, \_test_cmd_vdevice_alloc (self->fd, viommu_id, idev_id, \ virt_id, vdev_id)) + +static int _test_cmd_veventq_alloc (int fd,__u32 viommu_id,__u32 type, +__u32 *veventq_id,__u32 *veventq_fd) +{ +struct iommu_veventq_alloc cmd = { + .size =sizeof (cmd), + .type = type, + .viommu_id = viommu_id, + }; +int ret; + + ret =ioctl (fd,IOMMU_VEVENTQ_ALLOC , &cmd); +if (ret) +return ret; +if (veventq_id) + *veventq_id = cmd.out_veventq_id; +if (veventq_fd) + *veventq_fd = cmd.out_veventq_fd; +return 0 ; +} + +#define test_cmd_veventq_alloc (viommu_id, type, veventq_id, veventq_fd) \ + ASSERT_EQ(0, _test_cmd_veventq_alloc(self->fd, viommu_id, type, \ + veventq_id, veventq_fd)) +#define test_err_veventq_alloc (_errno, viommu_id, type, veventq_id, \ + veventq_fd) \ + EXPECT_ERRNO(_errno, \ + _test_cmd_veventq_alloc(self->fd, viommu_id, type, \ + veventq_id, veventq_fd)) + +static int _test_cmd_trigger_vevent (int fd,__u32 dev_id,__u32 event_fd, +__u32 virt_id) +{ +struct iommu_test_cmd trigger_vevent_cmd = { + .size =sizeof (trigger_vevent_cmd), + .op =IOMMU_TEST_OP_TRIGGER_VEVENT , + .trigger_vevent = { + .dev_id = dev_id, + }, + }; +struct pollfd pollfd = { .fd = event_fd, .events =POLLIN }; +struct iommu_viommu_event_selftest event; +ssize_t bytes; +int ret; + + ret =ioctl (fd,_IOMMU_TEST_CMD (IOMMU_TEST_OP_TRIGGER_VEVENT ), + &trigger_vevent_cmd); +if (ret) +return ret; + + ret =poll (&pollfd,1 ,1000 ); +if (ret <0 ) +return ret; + + bytes =read (event_fd, &event,sizeof (event)); +if (bytes <=0 ) +return -EIO ; + +return event.virt_id == virt_id ?0 : -EINVAL ; +} + +#define test_cmd_trigger_vevent (dev_id, event_fd, virt_id) \ + ASSERT_EQ(0, _test_cmd_trigger_vevent(self->fd, dev_id, event_fd, \ + virt_id))
tools/testing/selftests/iommu/iommufd.c +22 -0
@@ -2774,15 +2774,37 @@ TEST_F(iommufd_viommu, vdevice_alloc)uint32_t viommu_id = self->viommu_id;uint32_t dev_id = self->device_id;uint32_t vdev_id =0 ; +uint32_t veventq_id; +uint32_t veventq_fd;if (dev_id) { +/* Must allocate vdevice before attaching to a nested hwpt */ +test_err_mock_domain_replace (ENOENT , self->stdev_id, + self->nested_hwpt_id); + +test_cmd_veventq_alloc (viommu_id,IOMMU_VEVENTQ_TYPE_SELFTEST , + &veventq_id, &veventq_fd); +test_err_veventq_alloc (EEXIST , viommu_id, +IOMMU_VEVENTQ_TYPE_SELFTEST ,NULL ,NULL );/* Set vdev_id to 0x99, unset it, and set to 0x88 */ test_cmd_vdevice_alloc (viommu_id, dev_id,0x99 , &vdev_id); +test_cmd_mock_domain_replace (self->stdev_id, + self->nested_hwpt_id); +test_cmd_trigger_vevent (dev_id, veventq_fd,0x99 );test_err_vdevice_alloc (EEXIST , viommu_id, dev_id,0x99 , &vdev_id); +test_cmd_mock_domain_replace (self->stdev_id, self->ioas_id);test_ioctl_destroy (vdev_id); + +/* Try again with 0x88 */ test_cmd_vdevice_alloc (viommu_id, dev_id,0x88 , &vdev_id); +test_cmd_mock_domain_replace (self->stdev_id, + self->nested_hwpt_id); +test_cmd_trigger_vevent (dev_id, veventq_fd,0x88 ); +close (veventq_fd); +test_cmd_mock_domain_replace (self->stdev_id, self->ioas_id);test_ioctl_destroy (vdev_id); +test_ioctl_destroy (veventq_id); }else {test_err_vdevice_alloc (ENOENT , viommu_id, dev_id,0x99 ,NULL ); }
tools/testing/selftests/iommu/iommufd_fail_nth.c +7 -0
@@ -620,6 +620,7 @@ TEST_FAIL_NTH(basic_fail_nth, device) };struct iommu_test_hw_info info;uint32_t fault_id, fault_fd; +uint32_t veventq_id, veventq_fd;uint32_t fault_hwpt_id;uint32_t ioas_id;uint32_t ioas_id2;
@@ -692,6 +693,12 @@ TEST_FAIL_NTH(basic_fail_nth, device) IOMMU_HWPT_DATA_SELFTEST, &data, sizeof(data)))return -1 ; +if (_test_cmd_veventq_alloc (self->fd, viommu_id, +IOMMU_VEVENTQ_TYPE_SELFTEST , &veventq_id, + &veventq_fd)) +return -1 ; +close (veventq_fd); +return 0 ; }
Signature · 1 line
2.43.0
PATCH v4 12/14 Documentation: userspace-api: iommufd: Update FAULT and VEVENTQ
In reply to Nicolin ChenWith the introduction of the new objects, update the doc to reflect that.
--- Documentation/userspace-api/iommufd.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
Documentation/userspace-api/iommufd.rst +16 -0
@@ -63,6 +63,13 @@ Following IOMMUFD objects are exposed to userspace: space usually has mappings from guest-level I/O virtual addresses to guest- level physical addresses. +- IOMMUFD_FAULT, representing a software queue for an HWPT reporting IO page + faults using the IOMMU HW's PRI (Page Request Interface). This queue object + provides user space an FD to poll the page fault events and also to respond + to those events. A FAULT object must be created first to get a fault_id that + could be then used to allocate a fault-enabled HWPT via the IOMMU_HWPT_ALLOC + command by setting the IOMMU_HWPT_FAULT_ID_VALID bit in its flags field. + - IOMMUFD_OBJ_VIOMMU, representing a slice of the physical IOMMU instance, passed to or shared with a VM. It may be some HW-accelerated virtualization features and some SW resources used by the VM. For examples:
@@ -109,6 +116,13 @@ Following IOMMUFD objects are exposed to userspace: vIOMMU, which is a separate ioctl call from attaching the same device to an HWPT_PAGING that the vIOMMU holds. +- IOMMUFD_OBJ_VEVENTQ, representing a software queue for a vIOMMU to report its + events such as translation faults occurred to a nested stage-1 and HW-specific + events. This queue object provides user space an FD to poll the vIOMMU events. + A vIOMMU object must be created first to get its viommu_id that could be then + used to allocate a vEVENTQ. Each vIOMMU can support multiple types of vEVENTS, + but is confined to one vEVENTQ per vEVENTQ type. + All user-visible objects are destroyed via the IOMMU_DESTROY uAPI. The diagrams below show relationships between user-visible objects and kernel
@@ -251,8 +265,10 @@ User visible objects are backed by following datastructures: - iommufd_device for IOMMUFD_OBJ_DEVICE. - iommufd_hwpt_paging for IOMMUFD_OBJ_HWPT_PAGING. - iommufd_hwpt_nested for IOMMUFD_OBJ_HWPT_NESTED. +- iommufd_fault for IOMMUFD_OBJ_FAULT. - iommufd_viommu for IOMMUFD_OBJ_VIOMMU. - iommufd_vdevice for IOMMUFD_OBJ_VDEVICE. +- iommufd_veventq for IOMMUFD_OBJ_VEVENTQ. Several terminologies when looking at these datastructures:
Signature · 1 line
2.43.0
Re: [PATCH v4 12/14] Documentation: userspace-api: iommufd: Update FAULT and VEVENTQ
Quoted 6 lines · Nicolin Chen
With the introduction of the new objects, update the doc to reflect that.
Signed-off-by Nicolin Chen<[email protected]>--- Documentation/userspace-api/iommufd.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
PATCH v4 13/14 iommu/arm-smmu-v3: Introduce struct arm_smmu_vmaster
In reply to Nicolin ChenUse it to store all vSMMU-related data. The vsid (Virtual Stream ID) will be the first use case. Then, add a rw_semaphore to protect it.
Also add a pair of arm_smmu_attach_prepare/commit_vmaster helpers to set or unset the master->vmaster point. Put these helpers inside the existing arm_smmu_attach_prepare/commit(). Note that identity and blocked ops don't call arm_smmu_attach_prepare/commit(), thus simply call the new helpers at the top, so a device attaching to an identity/blocked domain can unset the master->vmaster when the device is moving away from a nested domain.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 23 +++++++++ .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 49 +++++++++++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 32 +++++++++++- 3 files changed, 103 insertions(+), 1 deletion(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +23 -0
@@ -799,6 +799,11 @@ struct arm_smmu_stream {struct rb_node node; }; +struct arm_smmu_vmaster { +struct arm_vsmmu *vsmmu; +unsigned long vsid; +}; +struct arm_smmu_event {u8 stall :1 , ssv : 1,
@@ -824,6 +829,8 @@ struct arm_smmu_master {struct arm_smmu_device *smmu;struct device *dev;struct arm_smmu_stream *streams; +struct arm_smmu_vmaster *vmaster; +struct rw_semaphore vmaster_rwsem;/* Locked by the iommu core using the group mutex */ struct arm_smmu_ctx_desc_cfg cd_table;unsigned int num_streams;
@@ -972,6 +979,7 @@ struct arm_smmu_attach_state {bool disable_ats;ioasid_t ssid;/* Resulting state */ +struct arm_smmu_vmaster *vmaster;bool ats_enabled; };
@@ -1055,9 +1063,24 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,struct iommu_domain *parent, struct iommufd_ctx *ictx, unsigned int viommu_type); +int arm_smmu_attach_prepare_vmaster (struct arm_smmu_attach_state *state, +struct iommu_domain *domain); +void arm_smmu_attach_commit_vmaster (struct arm_smmu_attach_state *state);#else #define arm_smmu_hw_info NULL#define arm_vsmmu_alloc NULL + +static inline int +arm_smmu_attach_prepare_vmaster (struct arm_smmu_attach_state *state, +struct iommu_domain *domain) +{ +return 0 ;/* NOP */ +} + +static inline void +arm_smmu_attach_commit_vmaster (struct arm_smmu_attach_state *state) +{ +}#endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ #endif /* _ARM_SMMU_V3_H */
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +49 -0
55 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +31 -1
@@ -2802,6 +2802,7 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,struct arm_smmu_domain *smmu_domain =to_smmu_domain_devices (new_domain);unsigned long flags; +int ret;/* * arm_smmu_share_asid() must not see two domains pointing to the same
@@ -2831,9 +2832,15 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, }if (smmu_domain) { + ret =arm_smmu_attach_prepare_vmaster (state, new_domain); +if (ret) +return ret; + master_domain =kzalloc (sizeof (*master_domain),GFP_KERNEL ); -if (!master_domain) +if (!master_domain) { +kfree (state->vmaster);return -ENOMEM ; + } master_domain->master = master; master_domain->ssid = state->ssid;if (new_domain->type ==IOMMU_DOMAIN_NESTED )
@@ -2860,6 +2867,7 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,spin_unlock_irqrestore (&smmu_domain->devices_lock, flags);kfree (master_domain); +kfree (state->vmaster);return -EINVAL ; }
@@ -2892,6 +2900,8 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)lockdep_assert_held (&arm_smmu_asid_lock); +arm_smmu_attach_commit_vmaster (state); +if (state->ats_enabled && !master->ats_enabled) {arm_smmu_enable_ats (master); }else if (state->ats_enabled && master->ats_enabled) {
@@ -3158,8 +3168,17 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,static int arm_smmu_attach_dev_identity (struct iommu_domain *domain,struct device *dev) { +int ret;struct arm_smmu_ste ste;struct arm_smmu_master *master =dev_iommu_priv_get (dev); +struct arm_smmu_attach_state state = { + .master = master, + }; + + ret =arm_smmu_attach_prepare_vmaster (&state, domain); +if (ret) +return ret; +arm_smmu_attach_commit_vmaster (&state);arm_smmu_make_bypass_ste (master->smmu, &ste);arm_smmu_attach_dev_ste (domain, dev, &ste,STRTAB_STE_1_S1DSS_BYPASS );
@@ -3178,7 +3197,17 @@ static struct iommu_domain arm_smmu_identity_domain = {static int arm_smmu_attach_dev_blocked (struct iommu_domain *domain,struct device *dev) { +int ret;struct arm_smmu_ste ste; +struct arm_smmu_master *master =dev_iommu_priv_get (dev); +struct arm_smmu_attach_state state = { + .master = master, + }; + + ret =arm_smmu_attach_prepare_vmaster (&state, domain); +if (ret) +return ret; +arm_smmu_attach_commit_vmaster (&state);arm_smmu_make_abort_ste (&ste); arm_smmu_attach_dev_ste(domain, dev, &ste,
@@ -3428,6 +3457,7 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) master->dev = dev; master->smmu = smmu; +init_rwsem (&master->vmaster_rwsem);dev_iommu_priv_set (dev, master); ret =arm_smmu_insert_master (smmu, master);
Signature · 1 line
2.43.0
PATCH v4 14/14 iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
In reply to Nicolin ChenAside from the IOPF framework, iommufd provides an additional pathway to report hardware events, via the vEVENTQ of vIOMMU infrastructure.
Define an iommu_vevent_arm_smmuv3 uAPI structure, and report stage-1 events in the threaded IRQ handler.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 7 +++ include/uapi/linux/iommufd.h | 15 +++++ .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 16 +++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 58 +++++++++++-------- 4 files changed, 71 insertions(+), 25 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +7 -0
@@ -1066,6 +1066,7 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,int arm_smmu_attach_prepare_vmaster (struct arm_smmu_attach_state *state,struct iommu_domain *domain);void arm_smmu_attach_commit_vmaster (struct arm_smmu_attach_state *state); +int arm_vmaster_report_event (struct arm_smmu_vmaster *vmaster,u64 *evt);#else #define arm_smmu_hw_info NULL#define arm_vsmmu_alloc NULL
@@ -1081,6 +1082,12 @@ static inline void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state) { } + +static inline int arm_vmaster_report_event (struct arm_smmu_vmaster *vmaster, +u64 *evt) +{ +return -EOPNOTSUPP ; +}#endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ #endif /* _ARM_SMMU_V3_H */
include/uapi/linux/iommufd.h +15 -0
@@ -1016,9 +1016,24 @@ struct iommu_ioas_change_process {/** * enum iommu_veventq_type - Virtual Event Queue Type * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue */ enum iommu_veventq_type {IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event +* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; };/**
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +16 -0
@@ -447,4 +447,20 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,return &vsmmu->core; } +int arm_vmaster_report_event (struct arm_smmu_vmaster *vmaster,u64 *evt) +{ +struct iommu_vevent_arm_smmuv3 vevt = + *(struct iommu_vevent_arm_smmuv3 *)evt; + + vevt.evt[0 ] &= ~EVTQ_0_SID ; + vevt.evt[0 ] |=FIELD_PREP (EVTQ_0_SID , vmaster->vsid); + + vevt.evt[0 ] =cpu_to_le64 (vevt.evt[0 ]); + vevt.evt[1 ] =cpu_to_le64 (vevt.evt[1 ]); + +return iommufd_viommu_report_event (&vmaster->vsmmu->core, +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 , &vevt, +sizeof (vevt)); +} +MODULE_IMPORT_NS ("IOMMUFD" );
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +33 -25
86 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
Quoted 17 lines · Nicolin Chen
include/uapi/linux/iommufd.h +6
-0@@ -1016,9 +1016,24 @@ struct iommu_ioas_change_process {/** * enum iommu_veventq_type - Virtual Event Queue Type * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue */ enum iommu_veventq_type {IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event
include/uapi/linux/iommufd.h struct iommu_ioas_change_process { · line 1037
Quoted 10 lines
include/uapi/linux/iommufd.h +9
-0+* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; };
Nit: I think it would be more readable to add a check in the vevent reporting helper.
drivers/iommu/iommufd/driver.c +3 -0
@@ -86,6 +86,9 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu,if (WARN_ON_ONCE (!data_len || !event_data))return -EINVAL ; +if (WARN_ON_ONCE (type !=IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 )) +return -EINVAL ; +down_read (&viommu->veventqs_rwsem); veventq =iommufd_viommu_find_veventq (viommu, type);
Or perhaps the compiler could automatically make a warning if the @type is not one of those values in enum iommu_veventq_type?
Others look good to me.
Thanks,
baolu
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
Quoted 37 lines · Baolu Lu
Quoted 17 lines · Nicolin Chen
include/uapi/linux/iommufd.h +6
-0@@ -1016,9 +1016,24 @@ struct iommu_ioas_change_process {/** * enum iommu_veventq_type - Virtual Event Queue Type * @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue */ enum iommu_veventq_type {IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event include/uapi/linux/iommufd.h struct iommu_ioas_change_process { · line 1037
Quoted 10 lines
include/uapi/linux/iommufd.h +9
-0+* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; };Nit: I think it would be more readable to add a check in the vevent reporting helper.
drivers/iommu/iommufd/driver.c +0
-0
drivers/iommu/iommufd/driver.c int iommufd_viommu_report_event(struct iommufd_viommu · line 92
Quoted 7 lines
drivers/iommu/iommufd/driver.c +3
-0@@ -86,6 +86,9 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu, if (WARN_ON_ONCE(!data_len || !event_data)) return -EINVAL; +if (WARN_ON_ONCE (type !=IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 )) +return -EINVAL ; +
Hmm, that's a good point I think.
Quoted 3 lines
drivers/iommu/iommufd/driver.c +0
-0down_read (&viommu->veventqs_rwsem);veventq = iommufd_viommu_find_veventq(viommu, type);
^ |
We actually have been missing a type validation entirely, so the type could have been rejected by this function. Perhaps we should add a static list of supported types to struct iommufd_viommu_ops for drivers to report so that then the core could reject from the first place during a vEVENTQ allocation.
Quoted 2 lines
Or perhaps the compiler could automatically make a warning if the @type is not one of those values in enum
iommu_veventq_type?
Just gave that a try. Mine doesn't give any warning. Not sure if needs to be some "-W" augment though..
Quoted 1 line
Others look good to me.
Thanks for the review!
Nicolin
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
Quoted 21 lines · Nicolin Chen
Quoted 8 lines · Baolu Lu
Nit: I think it would be more readable to add a check in the vevent reporting helper.
drivers/iommu/iommufd/driver.c +0
-0drivers/iommu/iommufd/driver.c int iommufd_viommu_report_event(struct iommufd_viommu · line 92
Quoted 7 lines
drivers/iommu/iommufd/driver.c +3
-0@@ -86,6 +86,9 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu, if (WARN_ON_ONCE(!data_len || !event_data)) return -EINVAL; +if (WARN_ON_ONCE (type !=IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 )) +return -EINVAL ; +Hmm, that's a good point I think.
Quoted 2 lines
drivers/iommu/iommufd/driver.c +0
-0down_read (&viommu->veventqs_rwsem);
Quoted 8 lines
Quoted 1 line
veventq = iommufd_viommu_find_veventq(viommu, type);^ |We actually have been missing a type validation entirely, so the type could have been rejected by this function. Perhaps we should add a static list of supported types to struct
iommufd_viommu_opsfor drivers to report so that then the core could reject from the first place during a vEVENTQ allocation.
I added something like this. Will send a v5.
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +6 -0
@@ -399,9 +399,15 @@ static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,return ret; } +static bool arm_vsmmu_supports_veventq (unsigned int type) +{ +return type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ; +} +static const struct iommufd_viommu_ops arm_vsmmu_ops = { .alloc_domain_nested = arm_vsmmu_alloc_domain_nested, .cache_invalidate = arm_vsmmu_cache_invalidate, + .supports_veventq = arm_vsmmu_supports_veventq, }; struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
drivers/iommu/iommufd/eventq.c +5 -0
@@ -555,6 +555,11 @@ int iommufd_veventq_alloc(struct iommufd_ucmd *ucmd) viommu =iommufd_get_viommu (ucmd, cmd->viommu_id);if (IS_ERR (viommu))return PTR_ERR (viommu); + +if (!viommu->ops || !viommu->ops->supports_veventq || + !viommu->ops->supports_veventq (cmd->type)) +return -EOPNOTSUPP ; +down_write (&viommu->veventqs_rwsem);if (iommufd_viommu_find_veventq (viommu, cmd->type)) {
include/linux/iommufd.h +2 -0
@@ -117,6 +117,7 @@ struct iommufd_viommu {* array->entry_num to report the number of handled requests. * The data structure of the array entry must be defined in * include/uapi/linux/iommufd.h +* @supports_veventq: Whether the vIOMMU supports a given vEVENTQ type */ struct iommufd_viommu_ops {void (*destroy)(struct iommufd_viommu *viommu);
@@ -125,6 +126,7 @@ struct iommufd_viommu_ops { const struct iommu_user_data *user_data);int (*cache_invalidate)(struct iommufd_viommu *viommu,struct iommu_user_data_array *array); +bool (*supports_veventq)(unsigned int type); };#if IS_ENABLED (CONFIG_IOMMUFD )
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, · line 404
Quoted 13 lines · Nicolin Chen
I added something like this. Will send a v5.
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -399,9 +399,15 @@ static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,return ret; } +static bool arm_vsmmu_supports_veventq (unsigned int type) +{ +return type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ;
Oops. Corrected this: IOMMU_VEVENTQ_TYPE_ARM_SMMUV3
And added your bits too:
@@ -83,6 +83,9 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu,
if (!viommu)
return -ENODEV;
+ if (WARN_ON_ONCE(!viommu->ops || !viommu->ops->supports_veventq ||
+ !viommu->ops->supports_veventq(type)))
+ return -EOPNOTSUPP;
if (WARN_ON_ONCE(!data_len || !event_data))
return -EINVAL;Thanks!
Nicolin
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
In reply to Nicolin ChenQuoted 36 lines · Nicolin Chen
Quoted 20 lines · Nicolin Chen
Quoted 8 lines · Baolu Lu
Nit: I think it would be more readable to add a check in the vevent reporting helper.
drivers/iommu/iommufd/driver.c +0
-0drivers/iommu/iommufd/driver.c int iommufd_viommu_report_event(struct iommufd_viommu · line 92
Quoted 7 lines
drivers/iommu/iommufd/driver.c +3
-0@@ -86,6 +86,9 @@ int iommufd_viommu_report_event(struct iommufd_viommu *viommu, if (WARN_ON_ONCE(!data_len || !event_data)) return -EINVAL; +if (WARN_ON_ONCE (type !=IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 )) +return -EINVAL ; +Hmm, that's a good point I think.
Quoted 2 lines
drivers/iommu/iommufd/driver.c +0
-0down_read (&viommu->veventqs_rwsem);Quoted 8 lines
Quoted 1 line
veventq = iommufd_viommu_find_veventq(viommu, type);^ |We actually have been missing a type validation entirely, so the type could have been rejected by this function. Perhaps we should add a static list of supported types to struct
iommufd_viommu_opsfor drivers to report so that then the core could reject from the first place during a vEVENTQ allocation.I added something like this. Will send a v5.
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +0
-0
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, · line 404
Quoted 6 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -399,9 +399,15 @@ static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,return ret; } +static bool arm_vsmmu_supports_veventq (unsigned int type) +{ +return type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ;
Do you need to check the hardware capabilities before reporting this? I am not familiar with the ARM architecture, but typically it's better to make it like this,
static bool arm_vsmmu_supports_veventq(struct iommufd_viommu *viommu,
enum iommu_veventq_type type)
{
if (type != IOMMU_VEVENTQ_TYPE_ARM_SMMUV3)
return false;
if (hardware_not_capable(viommu))
return false;
return true;
}drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, · line 411
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0+} +static const struct iommufd_viommu_ops arm_vsmmu_ops = { .alloc_domain_nested = arm_vsmmu_alloc_domain_nested, .cache_invalidate = arm_vsmmu_cache_invalidate, + .supports_veventq = arm_vsmmu_supports_veventq, };
Others look good to me.
Thanks,
baolu
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
Quoted 9 lines · Baolu Lu
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, · line 404
Quoted 3 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0+static bool arm_vsmmu_supports_veventq (unsigned int type) +{ +return type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ;Do you need to check the hardware capabilities before reporting this? I am not familiar with the ARM architecture, but typically it's better to make it like this,
Quoted 8 lines
static bool arm_vsmmu_supports_veventq(struct
iommufd_viommu*viommu,
enumiommu_veventq_typetype){ if (type != IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) return false; if (hardware_not_capable(viommu)) return false;
I think the ARM version of viommu_alloc op has already implemented enough capability checks and rejected any of hardware_not_capable. So, viommu shouldn't be a thing that the driver could actually use to call this helper :)
Thanks
Nicolin
Re: [PATCH v4 14/14] iommu/arm-smmu-v3: Report events that belong to devices attached to vIOMMU
Quoted 15 lines · Nicolin Chen
Quoted 14 lines · Baolu Lu
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, · line 404
Quoted 3 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0+static bool arm_vsmmu_supports_veventq (unsigned int type) +{ +return type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ;Do you need to check the hardware capabilities before reporting this? I am not familiar with the ARM architecture, but typically it's better to make it like this,
static bool arm_vsmmu_supports_veventq(struct
iommufd_viommu*viommu,
enumiommu_veventq_typetype){ if (type != IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) return false;
Quoted 6 lines
Quoted 2 lines
if (hardware_not_capable(viommu)) return false;I think the ARM version of
viommu_allocop has already implemented enough capability checks and rejected any ofhardware_not_capable. So, viommu shouldn't be a thing that the driver could actually use to call this helper 🙂
Okay, fair enough.