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 | |
| 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>
| -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);  | 
