Commit 5a1c7590 authored by Nicolin Chen's avatar Nicolin Chen Committed by Jason Gunthorpe
Browse files

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: default avatarWill Deacon <will@kernel.org>
Acked-by: default avatarWill Deacon <will@kernel.org>
Reviewed-by: default avatarPranjal Shrivastava <praan@google.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent ab6bc441
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -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,14 +446,20 @@ 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;
	}

	/*
	 * 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)
{
	struct iommu_vevent_arm_smmuv3 vevt;
+14 −0
Original line number Diff line number Diff line
@@ -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)