diff options
author | Thierry Reding <treding@nvidia.com> | 2020-08-06 17:54:04 +0200 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2020-09-04 11:00:14 +0200 |
commit | 1ea5440e36a792d01aae0b22159e0a13b33589fe (patch) | |
tree | ecf6cb5f8d2f770f606104fa36befea7f2b6a579 /drivers/iommu | |
parent | 5b30fbfa2aa5c068444d576b1c87b2bd1bddf0ba (diff) |
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')
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 13 |
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); |