diff options
| author | Robin Murphy <Robin.Murphy@arm.com> | 2014-12-05 08:41:02 -0500 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2014-12-05 09:35:52 -0500 |
| commit | a42a7a1fb5f1f9004b023594609dc22da02fc08b (patch) | |
| tree | e6f54fe900945b7c1939757a59aeabc510605a27 | |
| 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>
| -rw-r--r-- | drivers/iommu/of_iommu.c | 39 | ||||
| -rw-r--r-- | include/linux/of_iommu.h | 12 |
2 files changed, 41 insertions, 10 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 @@ | |||
| 22 | #include <linux/limits.h> | 22 | #include <linux/limits.h> |
| 23 | #include <linux/of.h> | 23 | #include <linux/of.h> |
| 24 | #include <linux/of_iommu.h> | 24 | #include <linux/of_iommu.h> |
| 25 | #include <linux/slab.h> | ||
| 25 | 26 | ||
| 26 | static const struct of_device_id __iommu_of_table_sentinel | 27 | static const struct of_device_id __iommu_of_table_sentinel |
| 27 | __used __section(__iommu_of_table_end); | 28 | __used __section(__iommu_of_table_end); |
| @@ -94,6 +95,44 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, | |||
| 94 | } | 95 | } |
| 95 | EXPORT_SYMBOL_GPL(of_get_dma_window); | 96 | EXPORT_SYMBOL_GPL(of_get_dma_window); |
| 96 | 97 | ||
| 98 | struct of_iommu_node { | ||
| 99 | struct list_head list; | ||
| 100 | struct device_node *np; | ||
| 101 | struct iommu_ops *ops; | ||
| 102 | }; | ||
| 103 | static LIST_HEAD(of_iommu_list); | ||
| 104 | static DEFINE_SPINLOCK(of_iommu_lock); | ||
| 105 | |||
| 106 | void of_iommu_set_ops(struct device_node *np, struct iommu_ops *ops) | ||
| 107 | { | ||
| 108 | struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | ||
| 109 | |||
| 110 | if (WARN_ON(!iommu)) | ||
| 111 | return; | ||
| 112 | |||
| 113 | INIT_LIST_HEAD(&iommu->list); | ||
| 114 | iommu->np = np; | ||
| 115 | iommu->ops = ops; | ||
| 116 | spin_lock(&of_iommu_lock); | ||
| 117 | list_add_tail(&iommu->list, &of_iommu_list); | ||
| 118 | spin_unlock(&of_iommu_lock); | ||
| 119 | } | ||
| 120 | |||
| 121 | struct iommu_ops *of_iommu_get_ops(struct device_node *np) | ||
| 122 | { | ||
| 123 | struct of_iommu_node *node; | ||
| 124 | struct iommu_ops *ops = NULL; | ||
| 125 | |||
| 126 | spin_lock(&of_iommu_lock); | ||
| 127 | list_for_each_entry(node, &of_iommu_list, list) | ||
| 128 | if (node->np == np) { | ||
| 129 | ops = node->ops; | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | spin_unlock(&of_iommu_lock); | ||
| 133 | return ops; | ||
| 134 | } | ||
| 135 | |||
| 97 | struct iommu_ops *of_iommu_configure(struct device *dev) | 136 | struct iommu_ops *of_iommu_configure(struct device *dev) |
| 98 | { | 137 | { |
| 99 | struct of_phandle_args iommu_spec; | 138 | struct of_phandle_args iommu_spec; |
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index d03abbb11c34..16c75547d725 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h | |||
| @@ -31,16 +31,8 @@ static inline struct iommu_ops *of_iommu_configure(struct device *dev) | |||
| 31 | 31 | ||
| 32 | #endif /* CONFIG_OF_IOMMU */ | 32 | #endif /* CONFIG_OF_IOMMU */ |
| 33 | 33 | ||
| 34 | static inline void of_iommu_set_ops(struct device_node *np, | 34 | void of_iommu_set_ops(struct device_node *np, struct iommu_ops *ops); |
| 35 | const struct iommu_ops *ops) | 35 | struct iommu_ops *of_iommu_get_ops(struct device_node *np); |
| 36 | { | ||
| 37 | np->data = (struct iommu_ops *)ops; | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline struct iommu_ops *of_iommu_get_ops(struct device_node *np) | ||
| 41 | { | ||
| 42 | return np->data; | ||
| 43 | } | ||
| 44 | 36 | ||
| 45 | extern struct of_device_id __iommu_of_table; | 37 | extern struct of_device_id __iommu_of_table; |
| 46 | 38 | ||
