diff options
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/Kconfig | 2 | ||||
-rw-r--r-- | drivers/iommu/iommu.c | 2 | ||||
-rw-r--r-- | drivers/iommu/of_iommu.c | 89 |
3 files changed, 91 insertions, 2 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 2fbe3b1dc92d..325188eef1c1 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
@@ -15,7 +15,7 @@ if IOMMU_SUPPORT | |||
15 | 15 | ||
16 | config OF_IOMMU | 16 | config OF_IOMMU |
17 | def_bool y | 17 | def_bool y |
18 | depends on OF | 18 | depends on OF && IOMMU_API |
19 | 19 | ||
20 | config FSL_PAMU | 20 | config FSL_PAMU |
21 | bool "Freescale IOMMU support" | 21 | bool "Freescale IOMMU support" |
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1bd63352ab17..f7718d73e984 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
@@ -737,7 +737,7 @@ static int add_iommu_group(struct device *dev, void *data) | |||
737 | const struct iommu_ops *ops = cb->ops; | 737 | const struct iommu_ops *ops = cb->ops; |
738 | 738 | ||
739 | if (!ops->add_device) | 739 | if (!ops->add_device) |
740 | return -ENODEV; | 740 | return 0; |
741 | 741 | ||
742 | WARN_ON(dev->iommu_group); | 742 | WARN_ON(dev->iommu_group); |
743 | 743 | ||
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index e550ccb7634e..af1dc6a1c0a1 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c | |||
@@ -18,9 +18,14 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/export.h> | 20 | #include <linux/export.h> |
21 | #include <linux/iommu.h> | ||
21 | #include <linux/limits.h> | 22 | #include <linux/limits.h> |
22 | #include <linux/of.h> | 23 | #include <linux/of.h> |
23 | #include <linux/of_iommu.h> | 24 | #include <linux/of_iommu.h> |
25 | #include <linux/slab.h> | ||
26 | |||
27 | static const struct of_device_id __iommu_of_table_sentinel | ||
28 | __used __section(__iommu_of_table_end); | ||
24 | 29 | ||
25 | /** | 30 | /** |
26 | * of_get_dma_window - Parse *dma-window property and returns 0 if found. | 31 | * of_get_dma_window - Parse *dma-window property and returns 0 if found. |
@@ -89,3 +94,87 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, | |||
89 | return 0; | 94 | return 0; |
90 | } | 95 | } |
91 | EXPORT_SYMBOL_GPL(of_get_dma_window); | 96 | EXPORT_SYMBOL_GPL(of_get_dma_window); |
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 | |||
136 | struct iommu_ops *of_iommu_configure(struct device *dev) | ||
137 | { | ||
138 | struct of_phandle_args iommu_spec; | ||
139 | struct device_node *np; | ||
140 | struct iommu_ops *ops = NULL; | ||
141 | int idx = 0; | ||
142 | |||
143 | /* | ||
144 | * We don't currently walk up the tree looking for a parent IOMMU. | ||
145 | * See the `Notes:' section of | ||
146 | * Documentation/devicetree/bindings/iommu/iommu.txt | ||
147 | */ | ||
148 | while (!of_parse_phandle_with_args(dev->of_node, "iommus", | ||
149 | "#iommu-cells", idx, | ||
150 | &iommu_spec)) { | ||
151 | np = iommu_spec.np; | ||
152 | ops = of_iommu_get_ops(np); | ||
153 | |||
154 | if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec)) | ||
155 | goto err_put_node; | ||
156 | |||
157 | of_node_put(np); | ||
158 | idx++; | ||
159 | } | ||
160 | |||
161 | return ops; | ||
162 | |||
163 | err_put_node: | ||
164 | of_node_put(np); | ||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | void __init of_iommu_init(void) | ||
169 | { | ||
170 | struct device_node *np; | ||
171 | const struct of_device_id *match, *matches = &__iommu_of_table; | ||
172 | |||
173 | for_each_matching_node_and_match(np, matches, &match) { | ||
174 | const of_iommu_init_fn init_fn = match->data; | ||
175 | |||
176 | if (init_fn(np)) | ||
177 | pr_err("Failed to initialise IOMMU %s\n", | ||
178 | of_node_full_name(np)); | ||
179 | } | ||
180 | } | ||