[PATCH 09/12] iommu/arm-smmu: Simplify mmu-masters handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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 <robin.murphy@xxxxxxx>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux