Skip to content

Commit c93529a

Browse files
committed
Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd
Pull iommufd updates from Jason Gunthorpe: "This broadly brings the assigned HW command queue support to iommufd. This feature is used to improve SVA performance in VMs by avoiding paravirtualization traps during SVA invalidations. Along the way I think some of the core logic is in a much better state to support future driver backed features. Summary: - IOMMU HW now has features to directly assign HW command queues to a guest VM. In this mode the command queue operates on a limited set of invalidation commands that are suitable for improving guest invalidation performance and easy for the HW to virtualize. This brings the generic infrastructure to allow IOMMU drivers to expose such command queues through the iommufd uAPI, mmap the doorbell pages, and get the guest physical range for the command queue ring itself. - An implementation for the NVIDIA SMMUv3 extension "cmdqv" is built on the new iommufd command queue features. It works with the existing SMMU driver support for cmdqv in guest VMs. - Many precursor cleanups and improvements to support the above cleanly, changes to the general ioctl and object helpers, driver support for VDEVICE, and mmap pgoff cookie infrastructure. - Sequence VDEVICE destruction to always happen before VFIO device destruction. When using the above type features, and also in future confidential compute, the internal virtual device representation becomes linked to HW or CC TSM configuration and objects. If a VFIO device is removed from iommufd those HW objects should also be cleaned up to prevent a sort of UAF. This became important now that we have HW backing the VDEVICE. - Fix one syzkaller found error related to math overflows during iova allocation" * tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd: (57 commits) iommu/arm-smmu-v3: Replace vsmmu_size/type with get_viommu_size iommu/arm-smmu-v3: Do not bother impl_ops if IOMMU_VIOMMU_TYPE_ARM_SMMUV3 iommufd: Rename some shortterm-related identifiers iommufd/selftest: Add coverage for vdevice tombstone iommufd/selftest: Explicitly skip tests for inapplicable variant iommufd/vdevice: Remove struct device reference from struct vdevice iommufd: Destroy vdevice on idevice destroy iommufd: Add a pre_destroy() op for objects iommufd: Add iommufd_object_tombstone_user() helper iommufd/viommu: Roll back to use iommufd_object_alloc() for vdevice iommufd/selftest: Test reserved regions near ULONG_MAX iommufd: Prevent ALIGN() overflow iommu/tegra241-cmdqv: import IOMMUFD module namespace iommufd: Do not allow _iommufd_object_alloc_ucmd if abort op is set iommu/tegra241-cmdqv: Add IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV support iommu/tegra241-cmdqv: Add user-space use support iommu/tegra241-cmdqv: Do not statically map LVCMDQs iommu/tegra241-cmdqv: Simplify deinit flow in tegra241_cmdqv_remove_vintf() iommu/tegra241-cmdqv: Use request_threaded_irq iommu/arm-smmu-v3-iommufd: Add hw_info to impl_ops ...
2 parents 7ce4de1 + 2c78e74 commit c93529a

File tree

25 files changed

+2436
-506
lines changed

25 files changed

+2436
-506
lines changed

Documentation/userspace-api/iommufd.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ Following IOMMUFD objects are exposed to userspace:
124124
used to allocate a vEVENTQ. Each vIOMMU can support multiple types of vEVENTS,
125125
but is confined to one vEVENTQ per vEVENTQ type.
126126

127+
- IOMMUFD_OBJ_HW_QUEUE, representing a hardware accelerated queue, as a subset
128+
of IOMMU's virtualization features, for the IOMMU HW to directly read or write
129+
the virtual queue memory owned by a guest OS. This HW-acceleration feature can
130+
allow VM to work with the IOMMU HW directly without a VM Exit, so as to reduce
131+
overhead from the hypercalls. Along with the HW QUEUE object, iommufd provides
132+
user space an mmap interface for VMM to mmap a physical MMIO region from the
133+
host physical address space to the guest physical address space, allowing the
134+
guest OS to directly control the allocated HW QUEUE. Thus, when allocating a
135+
HW QUEUE, the VMM must request a pair of mmap info (offset/length) and pass in
136+
exactly to an mmap syscall via its offset and length arguments.
137+
127138
All user-visible objects are destroyed via the IOMMU_DESTROY uAPI.
128139

129140
The diagrams below show relationships between user-visible objects and kernel
@@ -270,6 +281,7 @@ User visible objects are backed by following datastructures:
270281
- iommufd_viommu for IOMMUFD_OBJ_VIOMMU.
271282
- iommufd_vdevice for IOMMUFD_OBJ_VDEVICE.
272283
- iommufd_veventq for IOMMUFD_OBJ_VEVENTQ.
284+
- iommufd_hw_queue for IOMMUFD_OBJ_HW_QUEUE.
273285

274286
Several terminologies when looking at these datastructures:
275287

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,22 @@
77

88
#include "arm-smmu-v3.h"
99

10-
void *arm_smmu_hw_info(struct device *dev, u32 *length, u32 *type)
10+
void *arm_smmu_hw_info(struct device *dev, u32 *length,
11+
enum iommu_hw_info_type *type)
1112
{
1213
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
14+
const struct arm_smmu_impl_ops *impl_ops = master->smmu->impl_ops;
1315
struct iommu_hw_info_arm_smmuv3 *info;
1416
u32 __iomem *base_idr;
1517
unsigned int i;
1618

19+
if (*type != IOMMU_HW_INFO_TYPE_DEFAULT &&
20+
*type != IOMMU_HW_INFO_TYPE_ARM_SMMUV3) {
21+
if (!impl_ops || !impl_ops->hw_info)
22+
return ERR_PTR(-EOPNOTSUPP);
23+
return impl_ops->hw_info(master->smmu, length, type);
24+
}
25+
1726
info = kzalloc(sizeof(*info), GFP_KERNEL);
1827
if (!info)
1928
return ERR_PTR(-ENOMEM);
@@ -216,7 +225,7 @@ static int arm_smmu_validate_vste(struct iommu_hwpt_arm_smmuv3 *arg,
216225
return 0;
217226
}
218227

219-
static struct iommu_domain *
228+
struct iommu_domain *
220229
arm_vsmmu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
221230
const struct iommu_user_data *user_data)
222231
{
@@ -327,8 +336,8 @@ static int arm_vsmmu_convert_user_cmd(struct arm_vsmmu *vsmmu,
327336
return 0;
328337
}
329338

330-
static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,
331-
struct iommu_user_data_array *array)
339+
int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,
340+
struct iommu_user_data_array *array)
332341
{
333342
struct arm_vsmmu *vsmmu = container_of(viommu, struct arm_vsmmu, core);
334343
struct arm_smmu_device *smmu = vsmmu->smmu;
@@ -382,33 +391,22 @@ static const struct iommufd_viommu_ops arm_vsmmu_ops = {
382391
.cache_invalidate = arm_vsmmu_cache_invalidate,
383392
};
384393

385-
struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
386-
struct iommu_domain *parent,
387-
struct iommufd_ctx *ictx,
388-
unsigned int viommu_type)
394+
size_t arm_smmu_get_viommu_size(struct device *dev,
395+
enum iommu_viommu_type viommu_type)
389396
{
390-
struct arm_smmu_device *smmu =
391-
iommu_get_iommu_dev(dev, struct arm_smmu_device, iommu);
392397
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
393-
struct arm_smmu_domain *s2_parent = to_smmu_domain(parent);
394-
struct arm_vsmmu *vsmmu;
395-
396-
if (viommu_type != IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
397-
return ERR_PTR(-EOPNOTSUPP);
398+
struct arm_smmu_device *smmu = master->smmu;
398399

399400
if (!(smmu->features & ARM_SMMU_FEAT_NESTING))
400-
return ERR_PTR(-EOPNOTSUPP);
401-
402-
if (s2_parent->smmu != master->smmu)
403-
return ERR_PTR(-EINVAL);
401+
return 0;
404402

405403
/*
406404
* FORCE_SYNC is not set with FEAT_NESTING. Some study of the exact HW
407405
* defect is needed to determine if arm_vsmmu_cache_invalidate() needs
408406
* any change to remove this.
409407
*/
410408
if (WARN_ON(smmu->options & ARM_SMMU_OPT_CMDQ_FORCE_SYNC))
411-
return ERR_PTR(-EOPNOTSUPP);
409+
return 0;
412410

413411
/*
414412
* Must support some way to prevent the VM from bypassing the cache
@@ -420,19 +418,39 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
420418
*/
421419
if (!arm_smmu_master_canwbs(master) &&
422420
!(smmu->features & ARM_SMMU_FEAT_S2FWB))
423-
return ERR_PTR(-EOPNOTSUPP);
421+
return 0;
424422

425-
vsmmu = iommufd_viommu_alloc(ictx, struct arm_vsmmu, core,
426-
&arm_vsmmu_ops);
427-
if (IS_ERR(vsmmu))
428-
return ERR_CAST(vsmmu);
423+
if (viommu_type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
424+
return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core);
425+
426+
if (!smmu->impl_ops || !smmu->impl_ops->get_viommu_size)
427+
return 0;
428+
return smmu->impl_ops->get_viommu_size(viommu_type);
429+
}
430+
431+
int arm_vsmmu_init(struct iommufd_viommu *viommu,
432+
struct iommu_domain *parent_domain,
433+
const struct iommu_user_data *user_data)
434+
{
435+
struct arm_vsmmu *vsmmu = container_of(viommu, struct arm_vsmmu, core);
436+
struct arm_smmu_device *smmu =
437+
container_of(viommu->iommu_dev, struct arm_smmu_device, iommu);
438+
struct arm_smmu_domain *s2_parent = to_smmu_domain(parent_domain);
439+
440+
if (s2_parent->smmu != smmu)
441+
return -EINVAL;
429442

430443
vsmmu->smmu = smmu;
431444
vsmmu->s2_parent = s2_parent;
432445
/* FIXME Move VMID allocation from the S2 domain allocation to here */
433446
vsmmu->vmid = s2_parent->s2_cfg.vmid;
434447

435-
return &vsmmu->core;
448+
if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) {
449+
viommu->ops = &arm_vsmmu_ops;
450+
return 0;
451+
}
452+
453+
return smmu->impl_ops->vsmmu_init(vsmmu, user_data);
436454
}
437455

438456
int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt)

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3689,7 +3689,8 @@ static const struct iommu_ops arm_smmu_ops = {
36893689
.get_resv_regions = arm_smmu_get_resv_regions,
36903690
.page_response = arm_smmu_page_response,
36913691
.def_domain_type = arm_smmu_def_domain_type,
3692-
.viommu_alloc = arm_vsmmu_alloc,
3692+
.get_viommu_size = arm_smmu_get_viommu_size,
3693+
.viommu_init = arm_vsmmu_init,
36933694
.user_pasid_table = 1,
36943695
.owner = THIS_MODULE,
36953696
.default_domain_ops = &(const struct iommu_domain_ops) {
@@ -4700,6 +4701,7 @@ static void arm_smmu_impl_remove(void *data)
47004701
static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
47014702
{
47024703
struct arm_smmu_device *new_smmu = ERR_PTR(-ENODEV);
4704+
const struct arm_smmu_impl_ops *ops;
47034705
int ret;
47044706

47054707
if (smmu->impl_dev && (smmu->options & ARM_SMMU_OPT_TEGRA241_CMDQV))
@@ -4710,11 +4712,24 @@ static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
47104712
if (IS_ERR(new_smmu))
47114713
return new_smmu;
47124714

4715+
ops = new_smmu->impl_ops;
4716+
if (ops) {
4717+
/* get_viommu_size and vsmmu_init ops must be paired */
4718+
if (WARN_ON(!ops->get_viommu_size != !ops->vsmmu_init)) {
4719+
ret = -EINVAL;
4720+
goto err_remove;
4721+
}
4722+
}
4723+
47134724
ret = devm_add_action_or_reset(new_smmu->dev, arm_smmu_impl_remove,
47144725
new_smmu);
47154726
if (ret)
47164727
return ERR_PTR(ret);
47174728
return new_smmu;
4729+
4730+
err_remove:
4731+
arm_smmu_impl_remove(new_smmu);
4732+
return ERR_PTR(ret);
47184733
}
47194734

47204735
static int arm_smmu_device_probe(struct platform_device *pdev)

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/sizes.h>
1717

1818
struct arm_smmu_device;
19+
struct arm_vsmmu;
1920

2021
/* MMIO registers */
2122
#define ARM_SMMU_IDR0 0x0
@@ -721,6 +722,16 @@ struct arm_smmu_impl_ops {
721722
int (*init_structures)(struct arm_smmu_device *smmu);
722723
struct arm_smmu_cmdq *(*get_secondary_cmdq)(
723724
struct arm_smmu_device *smmu, struct arm_smmu_cmdq_ent *ent);
725+
/*
726+
* An implementation should define its own type other than the default
727+
* IOMMU_HW_INFO_TYPE_ARM_SMMUV3. And it must validate the input @type
728+
* to return its own structure.
729+
*/
730+
void *(*hw_info)(struct arm_smmu_device *smmu, u32 *length,
731+
enum iommu_hw_info_type *type);
732+
size_t (*get_viommu_size)(enum iommu_viommu_type viommu_type);
733+
int (*vsmmu_init)(struct arm_vsmmu *vsmmu,
734+
const struct iommu_user_data *user_data);
724735
};
725736

726737
/* An SMMUv3 instance */
@@ -1035,19 +1046,29 @@ struct arm_vsmmu {
10351046
};
10361047

10371048
#if IS_ENABLED(CONFIG_ARM_SMMU_V3_IOMMUFD)
1038-
void *arm_smmu_hw_info(struct device *dev, u32 *length, u32 *type);
1039-
struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
1040-
struct iommu_domain *parent,
1041-
struct iommufd_ctx *ictx,
1042-
unsigned int viommu_type);
1049+
void *arm_smmu_hw_info(struct device *dev, u32 *length,
1050+
enum iommu_hw_info_type *type);
1051+
size_t arm_smmu_get_viommu_size(struct device *dev,
1052+
enum iommu_viommu_type viommu_type);
1053+
int arm_vsmmu_init(struct iommufd_viommu *viommu,
1054+
struct iommu_domain *parent_domain,
1055+
const struct iommu_user_data *user_data);
10431056
int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
10441057
struct arm_smmu_nested_domain *nested_domain);
10451058
void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state);
10461059
void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master);
10471060
int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt);
1061+
struct iommu_domain *
1062+
arm_vsmmu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
1063+
const struct iommu_user_data *user_data);
1064+
int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,
1065+
struct iommu_user_data_array *array);
10481066
#else
1067+
#define arm_smmu_get_viommu_size NULL
10491068
#define arm_smmu_hw_info NULL
1050-
#define arm_vsmmu_alloc NULL
1069+
#define arm_vsmmu_init NULL
1070+
#define arm_vsmmu_alloc_domain_nested NULL
1071+
#define arm_vsmmu_cache_invalidate NULL
10511072

10521073
static inline int
10531074
arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,

0 commit comments

Comments
 (0)