1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/kernel.h> |
3 | #include <linux/of.h> |
4 | #include <linux/of_device.h> |
5 | #include <linux/of_address.h> |
6 | #include <linux/of_iommu.h> |
7 | #include <linux/of_reserved_mem.h> |
8 | #include <linux/dma-direct.h> /* for bus_dma_region */ |
9 | #include <linux/dma-map-ops.h> |
10 | #include <linux/init.h> |
11 | #include <linux/mod_devicetable.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/platform_device.h> |
14 | |
15 | #include <asm/errno.h> |
16 | #include "of_private.h" |
17 | |
18 | /** |
19 | * of_match_device - Tell if a struct device matches an of_device_id list |
20 | * @matches: array of of device match structures to search in |
21 | * @dev: the of device structure to match against |
22 | * |
23 | * Used by a driver to check whether an platform_device present in the |
24 | * system is in its list of supported devices. |
25 | */ |
26 | const struct of_device_id *of_match_device(const struct of_device_id *matches, |
27 | const struct device *dev) |
28 | { |
29 | if (!matches || !dev->of_node || dev->of_node_reused) |
30 | return NULL; |
31 | return of_match_node(matches, node: dev->of_node); |
32 | } |
33 | EXPORT_SYMBOL(of_match_device); |
34 | |
35 | static void |
36 | of_dma_set_restricted_buffer(struct device *dev, struct device_node *np) |
37 | { |
38 | struct device_node *node, *of_node = dev->of_node; |
39 | int count, i; |
40 | |
41 | if (!IS_ENABLED(CONFIG_DMA_RESTRICTED_POOL)) |
42 | return; |
43 | |
44 | count = of_property_count_elems_of_size(np: of_node, propname: "memory-region" , |
45 | elem_size: sizeof(u32)); |
46 | /* |
47 | * If dev->of_node doesn't exist or doesn't contain memory-region, try |
48 | * the OF node having DMA configuration. |
49 | */ |
50 | if (count <= 0) { |
51 | of_node = np; |
52 | count = of_property_count_elems_of_size( |
53 | np: of_node, propname: "memory-region" , elem_size: sizeof(u32)); |
54 | } |
55 | |
56 | for (i = 0; i < count; i++) { |
57 | node = of_parse_phandle(np: of_node, phandle_name: "memory-region" , index: i); |
58 | /* |
59 | * There might be multiple memory regions, but only one |
60 | * restricted-dma-pool region is allowed. |
61 | */ |
62 | if (of_device_is_compatible(device: node, "restricted-dma-pool" ) && |
63 | of_device_is_available(device: node)) { |
64 | of_node_put(node); |
65 | break; |
66 | } |
67 | of_node_put(node); |
68 | } |
69 | |
70 | /* |
71 | * Attempt to initialize a restricted-dma-pool region if one was found. |
72 | * Note that count can hold a negative error code. |
73 | */ |
74 | if (i < count && of_reserved_mem_device_init_by_idx(dev, np: of_node, idx: i)) |
75 | dev_warn(dev, "failed to initialise \"restricted-dma-pool\" memory node\n" ); |
76 | } |
77 | |
78 | /** |
79 | * of_dma_configure_id - Setup DMA configuration |
80 | * @dev: Device to apply DMA configuration |
81 | * @np: Pointer to OF node having DMA configuration |
82 | * @force_dma: Whether device is to be set up by of_dma_configure() even if |
83 | * DMA capability is not explicitly described by firmware. |
84 | * @id: Optional const pointer value input id |
85 | * |
86 | * Try to get devices's DMA configuration from DT and update it |
87 | * accordingly. |
88 | * |
89 | * If platform code needs to use its own special DMA configuration, it |
90 | * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events |
91 | * to fix up DMA configuration. |
92 | */ |
93 | int of_dma_configure_id(struct device *dev, struct device_node *np, |
94 | bool force_dma, const u32 *id) |
95 | { |
96 | const struct iommu_ops *iommu; |
97 | const struct bus_dma_region *map = NULL; |
98 | struct device_node *bus_np; |
99 | u64 dma_start = 0; |
100 | u64 mask, end, size = 0; |
101 | bool coherent; |
102 | int ret; |
103 | |
104 | if (np == dev->of_node) |
105 | bus_np = __of_get_dma_parent(np); |
106 | else |
107 | bus_np = of_node_get(node: np); |
108 | |
109 | ret = of_dma_get_range(np: bus_np, map: &map); |
110 | of_node_put(node: bus_np); |
111 | if (ret < 0) { |
112 | /* |
113 | * For legacy reasons, we have to assume some devices need |
114 | * DMA configuration regardless of whether "dma-ranges" is |
115 | * correctly specified or not. |
116 | */ |
117 | if (!force_dma) |
118 | return ret == -ENODEV ? 0 : ret; |
119 | } else { |
120 | const struct bus_dma_region *r = map; |
121 | u64 dma_end = 0; |
122 | |
123 | /* Determine the overall bounds of all DMA regions */ |
124 | for (dma_start = ~0; r->size; r++) { |
125 | /* Take lower and upper limits */ |
126 | if (r->dma_start < dma_start) |
127 | dma_start = r->dma_start; |
128 | if (r->dma_start + r->size > dma_end) |
129 | dma_end = r->dma_start + r->size; |
130 | } |
131 | size = dma_end - dma_start; |
132 | |
133 | /* |
134 | * Add a work around to treat the size as mask + 1 in case |
135 | * it is defined in DT as a mask. |
136 | */ |
137 | if (size & 1) { |
138 | dev_warn(dev, "Invalid size 0x%llx for dma-range(s)\n" , |
139 | size); |
140 | size = size + 1; |
141 | } |
142 | |
143 | if (!size) { |
144 | dev_err(dev, "Adjusted size 0x%llx invalid\n" , size); |
145 | kfree(objp: map); |
146 | return -EINVAL; |
147 | } |
148 | } |
149 | |
150 | /* |
151 | * If @dev is expected to be DMA-capable then the bus code that created |
152 | * it should have initialised its dma_mask pointer by this point. For |
153 | * now, we'll continue the legacy behaviour of coercing it to the |
154 | * coherent mask if not, but we'll no longer do so quietly. |
155 | */ |
156 | if (!dev->dma_mask) { |
157 | dev_warn(dev, "DMA mask not set\n" ); |
158 | dev->dma_mask = &dev->coherent_dma_mask; |
159 | } |
160 | |
161 | if (!size && dev->coherent_dma_mask) |
162 | size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); |
163 | else if (!size) |
164 | size = 1ULL << 32; |
165 | |
166 | /* |
167 | * Limit coherent and dma mask based on size and default mask |
168 | * set by the driver. |
169 | */ |
170 | end = dma_start + size - 1; |
171 | mask = DMA_BIT_MASK(ilog2(end) + 1); |
172 | dev->coherent_dma_mask &= mask; |
173 | *dev->dma_mask &= mask; |
174 | /* ...but only set bus limit and range map if we found valid dma-ranges earlier */ |
175 | if (!ret) { |
176 | dev->bus_dma_limit = end; |
177 | dev->dma_range_map = map; |
178 | } |
179 | |
180 | coherent = of_dma_is_coherent(np); |
181 | dev_dbg(dev, "device is%sdma coherent\n" , |
182 | coherent ? " " : " not " ); |
183 | |
184 | iommu = of_iommu_configure(dev, master_np: np, id); |
185 | if (PTR_ERR(ptr: iommu) == -EPROBE_DEFER) { |
186 | /* Don't touch range map if it wasn't set from a valid dma-ranges */ |
187 | if (!ret) |
188 | dev->dma_range_map = NULL; |
189 | kfree(objp: map); |
190 | return -EPROBE_DEFER; |
191 | } |
192 | |
193 | dev_dbg(dev, "device is%sbehind an iommu\n" , |
194 | iommu ? " " : " not " ); |
195 | |
196 | arch_setup_dma_ops(dev, dma_base: dma_start, size, iommu, coherent); |
197 | |
198 | if (!iommu) |
199 | of_dma_set_restricted_buffer(dev, np); |
200 | |
201 | return 0; |
202 | } |
203 | EXPORT_SYMBOL_GPL(of_dma_configure_id); |
204 | |
205 | const void *of_device_get_match_data(const struct device *dev) |
206 | { |
207 | const struct of_device_id *match; |
208 | |
209 | match = of_match_device(dev->driver->of_match_table, dev); |
210 | if (!match) |
211 | return NULL; |
212 | |
213 | return match->data; |
214 | } |
215 | EXPORT_SYMBOL(of_device_get_match_data); |
216 | |
217 | /** |
218 | * of_device_modalias - Fill buffer with newline terminated modalias string |
219 | * @dev: Calling device |
220 | * @str: Modalias string |
221 | * @len: Size of @str |
222 | */ |
223 | ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) |
224 | { |
225 | ssize_t sl; |
226 | |
227 | if (!dev || !dev->of_node || dev->of_node_reused) |
228 | return -ENODEV; |
229 | |
230 | sl = of_modalias(np: dev->of_node, str, len: len - 2); |
231 | if (sl < 0) |
232 | return sl; |
233 | if (sl > len - 2) |
234 | return -ENOMEM; |
235 | |
236 | str[sl++] = '\n'; |
237 | str[sl] = 0; |
238 | return sl; |
239 | } |
240 | EXPORT_SYMBOL_GPL(of_device_modalias); |
241 | |
242 | /** |
243 | * of_device_uevent - Display OF related uevent information |
244 | * @dev: Device to display the uevent information for |
245 | * @env: Kernel object's userspace event reference to fill up |
246 | */ |
247 | void of_device_uevent(const struct device *dev, struct kobj_uevent_env *env) |
248 | { |
249 | const char *compat, *type; |
250 | struct alias_prop *app; |
251 | struct property *p; |
252 | int seen = 0; |
253 | |
254 | if ((!dev) || (!dev->of_node)) |
255 | return; |
256 | |
257 | add_uevent_var(env, format: "OF_NAME=%pOFn" , dev->of_node); |
258 | add_uevent_var(env, format: "OF_FULLNAME=%pOF" , dev->of_node); |
259 | type = of_node_get_device_type(np: dev->of_node); |
260 | if (type) |
261 | add_uevent_var(env, format: "OF_TYPE=%s" , type); |
262 | |
263 | /* Since the compatible field can contain pretty much anything |
264 | * it's not really legal to split it out with commas. We split it |
265 | * up using a number of environment variables instead. */ |
266 | of_property_for_each_string(dev->of_node, "compatible" , p, compat) { |
267 | add_uevent_var(env, format: "OF_COMPATIBLE_%d=%s" , seen, compat); |
268 | seen++; |
269 | } |
270 | add_uevent_var(env, format: "OF_COMPATIBLE_N=%d" , seen); |
271 | |
272 | seen = 0; |
273 | mutex_lock(&of_mutex); |
274 | list_for_each_entry(app, &aliases_lookup, link) { |
275 | if (dev->of_node == app->np) { |
276 | add_uevent_var(env, format: "OF_ALIAS_%d=%s" , seen, |
277 | app->alias); |
278 | seen++; |
279 | } |
280 | } |
281 | mutex_unlock(lock: &of_mutex); |
282 | } |
283 | EXPORT_SYMBOL_GPL(of_device_uevent); |
284 | |
285 | int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *env) |
286 | { |
287 | int sl; |
288 | |
289 | if ((!dev) || (!dev->of_node) || dev->of_node_reused) |
290 | return -ENODEV; |
291 | |
292 | /* Devicetree modalias is tricky, we add it in 2 steps */ |
293 | if (add_uevent_var(env, format: "MODALIAS=" )) |
294 | return -ENOMEM; |
295 | |
296 | sl = of_modalias(np: dev->of_node, str: &env->buf[env->buflen-1], |
297 | len: sizeof(env->buf) - env->buflen); |
298 | if (sl < 0) |
299 | return sl; |
300 | if (sl >= (sizeof(env->buf) - env->buflen)) |
301 | return -ENOMEM; |
302 | env->buflen += sl; |
303 | |
304 | return 0; |
305 | } |
306 | EXPORT_SYMBOL_GPL(of_device_uevent_modalias); |
307 | |