This could ease driver to access corresponding as pointer
when having tegra_smmu_group pointer only, which can help
new mappings debugfs nodes.

Also moving tegra_smmu_find_group_soc() upward, for using
it in new tegra_smmu_attach_as(); and it's better to have
all tegra_smmu_find_* functions together.

Acked-by: Thierry Reding <tred...@nvidia.com>
Signed-off-by: Nicolin Chen <nicol...@nvidia.com>
---
 drivers/iommu/tegra-smmu.c | 96 +++++++++++++++++++++++++++++++-------
 1 file changed, 80 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 532c843eb631..454504aa6602 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -25,6 +25,7 @@ struct tegra_smmu_group {
        struct tegra_smmu *smmu;
        const struct tegra_smmu_group_soc *soc;
        const struct tegra_smmu_swgroup *swgrp;
+       struct tegra_smmu_as *as;
        struct iommu_group *grp;
 };
 
@@ -351,6 +352,19 @@ tegra_smmu_find_swgrp(struct tegra_smmu *smmu, unsigned 
int swgroup)
        return swgrp;
 }
 
+static const struct tegra_smmu_group_soc *
+tegra_smmu_find_group_soc(struct tegra_smmu *smmu, unsigned int swgroup)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < smmu->soc->num_groups; i++)
+               for (j = 0; j < smmu->soc->groups[i].num_swgroups; j++)
+                       if (smmu->soc->groups[i].swgroups[j] == swgroup)
+                               return &smmu->soc->groups[i];
+
+       return NULL;
+}
+
 static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
                              unsigned int asid)
 {
@@ -484,6 +498,59 @@ static void tegra_smmu_as_unprepare(struct tegra_smmu 
*smmu,
        mutex_unlock(&smmu->lock);
 }
 
+static void tegra_smmu_attach_as(struct tegra_smmu *smmu,
+                                struct tegra_smmu_as *as,
+                                unsigned int swgroup)
+{
+       const struct tegra_smmu_swgroup *swgrp;
+       struct tegra_smmu_group *group;
+
+       /* Find swgrp according to the swgroup id */
+       swgrp = tegra_smmu_find_swgrp(smmu, swgroup);
+       if (!swgrp)
+               return;
+
+       mutex_lock(&smmu->lock);
+
+       list_for_each_entry(group, &smmu->groups, list) {
+               if (group->swgrp != swgrp)
+                       continue;
+               if (group->as == as)
+                       break;
+
+               if (group->as)
+                       dev_warn(smmu->dev,
+                                "overwriting group->as for swgroup: %s\n", 
swgrp->name);
+               group->as = as;
+               break;
+       }
+
+       mutex_unlock(&smmu->lock);
+}
+
+static void tegra_smmu_detach_as(struct tegra_smmu *smmu,
+                                unsigned int swgroup)
+{
+       const struct tegra_smmu_swgroup *swgrp;
+       struct tegra_smmu_group *group;
+
+       /* Find swgrp according to the swgroup id */
+       swgrp = tegra_smmu_find_swgrp(smmu, swgroup);
+       if (!swgrp)
+               return;
+
+       mutex_lock(&smmu->lock);
+
+       list_for_each_entry(group, &smmu->groups, list) {
+               if (group->swgrp != swgrp)
+                       continue;
+               group->as = NULL;
+               break;
+       }
+
+       mutex_unlock(&smmu->lock);
+}
+
 static int tegra_smmu_attach_dev(struct iommu_domain *domain,
                                 struct device *dev)
 {
@@ -497,11 +564,15 @@ static int tegra_smmu_attach_dev(struct iommu_domain 
*domain,
                return -ENOENT;
 
        for (index = 0; index < fwspec->num_ids; index++) {
+               unsigned int swgroup = fwspec->ids[index];
+
                err = tegra_smmu_as_prepare(smmu, as);
                if (err)
                        goto disable;
 
-               tegra_smmu_enable(smmu, fwspec->ids[index], as->id);
+               tegra_smmu_attach_as(smmu, as, swgroup);
+
+               tegra_smmu_enable(smmu, swgroup, as->id);
        }
 
        if (index == 0)
@@ -511,7 +582,10 @@ static int tegra_smmu_attach_dev(struct iommu_domain 
*domain,
 
 disable:
        while (index--) {
-               tegra_smmu_disable(smmu, fwspec->ids[index], as->id);
+               unsigned int swgroup = fwspec->ids[index];
+
+               tegra_smmu_disable(smmu, swgroup, as->id);
+               tegra_smmu_detach_as(smmu, swgroup);
                tegra_smmu_as_unprepare(smmu, as);
        }
 
@@ -529,7 +603,10 @@ static void tegra_smmu_detach_dev(struct iommu_domain 
*domain, struct device *de
                return;
 
        for (index = 0; index < fwspec->num_ids; index++) {
-               tegra_smmu_disable(smmu, fwspec->ids[index], as->id);
+               unsigned int swgroup = fwspec->ids[index];
+
+               tegra_smmu_disable(smmu, swgroup, as->id);
+               tegra_smmu_detach_as(smmu, swgroup);
                tegra_smmu_as_unprepare(smmu, as);
        }
 }
@@ -871,19 +948,6 @@ static struct iommu_device *tegra_smmu_probe_device(struct 
device *dev)
 
 static void tegra_smmu_release_device(struct device *dev) {}
 
-static const struct tegra_smmu_group_soc *
-tegra_smmu_find_group_soc(struct tegra_smmu *smmu, unsigned int swgroup)
-{
-       unsigned int i, j;
-
-       for (i = 0; i < smmu->soc->num_groups; i++)
-               for (j = 0; j < smmu->soc->groups[i].num_swgroups; j++)
-                       if (smmu->soc->groups[i].swgroups[j] == swgroup)
-                               return &smmu->soc->groups[i];
-
-       return NULL;
-}
-
 static void tegra_smmu_group_release(void *iommu_data)
 {
        struct tegra_smmu_group *group = iommu_data;
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to