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

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
...@@ -3858,7 +3858,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev) ...@@ -3858,7 +3858,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
static void arm_smmu_device_shutdown(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[] = { static const struct of_device_id arm_smmu_of_match[] = {
......
...@@ -1316,8 +1316,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap) ...@@ -1316,8 +1316,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
switch (cap) { switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY: 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: case IOMMU_CAP_NOEXEC:
return true; return true;
default: default:
...@@ -2185,19 +2191,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev) ...@@ -2185,19 +2191,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
return 0; 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); struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
if (!smmu) if (!smmu)
return -ENODEV; return;
if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS)) if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
dev_notice(&pdev->dev, "disabling translation\n"); dev_notice(&pdev->dev, "disabling translation\n");
iommu_device_unregister(&smmu->iommu);
iommu_device_sysfs_remove(&smmu->iommu);
arm_smmu_rpm_get(smmu); arm_smmu_rpm_get(smmu);
/* Turn the thing off */ /* Turn the thing off */
arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD); 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) ...@@ -2209,12 +2212,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
clk_bulk_disable(smmu->num_clks, smmu->clks); clk_bulk_disable(smmu->num_clks, smmu->clks);
clk_bulk_unprepare(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) static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
......
...@@ -3185,14 +3185,16 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner); ...@@ -3185,14 +3185,16 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner);
*/ */
int iommu_device_claim_dma_owner(struct device *dev, void *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; int ret = 0;
if (!group)
return -ENODEV;
if (WARN_ON(!owner)) if (WARN_ON(!owner))
return -EINVAL; return -EINVAL;
group = iommu_group_get(dev);
if (!group)
return -ENODEV;
mutex_lock(&group->mutex); mutex_lock(&group->mutex);
if (group->owner_cnt) { if (group->owner_cnt) {
if (group->owner != owner) { if (group->owner != owner) {
......
...@@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, ...@@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
curr = __get_cached_rbnode(iovad, limit_pfn); curr = __get_cached_rbnode(iovad, limit_pfn);
curr_iova = to_iova(curr); curr_iova = to_iova(curr);
retry_pfn = curr_iova->pfn_hi + 1; retry_pfn = curr_iova->pfn_hi;
retry: retry:
do { do {
...@@ -211,7 +211,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, ...@@ -211,7 +211,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
if (high_pfn < size || new_pfn < low_pfn) { if (high_pfn < size || new_pfn < low_pfn) {
if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) { if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) {
high_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_find_limit(iovad, limit_pfn);
curr_iova = to_iova(curr); curr_iova = to_iova(curr);
goto retry; goto retry;
......
...@@ -683,7 +683,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) ...@@ -683,7 +683,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
dev_name(&pdev->dev)); dev_name(&pdev->dev));
if (ret) if (ret)
return ret; goto out_clk_unprepare;
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev); ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
if (ret) if (ret)
...@@ -698,6 +698,8 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev) ...@@ -698,6 +698,8 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
iommu_device_unregister(&data->iommu); iommu_device_unregister(&data->iommu);
out_sysfs_remove: out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu); iommu_device_sysfs_remove(&data->iommu);
out_clk_unprepare:
clk_disable_unprepare(data->bclk);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment