With the preceding data reshuffles allowing SMMU instances to be looked
up directly wherever needed, we can now wipe out the last vestiges of
the global SMMU list. With mmu-masters lookup now a one-time thing
outside of any real hotpath, condense our stash of those out of the SMMU
instance data down to a single shared list, where they may await their
eventual deprecation.

This also seems like a good opportunity to move the parts only relevant
to the probe/remove routines down to live in that area of the code.

Signed-off-by: Robin Murphy <[email protected]>
---
 drivers/iommu/arm-smmu.c | 231 +++++++++++++++++++----------------------------
 1 file changed, 91 insertions(+), 140 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 5eaa8cf..91b0a1b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -301,7 +301,7 @@ struct arm_smmu_group_cfg {
 
 struct arm_smmu_master {
        struct device_node              *of_node;
-       struct rb_node                  node;
+       struct list_head                list;
        struct arm_smmu_master_cfg      cfg;
 };
 
@@ -372,8 +372,8 @@ struct arm_smmu_domain {
 
 static struct iommu_ops arm_smmu_ops;
 
-static DEFINE_SPINLOCK(arm_smmu_devices_lock);
-static LIST_HEAD(arm_smmu_devices);
+static DEFINE_RWLOCK(arm_smmu_masters_lock);
+static LIST_HEAD(arm_smmu_masters);
 
 struct arm_smmu_option_prop {
        u32 opt;
@@ -417,111 +417,20 @@ static struct device_node *dev_get_dev_node(struct 
device *dev)
        return dev->of_node;
 }
 
-static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
-                                               struct device_node *dev_node)
+static struct arm_smmu_master *find_smmu_master(struct device_node *dev_node)
 {
-       struct rb_node *node = smmu->masters.rb_node;
-
-       while (node) {
-               struct arm_smmu_master *master;
-
-               master = container_of(node, struct arm_smmu_master, node);
-
-               if (dev_node < master->of_node)
-                       node = node->rb_left;
-               else if (dev_node > master->of_node)
-                       node = node->rb_right;
-               else
-                       return master;
-       }
-
-       return NULL;
-}
-
-static int insert_smmu_master(struct arm_smmu_device *smmu,
-                             struct arm_smmu_master *master)
-{
-       struct rb_node **new, *parent;
-
-       new = &smmu->masters.rb_node;
-       parent = NULL;
-       while (*new) {
-               struct arm_smmu_master *this
-                       = container_of(*new, struct arm_smmu_master, node);
-
-               parent = *new;
-               if (master->of_node < this->of_node)
-                       new = &((*new)->rb_left);
-               else if (master->of_node > this->of_node)
-                       new = &((*new)->rb_right);
-               else
-                       return -EEXIST;
-       }
-
-       rb_link_node(&master->node, parent, new);
-       rb_insert_color(&master->node, &smmu->masters);
-       return 0;
-}
-
-static int register_smmu_master(struct arm_smmu_device *smmu,
-                               struct of_phandle_args *masterspec)
-{
-       int i;
        struct arm_smmu_master *master;
 
-       master = find_smmu_master(smmu, masterspec->np);
-       if (master) {
-               dev_err(smmu->dev,
-                       "rejecting multiple registrations for master device 
%s\n",
-                       masterspec->np->name);
-               return -EBUSY;
-       }
+       read_lock(&arm_smmu_masters_lock);
+       list_for_each_entry(master, &arm_smmu_masters, list)
+               if (master->of_node == dev_node)
+                       goto out_unlock;
 
-       if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
-               dev_err(smmu->dev,
-                       "reached maximum number (%d) of stream IDs for master 
device %s\n",
-                       MAX_MASTER_STREAMIDS, masterspec->np->name);
-               return -ENOSPC;
-       }
+       master = NULL;
 
-       master = devm_kzalloc(smmu->dev, sizeof(*master), GFP_KERNEL);
-       if (!master)
-               return -ENOMEM;
-
-       master->of_node                 = masterspec->np;
-       master->cfg.num_streamids       = masterspec->args_count;
-
-       for (i = 0; i < master->cfg.num_streamids; ++i) {
-               u16 streamid = masterspec->args[i];
-
-               if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
-                    (streamid >= smmu->num_mapping_groups)) {
-                       dev_err(smmu->dev,
-                               "stream ID for master device %s greater than 
maximum allowed (%d)\n",
-                               masterspec->np->name, smmu->num_mapping_groups);
-                       return -ERANGE;
-               }
-               master->cfg.streamids[i].id = streamid;
-               /* leave .mask 0; we don't currently share SMRs */
-       }
-       return insert_smmu_master(smmu, master);
-}
-
-static struct arm_smmu_device *find_smmu_for_device(struct device *dev)
-{
-       struct arm_smmu_device *smmu;
-       struct arm_smmu_master *master = NULL;
-       struct device_node *dev_node = dev_get_dev_node(dev);
-
-       spin_lock(&arm_smmu_devices_lock);
-       list_for_each_entry(smmu, &arm_smmu_devices, list) {
-               master = find_smmu_master(smmu, dev_node);
-               if (master)
-                       break;
-       }
-       spin_unlock(&arm_smmu_devices_lock);
-
-       return master ? smmu : NULL;
+out_unlock:
+       read_unlock(&arm_smmu_masters_lock);
+       return master;
 }
 
 static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
@@ -1327,36 +1236,26 @@ static int arm_smmu_init_pci_device(struct 
arm_smmu_device *smmu,
        return 0;
 }
 
-static int arm_smmu_init_platform_device(struct arm_smmu_device *smmu,
-                                        struct device *dev)
-{
-       struct arm_smmu_master *master;
-
-       master = find_smmu_master(smmu, dev_get_dev_node(dev));
-       dev->archdata.iommu = &master->cfg;
-
-       return 0;
-}
-
 static int arm_smmu_add_device(struct device *dev)
 {
        struct iommu_group *group;
-       struct arm_smmu_device *smmu;
-       int ret;
+       struct arm_smmu_master *master;
 
        if (dev->archdata.iommu)
                return -EEXIST;
 
-       smmu = find_smmu_for_device(dev);
-       if (!smmu)
+       master = find_smmu_master(dev_get_dev_node(dev));
+       if (!master)
                return -ENODEV;
 
-       if (dev_is_pci(dev))
-               ret = arm_smmu_init_pci_device(smmu, to_pci_dev(dev));
-       else
-               ret = arm_smmu_init_platform_device(smmu, dev);
-       if (ret)
-               return ret;
+       if (dev_is_pci(dev)) {
+               int ret = arm_smmu_init_pci_device(master->cfg.smmu,
+                                                  to_pci_dev(dev));
+               if (ret)
+                       return ret;
+       } else {
+               dev->archdata.iommu = &master->cfg;
+       }
 
        group = iommu_group_get_for_dev(dev);
        if (IS_ERR(group))
@@ -1752,19 +1651,79 @@ MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
 
 static void arm_smmu_remove_mmu_masters(struct arm_smmu_device *smmu)
 {
-       struct arm_smmu_master *master;
-       struct rb_node *node, *tmp;
+       struct arm_smmu_master *master, *tmp;
 
-       node = rb_first(&smmu->masters);
-       while (node) {
-               tmp = node;
-               node = rb_next(node);
-               master = container_of(tmp, struct arm_smmu_master, node);
+       write_lock(&arm_smmu_masters_lock);
+       list_for_each_entry_safe(master, tmp, &arm_smmu_masters, list) {
+               if (master->cfg.smmu != smmu)
+                       continue;
 
-               rb_erase(tmp, &smmu->masters);
+               list_del(&master->list);
                of_node_put(master->of_node);
                devm_kfree(smmu->dev, master);
        }
+       write_unlock(&arm_smmu_masters_lock);
+}
+
+static int insert_smmu_master(struct arm_smmu_master *master)
+{
+       struct arm_smmu_master *tmp;
+       int ret = -EEXIST;
+
+       write_lock(&arm_smmu_masters_lock);
+       list_for_each_entry(tmp, &arm_smmu_masters, list)
+               if (tmp->of_node == master->of_node)
+                       goto out_unlock;
+
+       ret = 0;
+       list_add(&master->list, &arm_smmu_masters);
+out_unlock:
+       write_unlock(&arm_smmu_masters_lock);
+       return ret;
+}
+
+static int register_smmu_master(struct arm_smmu_device *smmu,
+                               struct of_phandle_args *masterspec)
+{
+       int i;
+       struct arm_smmu_master *master;
+
+       master = find_smmu_master(masterspec->np);
+       if (master) {
+               dev_err(smmu->dev,
+                       "rejecting multiple registrations for master device 
%s\n",
+                       masterspec->np->name);
+               return -EBUSY;
+       }
+
+       if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
+               dev_err(smmu->dev,
+                       "reached maximum number (%d) of stream IDs for master 
device %s\n",
+                       MAX_MASTER_STREAMIDS, masterspec->np->name);
+               return -ENOSPC;
+       }
+
+       master = devm_kzalloc(smmu->dev, sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       master->of_node                 = masterspec->np;
+       master->cfg.num_streamids       = masterspec->args_count;
+
+       for (i = 0; i < master->cfg.num_streamids; ++i) {
+               u16 streamid = masterspec->args[i];
+
+               if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
+                    (streamid >= smmu->num_mapping_groups)) {
+                       dev_err(smmu->dev,
+                               "stream ID for master device %s greater than 
maximum allowed (%d)\n",
+                               masterspec->np->name, smmu->num_mapping_groups);
+                       return -ERANGE;
+               }
+               master->cfg.streamids[i].id = streamid;
+               /* leave .mask 0; we don't currently share SMRs */
+       }
+       return insert_smmu_master(master);
 }
 
 static int arm_smmu_probe_mmu_masters(struct arm_smmu_device *smmu)
@@ -1880,11 +1839,6 @@ static int arm_smmu_device_dt_probe(struct 
platform_device *pdev)
 
        platform_set_drvdata(pdev, smmu);
        arm_smmu_probe_mmu_masters(smmu);
-       INIT_LIST_HEAD(&smmu->list);
-       spin_lock(&arm_smmu_devices_lock);
-       list_add(&smmu->list, &arm_smmu_devices);
-       spin_unlock(&arm_smmu_devices_lock);
-
        arm_smmu_device_reset(smmu);
        return 0;
 
@@ -1903,9 +1857,6 @@ static int arm_smmu_device_remove(struct platform_device 
*pdev)
                return -ENODEV;
 
        arm_smmu_remove_mmu_masters(smmu);
-       spin_lock(&arm_smmu_devices_lock);
-       list_del(&smmu->list);
-       spin_unlock(&arm_smmu_devices_lock);
 
        if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
                dev_err(&pdev->dev, "removing device with active domains!\n");
-- 
2.7.2.333.g70bd996.dirty

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to