diff options
author | Robin Murphy | 2014-12-05 13:41:02 +0000 |
---|---|---|
committer | Will Deacon | 2014-12-05 14:35:52 +0000 |
commit | a42a7a1fb5f1f9004b023594609dc22da02fc08b (patch) | |
tree | e6f54fe900945b7c1939757a59aeabc510605a27 /drivers/iommu | |
parent | 4bb25789ed28228a52c030bf28edb2fcdb214be8 (diff) |
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')
-rw-r--r-- | drivers/iommu/of_iommu.c | 39 |
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; |