summaryrefslogtreecommitdiff
path: root/drivers/iommu/of_iommu.c
diff options
context:
space:
mode:
authorRobin Murphy <Robin.Murphy@arm.com>2014-12-05 16:41:02 +0300
committerWill Deacon <will.deacon@arm.com>2014-12-05 17:35:52 +0300
commita42a7a1fb5f1f9004b023594609dc22da02fc08b (patch)
treee6f54fe900945b7c1939757a59aeabc510605a27 /drivers/iommu/of_iommu.c
parent4bb25789ed28228a52c030bf28edb2fcdb214be8 (diff)
downloadlinux-a42a7a1fb5f1f9004b023594609dc22da02fc08b.tar.xz
iommu: store DT-probed IOMMU data privately
Since the data pointer in the DT node is public and may be overwritten by conflicting code, move the DT-probed IOMMU ops to a private list where they will be safe. Acked-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Robin Murphy <robin.murphy@arm.com> [will: added missing #include and missing ')'] Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/of_iommu.c')
-rw-r--r--drivers/iommu/of_iommu.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 73236d3cc955..af1dc6a1c0a1 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -22,6 +22,7 @@
#include <linux/limits.h>
#include <linux/of.h>
#include <linux/of_iommu.h>
+#include <linux/slab.h>
static const struct of_device_id __iommu_of_table_sentinel
__used __section(__iommu_of_table_end);
@@ -94,6 +95,44 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
}
EXPORT_SYMBOL_GPL(of_get_dma_window);
+struct of_iommu_node {
+ struct list_head list;
+ struct device_node *np;
+ struct iommu_ops *ops;
+};
+static LIST_HEAD(of_iommu_list);
+static DEFINE_SPINLOCK(of_iommu_lock);
+
+void of_iommu_set_ops(struct device_node *np, struct iommu_ops *ops)
+{
+ struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+
+ if (WARN_ON(!iommu))
+ return;
+
+ INIT_LIST_HEAD(&iommu->list);
+ iommu->np = np;
+ iommu->ops = ops;
+ spin_lock(&of_iommu_lock);
+ list_add_tail(&iommu->list, &of_iommu_list);
+ spin_unlock(&of_iommu_lock);
+}
+
+struct iommu_ops *of_iommu_get_ops(struct device_node *np)
+{
+ struct of_iommu_node *node;
+ struct iommu_ops *ops = NULL;
+
+ spin_lock(&of_iommu_lock);
+ list_for_each_entry(node, &of_iommu_list, list)
+ if (node->np == np) {
+ ops = node->ops;
+ break;
+ }
+ spin_unlock(&of_iommu_lock);
+ return ops;
+}
+
struct iommu_ops *of_iommu_configure(struct device *dev)
{
struct of_phandle_args iommu_spec;