When viommu type is IOMMU_VIOMMU_TYPE_ARM_SMMUV3, always return or init the
standard struct arm_vsmmu, instead of going through impl_ops that must have
its own viommu type than the standard IOMMU_VIOMMU_TYPE_ARM_SMMUV3.
Given that arm_vsmmu_init() is called after arm_smmu_get_viommu_size(), any
unsupported viommu->type must be a corruption. And it must be a driver bug
that its vsmmu_size and vsmmu_init ops aren't paired. Warn these two cases.
Suggested-by: Will Deacon <will@kernel.org>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
.../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 24 ++++++++++---------
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 14 +++++++++++
2 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index d9bea8f1f636..c034d6c5468f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -420,14 +420,13 @@ size_t arm_smmu_get_viommu_size(struct device *dev,
!(smmu->features & ARM_SMMU_FEAT_S2FWB))
return 0;
- if (smmu->impl_ops && smmu->impl_ops->vsmmu_size &&
- viommu_type == smmu->impl_ops->vsmmu_type)
- return smmu->impl_ops->vsmmu_size;
+ if (viommu_type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
+ return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core);
- if (viommu_type != IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
+ if (!smmu->impl_ops || !smmu->impl_ops->vsmmu_size ||
+ viommu_type != smmu->impl_ops->vsmmu_type)
return 0;
-
- return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core);
+ return smmu->impl_ops->vsmmu_size;
}
int arm_vsmmu_init(struct iommufd_viommu *viommu,
@@ -447,12 +446,15 @@ int arm_vsmmu_init(struct iommufd_viommu *viommu,
/* FIXME Move VMID allocation from the S2 domain allocation to here */
vsmmu->vmid = s2_parent->s2_cfg.vmid;
- if (smmu->impl_ops && smmu->impl_ops->vsmmu_init &&
- viommu->type == smmu->impl_ops->vsmmu_type)
- return smmu->impl_ops->vsmmu_init(vsmmu, user_data);
+ if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) {
+ viommu->ops = &arm_vsmmu_ops;
+ return 0;
+ }
- viommu->ops = &arm_vsmmu_ops;
- return 0;
+ /* Unsupported type was rejected in arm_smmu_get_viommu_size() */
+ if (WARN_ON(viommu->type != smmu->impl_ops->vsmmu_type))
+ return -EOPNOTSUPP;
+ return smmu->impl_ops->vsmmu_init(vsmmu, user_data);
}
int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, u64 *evt)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 181d07bc1a9d..dfe7f40fac35 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4703,6 +4703,7 @@ static void arm_smmu_impl_remove(void *data)
static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
{
struct arm_smmu_device *new_smmu = ERR_PTR(-ENODEV);
+ const struct arm_smmu_impl_ops *ops;
int ret;
if (smmu->impl_dev && (smmu->options & ARM_SMMU_OPT_TEGRA241_CMDQV))
@@ -4713,11 +4714,24 @@ static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
if (IS_ERR(new_smmu))
return new_smmu;
+ ops = new_smmu->impl_ops;
+ if (ops) {
+ /* vsmmu_size and vsmmu_init ops must be paired */
+ if (WARN_ON(!ops->vsmmu_size ^ !ops->vsmmu_init)) {
+ ret = -EINVAL;
+ goto err_remove;
+ }
+ }
+
ret = devm_add_action_or_reset(new_smmu->dev, arm_smmu_impl_remove,
new_smmu);
if (ret)
return ERR_PTR(ret);
return new_smmu;
+
+err_remove:
+ arm_smmu_impl_remove(new_smmu);
+ return ERR_PTR(ret);
}
static int arm_smmu_device_probe(struct platform_device *pdev)
--
2.43.0
On Mon, Jul 21, 2025 at 12:12:35PM -0700, Nicolin Chen wrote: > When viommu type is IOMMU_VIOMMU_TYPE_ARM_SMMUV3, always return or init the > standard struct arm_vsmmu, instead of going through impl_ops that must have > its own viommu type than the standard IOMMU_VIOMMU_TYPE_ARM_SMMUV3. > > Given that arm_vsmmu_init() is called after arm_smmu_get_viommu_size(), any > unsupported viommu->type must be a corruption. And it must be a driver bug > that its vsmmu_size and vsmmu_init ops aren't paired. Warn these two cases. > > Suggested-by: Will Deacon <will@kernel.org> > Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> > --- > .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 24 ++++++++++--------- > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 14 +++++++++++ > 2 files changed, 27 insertions(+), 11 deletions(-) Cheers for the quick respin. > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > index 181d07bc1a9d..dfe7f40fac35 100644 > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > @@ -4703,6 +4703,7 @@ static void arm_smmu_impl_remove(void *data) > static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu) > { > struct arm_smmu_device *new_smmu = ERR_PTR(-ENODEV); > + const struct arm_smmu_impl_ops *ops; > int ret; > > if (smmu->impl_dev && (smmu->options & ARM_SMMU_OPT_TEGRA241_CMDQV)) > @@ -4713,11 +4714,24 @@ static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu) > if (IS_ERR(new_smmu)) > return new_smmu; > > + ops = new_smmu->impl_ops; > + if (ops) { > + /* vsmmu_size and vsmmu_init ops must be paired */ > + if (WARN_ON(!ops->vsmmu_size ^ !ops->vsmmu_init)) { > + ret = -EINVAL; > + goto err_remove; > + } I suppose that could be != instead of ^ to avoid mixing up logical and arithmetic operators, but it does the trick either way so: Acked-by: Will Deacon <will@kernel.org> Will
On Mon, Jul 21, 2025 at 08:23:36PM +0100, Will Deacon wrote: > On Mon, Jul 21, 2025 at 12:12:35PM -0700, Nicolin Chen wrote: > > + ops = new_smmu->impl_ops; > > + if (ops) { > > + /* vsmmu_size and vsmmu_init ops must be paired */ > > + if (WARN_ON(!ops->vsmmu_size ^ !ops->vsmmu_init)) { > > + ret = -EINVAL; > > + goto err_remove; > > + } > > I suppose that could be != instead of ^ to avoid mixing up logical and > arithmetic operators, but it does the trick either way so: > > Acked-by: Will Deacon <will@kernel.org> Ah, it only compares one bit, so I think "!=" would be nicer. Will quickly respin a v3. Thanks Nicolin
© 2016 - 2025 Red Hat, Inc.