Skip to content

Commit

Permalink
Merge tag 'iommu-fixes-v6.2-rc3' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/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
  • Loading branch information
Linus Torvalds committed Jan 14, 2023
2 parents 4f43ade + 142e821 commit 7c69844
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 17 deletions.
4 changes: 3 additions & 1 deletion drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down
32 changes: 22 additions & 10 deletions drivers/iommu/arm/arm-smmu/arm-smmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions drivers/iommu/iova.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion drivers/iommu/mtk_iommu_v1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down

0 comments on commit 7c69844

Please sign in to comment.