iommu/arm-smmu-v3: Do not bother impl_ops if IOMMU_VIOMMU_TYPE_ARM_SMMUV3

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.

Link: https://patch.msgid.link/r/20250724221002.1883034-2-nicolinc@nvidia.com
Suggested-by: Will Deacon <will@kernel.org>
Acked-by: Will Deacon <will@kernel.org>
Reviewed-by: Pranjal Shrivastava <praan@google.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
Nicolin Chen 2025-07-24 15:10:01 -07:00 committed by Jason Gunthorpe
parent ab6bc44159
commit 5a1c759093
2 changed files with 30 additions and 11 deletions

View File

@ -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,18 @@ 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 should be rejected by arm_smmu_get_viommu_size.
* Seeing one here indicates a kernel bug or some data corruption.
*/
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)

View File

@ -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)