summaryrefslogtreecommitdiffstats
path: root/drivers/iommu/tegra-smmu.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2020-08-06 17:54:04 +0200
committerJoerg Roedel <jroedel@suse.de>2020-09-04 11:00:14 +0200
commit1ea5440e36a792d01aae0b22159e0a13b33589fe (patch)
treeecf6cb5f8d2f770f606104fa36befea7f2b6a579 /drivers/iommu/tegra-smmu.c
parentiommu/tegra-smmu: Balance IOMMU group reference count (diff)
downloadlinux-1ea5440e36a792d01aae0b22159e0a13b33589fe.tar.xz
linux-1ea5440e36a792d01aae0b22159e0a13b33589fe.zip
iommu/tegra-smmu: Prune IOMMU group when it is released
In order to share groups between multiple devices we keep track of them in a per-SMMU list. When an IOMMU group is released, a dangling pointer to it stays around in that list. Fix this by implementing an IOMMU data release callback for groups where the dangling pointer can be removed. Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://lore.kernel.org/r/20200806155404.3936074-4-thierry.reding@gmail.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/tegra-smmu.c')
-rw-r--r--drivers/iommu/tegra-smmu.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index c439c0929ef8..2574e716086b 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -19,6 +19,7 @@
struct tegra_smmu_group {
struct list_head list;
+ struct tegra_smmu *smmu;
const struct tegra_smmu_group_soc *soc;
struct iommu_group *group;
};
@@ -813,6 +814,16 @@ tegra_smmu_find_group(struct tegra_smmu *smmu, unsigned int swgroup)
return NULL;
}
+static void tegra_smmu_group_release(void *iommu_data)
+{
+ struct tegra_smmu_group *group = iommu_data;
+ struct tegra_smmu *smmu = group->smmu;
+
+ mutex_lock(&smmu->lock);
+ list_del(&group->list);
+ mutex_unlock(&smmu->lock);
+}
+
static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
unsigned int swgroup)
{
@@ -840,6 +851,7 @@ static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
}
INIT_LIST_HEAD(&group->list);
+ group->smmu = smmu;
group->soc = soc;
group->group = iommu_group_alloc();
@@ -849,6 +861,7 @@ static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
return NULL;
}
+ iommu_group_set_iommudata(group->group, group, tegra_smmu_group_release);
iommu_group_set_name(group->group, soc->name);
list_add_tail(&group->list, &smmu->groups);
mutex_unlock(&smmu->lock);