Commit 7c698440 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'iommu-fixes-v6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - Core: Fix an iommu-group refcount leak

 - Fix overflow issue in IOVA alloc path

 - ARM-SMMU fixes from Will:
    - Fix VFIO regression on NXP SoCs by reporting IOMMU_CAP_CACHE_COHERENCY
    - Fix SMMU shutdown paths to avoid device unregistration race

 - Error handling fix for Mediatek IOMMU driver

* tag 'iommu-fixes-v6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
  iommu/iova: Fix alloc iova overflows issue
  iommu: Fix refcount leak in iommu_device_claim_dma_owner
  iommu/arm-smmu-v3: Don't unregister on shutdown
  iommu/arm-smmu: Don't unregister on shutdown
  iommu/arm-smmu: Report IOMMU_CAP_CACHE_COHERENCY even betterer
parents 4f43ade4 142e821f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -3858,7 +3858,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)

static void arm_smmu_device_shutdown(struct platform_device *pdev)
{
	arm_smmu_device_remove(pdev);
	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);

	arm_smmu_device_disable(smmu);
}

static const struct of_device_id arm_smmu_of_match[] = {
+22 −10
Original line number Diff line number Diff line
@@ -1316,8 +1316,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)

	switch (cap) {
	case IOMMU_CAP_CACHE_COHERENCY:
		/* Assume that a coherent TCU implies coherent TBUs */
		return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
		/*
		 * It's overwhelmingly the case in practice that when the pagetable
		 * walk interface is connected to a coherent interconnect, all the
		 * translation interfaces are too. Furthermore if the device is
		 * natively coherent, then its translation interface must also be.
		 */
		return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK ||
			device_get_dma_attr(dev) == DEV_DMA_COHERENT;
	case IOMMU_CAP_NOEXEC:
		return true;
	default:
@@ -2185,19 +2191,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
	return 0;
}

static int arm_smmu_device_remove(struct platform_device *pdev)
static void arm_smmu_device_shutdown(struct platform_device *pdev)
{
	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);

	if (!smmu)
		return -ENODEV;
		return;

	if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
		dev_notice(&pdev->dev, "disabling translation\n");

	iommu_device_unregister(&smmu->iommu);
	iommu_device_sysfs_remove(&smmu->iommu);

	arm_smmu_rpm_get(smmu);
	/* Turn the thing off */
	arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD);
@@ -2209,12 +2212,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
		clk_bulk_disable(smmu->num_clks, smmu->clks);

	clk_bulk_unprepare(smmu->num_clks, smmu->clks);
	return 0;
}

static void arm_smmu_device_shutdown(struct platform_device *pdev)
static int arm_smmu_device_remove(struct platform_device *pdev)
{
	arm_smmu_device_remove(pdev);
	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);

	if (!smmu)
		return -ENODEV;

	iommu_device_unregister(&smmu->iommu);
	iommu_device_sysfs_remove(&smmu->iommu);

	arm_smmu_device_shutdown(pdev);

	return 0;
}

static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
+5 −3
Original line number Diff line number Diff line
@@ -3185,14 +3185,16 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner);
 */
int iommu_device_claim_dma_owner(struct device *dev, void *owner)
{
	struct iommu_group *group = iommu_group_get(dev);
	struct iommu_group *group;
	int ret = 0;

	if (!group)
		return -ENODEV;
	if (WARN_ON(!owner))
		return -EINVAL;

	group = iommu_group_get(dev);
	if (!group)
		return -ENODEV;

	mutex_lock(&group->mutex);
	if (group->owner_cnt) {
		if (group->owner != owner) {
+2 −2
Original line number Diff line number Diff line
@@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,

	curr = __get_cached_rbnode(iovad, limit_pfn);
	curr_iova = to_iova(curr);
	retry_pfn = curr_iova->pfn_hi + 1;
	retry_pfn = curr_iova->pfn_hi;

retry:
	do {
@@ -211,7 +211,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
	if (high_pfn < size || new_pfn < low_pfn) {
		if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) {
			high_pfn = limit_pfn;
			low_pfn = retry_pfn;
			low_pfn = retry_pfn + 1;
			curr = iova_find_limit(iovad, limit_pfn);
			curr_iova = to_iova(curr);
			goto retry;
+3 −1
Original line number Diff line number Diff line
@@ -683,7 +683,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
	ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
				     dev_name(&pdev->dev));
	if (ret)
		return ret;
		goto out_clk_unprepare;

	ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
	if (ret)
@@ -698,6 +698,8 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
	iommu_device_unregister(&data->iommu);
out_sysfs_remove:
	iommu_device_sysfs_remove(&data->iommu);
out_clk_unprepare:
	clk_disable_unprepare(data->bclk);
	return ret;
}