From: Nicolin Chen Date: Thu, 24 Jul 2025 22:10:01 +0000 (-0700) Subject: iommu/arm-smmu-v3: Do not bother impl_ops if IOMMU_VIOMMU_TYPE_ARM_SMMUV3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a1c7590939c3c5678b782d29f0ccfd1323a8d92;p=thirdparty%2Fkernel%2Flinux.git 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 Acked-by: Will Deacon Reviewed-by: Pranjal Shrivastava Signed-off-by: Nicolin Chen Signed-off-by: Jason Gunthorpe --- 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 d9bea8f1f636d..b963b9b3de542 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,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) 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 181d07bc1a9d4..9f4ad37058010 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)