diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 303 |
1 files changed, 207 insertions, 96 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 2390ddb22d60..321d3ef05006 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -24,38 +24,21 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/proc_fs.h> | 25 | #include <linux/proc_fs.h> |
26 | 26 | ||
27 | /** | 27 | #include "of_private.h" |
28 | * struct alias_prop - Alias property in 'aliases' node | ||
29 | * @link: List node to link the structure in aliases_lookup list | ||
30 | * @alias: Alias property name | ||
31 | * @np: Pointer to device_node that the alias stands for | ||
32 | * @id: Index value from end of alias name | ||
33 | * @stem: Alias string without the index | ||
34 | * | ||
35 | * The structure represents one alias property of 'aliases' node as | ||
36 | * an entry in aliases_lookup list. | ||
37 | */ | ||
38 | struct alias_prop { | ||
39 | struct list_head link; | ||
40 | const char *alias; | ||
41 | struct device_node *np; | ||
42 | int id; | ||
43 | char stem[0]; | ||
44 | }; | ||
45 | 28 | ||
46 | static LIST_HEAD(aliases_lookup); | 29 | LIST_HEAD(aliases_lookup); |
47 | 30 | ||
48 | struct device_node *of_allnodes; | 31 | struct device_node *of_allnodes; |
49 | EXPORT_SYMBOL(of_allnodes); | 32 | EXPORT_SYMBOL(of_allnodes); |
50 | struct device_node *of_chosen; | 33 | struct device_node *of_chosen; |
51 | struct device_node *of_aliases; | 34 | struct device_node *of_aliases; |
52 | 35 | ||
53 | static DEFINE_MUTEX(of_aliases_mutex); | 36 | DEFINE_MUTEX(of_aliases_mutex); |
54 | 37 | ||
55 | /* use when traversing tree through the allnext, child, sibling, | 38 | /* use when traversing tree through the allnext, child, sibling, |
56 | * or parent members of struct device_node. | 39 | * or parent members of struct device_node. |
57 | */ | 40 | */ |
58 | DEFINE_RWLOCK(devtree_lock); | 41 | DEFINE_RAW_SPINLOCK(devtree_lock); |
59 | 42 | ||
60 | int of_n_addr_cells(struct device_node *np) | 43 | int of_n_addr_cells(struct device_node *np) |
61 | { | 44 | { |
@@ -164,16 +147,14 @@ void of_node_put(struct device_node *node) | |||
164 | EXPORT_SYMBOL(of_node_put); | 147 | EXPORT_SYMBOL(of_node_put); |
165 | #endif /* CONFIG_OF_DYNAMIC */ | 148 | #endif /* CONFIG_OF_DYNAMIC */ |
166 | 149 | ||
167 | struct property *of_find_property(const struct device_node *np, | 150 | static struct property *__of_find_property(const struct device_node *np, |
168 | const char *name, | 151 | const char *name, int *lenp) |
169 | int *lenp) | ||
170 | { | 152 | { |
171 | struct property *pp; | 153 | struct property *pp; |
172 | 154 | ||
173 | if (!np) | 155 | if (!np) |
174 | return NULL; | 156 | return NULL; |
175 | 157 | ||
176 | read_lock(&devtree_lock); | ||
177 | for (pp = np->properties; pp; pp = pp->next) { | 158 | for (pp = np->properties; pp; pp = pp->next) { |
178 | if (of_prop_cmp(pp->name, name) == 0) { | 159 | if (of_prop_cmp(pp->name, name) == 0) { |
179 | if (lenp) | 160 | if (lenp) |
@@ -181,7 +162,20 @@ struct property *of_find_property(const struct device_node *np, | |||
181 | break; | 162 | break; |
182 | } | 163 | } |
183 | } | 164 | } |
184 | read_unlock(&devtree_lock); | 165 | |
166 | return pp; | ||
167 | } | ||
168 | |||
169 | struct property *of_find_property(const struct device_node *np, | ||
170 | const char *name, | ||
171 | int *lenp) | ||
172 | { | ||
173 | struct property *pp; | ||
174 | unsigned long flags; | ||
175 | |||
176 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
177 | pp = __of_find_property(np, name, lenp); | ||
178 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
185 | 179 | ||
186 | return pp; | 180 | return pp; |
187 | } | 181 | } |
@@ -199,13 +193,13 @@ struct device_node *of_find_all_nodes(struct device_node *prev) | |||
199 | { | 193 | { |
200 | struct device_node *np; | 194 | struct device_node *np; |
201 | 195 | ||
202 | read_lock(&devtree_lock); | 196 | raw_spin_lock(&devtree_lock); |
203 | np = prev ? prev->allnext : of_allnodes; | 197 | np = prev ? prev->allnext : of_allnodes; |
204 | for (; np != NULL; np = np->allnext) | 198 | for (; np != NULL; np = np->allnext) |
205 | if (of_node_get(np)) | 199 | if (of_node_get(np)) |
206 | break; | 200 | break; |
207 | of_node_put(prev); | 201 | of_node_put(prev); |
208 | read_unlock(&devtree_lock); | 202 | raw_spin_unlock(&devtree_lock); |
209 | return np; | 203 | return np; |
210 | } | 204 | } |
211 | EXPORT_SYMBOL(of_find_all_nodes); | 205 | EXPORT_SYMBOL(of_find_all_nodes); |
@@ -214,8 +208,20 @@ EXPORT_SYMBOL(of_find_all_nodes); | |||
214 | * Find a property with a given name for a given node | 208 | * Find a property with a given name for a given node |
215 | * and return the value. | 209 | * and return the value. |
216 | */ | 210 | */ |
211 | static const void *__of_get_property(const struct device_node *np, | ||
212 | const char *name, int *lenp) | ||
213 | { | ||
214 | struct property *pp = __of_find_property(np, name, lenp); | ||
215 | |||
216 | return pp ? pp->value : NULL; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Find a property with a given name for a given node | ||
221 | * and return the value. | ||
222 | */ | ||
217 | const void *of_get_property(const struct device_node *np, const char *name, | 223 | const void *of_get_property(const struct device_node *np, const char *name, |
218 | int *lenp) | 224 | int *lenp) |
219 | { | 225 | { |
220 | struct property *pp = of_find_property(np, name, lenp); | 226 | struct property *pp = of_find_property(np, name, lenp); |
221 | 227 | ||
@@ -226,13 +232,13 @@ EXPORT_SYMBOL(of_get_property); | |||
226 | /** Checks if the given "compat" string matches one of the strings in | 232 | /** Checks if the given "compat" string matches one of the strings in |
227 | * the device's "compatible" property | 233 | * the device's "compatible" property |
228 | */ | 234 | */ |
229 | int of_device_is_compatible(const struct device_node *device, | 235 | static int __of_device_is_compatible(const struct device_node *device, |
230 | const char *compat) | 236 | const char *compat) |
231 | { | 237 | { |
232 | const char* cp; | 238 | const char* cp; |
233 | int cplen, l; | 239 | int cplen, l; |
234 | 240 | ||
235 | cp = of_get_property(device, "compatible", &cplen); | 241 | cp = __of_get_property(device, "compatible", &cplen); |
236 | if (cp == NULL) | 242 | if (cp == NULL) |
237 | return 0; | 243 | return 0; |
238 | while (cplen > 0) { | 244 | while (cplen > 0) { |
@@ -245,6 +251,21 @@ int of_device_is_compatible(const struct device_node *device, | |||
245 | 251 | ||
246 | return 0; | 252 | return 0; |
247 | } | 253 | } |
254 | |||
255 | /** Checks if the given "compat" string matches one of the strings in | ||
256 | * the device's "compatible" property | ||
257 | */ | ||
258 | int of_device_is_compatible(const struct device_node *device, | ||
259 | const char *compat) | ||
260 | { | ||
261 | unsigned long flags; | ||
262 | int res; | ||
263 | |||
264 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
265 | res = __of_device_is_compatible(device, compat); | ||
266 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
267 | return res; | ||
268 | } | ||
248 | EXPORT_SYMBOL(of_device_is_compatible); | 269 | EXPORT_SYMBOL(of_device_is_compatible); |
249 | 270 | ||
250 | /** | 271 | /** |
@@ -269,19 +290,19 @@ int of_machine_is_compatible(const char *compat) | |||
269 | EXPORT_SYMBOL(of_machine_is_compatible); | 290 | EXPORT_SYMBOL(of_machine_is_compatible); |
270 | 291 | ||
271 | /** | 292 | /** |
272 | * of_device_is_available - check if a device is available for use | 293 | * __of_device_is_available - check if a device is available for use |
273 | * | 294 | * |
274 | * @device: Node to check for availability | 295 | * @device: Node to check for availability, with locks already held |
275 | * | 296 | * |
276 | * Returns 1 if the status property is absent or set to "okay" or "ok", | 297 | * Returns 1 if the status property is absent or set to "okay" or "ok", |
277 | * 0 otherwise | 298 | * 0 otherwise |
278 | */ | 299 | */ |
279 | int of_device_is_available(const struct device_node *device) | 300 | static int __of_device_is_available(const struct device_node *device) |
280 | { | 301 | { |
281 | const char *status; | 302 | const char *status; |
282 | int statlen; | 303 | int statlen; |
283 | 304 | ||
284 | status = of_get_property(device, "status", &statlen); | 305 | status = __of_get_property(device, "status", &statlen); |
285 | if (status == NULL) | 306 | if (status == NULL) |
286 | return 1; | 307 | return 1; |
287 | 308 | ||
@@ -292,6 +313,26 @@ int of_device_is_available(const struct device_node *device) | |||
292 | 313 | ||
293 | return 0; | 314 | return 0; |
294 | } | 315 | } |
316 | |||
317 | /** | ||
318 | * of_device_is_available - check if a device is available for use | ||
319 | * | ||
320 | * @device: Node to check for availability | ||
321 | * | ||
322 | * Returns 1 if the status property is absent or set to "okay" or "ok", | ||
323 | * 0 otherwise | ||
324 | */ | ||
325 | int of_device_is_available(const struct device_node *device) | ||
326 | { | ||
327 | unsigned long flags; | ||
328 | int res; | ||
329 | |||
330 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
331 | res = __of_device_is_available(device); | ||
332 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
333 | return res; | ||
334 | |||
335 | } | ||
295 | EXPORT_SYMBOL(of_device_is_available); | 336 | EXPORT_SYMBOL(of_device_is_available); |
296 | 337 | ||
297 | /** | 338 | /** |
@@ -304,13 +345,14 @@ EXPORT_SYMBOL(of_device_is_available); | |||
304 | struct device_node *of_get_parent(const struct device_node *node) | 345 | struct device_node *of_get_parent(const struct device_node *node) |
305 | { | 346 | { |
306 | struct device_node *np; | 347 | struct device_node *np; |
348 | unsigned long flags; | ||
307 | 349 | ||
308 | if (!node) | 350 | if (!node) |
309 | return NULL; | 351 | return NULL; |
310 | 352 | ||
311 | read_lock(&devtree_lock); | 353 | raw_spin_lock_irqsave(&devtree_lock, flags); |
312 | np = of_node_get(node->parent); | 354 | np = of_node_get(node->parent); |
313 | read_unlock(&devtree_lock); | 355 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
314 | return np; | 356 | return np; |
315 | } | 357 | } |
316 | EXPORT_SYMBOL(of_get_parent); | 358 | EXPORT_SYMBOL(of_get_parent); |
@@ -329,14 +371,15 @@ EXPORT_SYMBOL(of_get_parent); | |||
329 | struct device_node *of_get_next_parent(struct device_node *node) | 371 | struct device_node *of_get_next_parent(struct device_node *node) |
330 | { | 372 | { |
331 | struct device_node *parent; | 373 | struct device_node *parent; |
374 | unsigned long flags; | ||
332 | 375 | ||
333 | if (!node) | 376 | if (!node) |
334 | return NULL; | 377 | return NULL; |
335 | 378 | ||
336 | read_lock(&devtree_lock); | 379 | raw_spin_lock_irqsave(&devtree_lock, flags); |
337 | parent = of_node_get(node->parent); | 380 | parent = of_node_get(node->parent); |
338 | of_node_put(node); | 381 | of_node_put(node); |
339 | read_unlock(&devtree_lock); | 382 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
340 | return parent; | 383 | return parent; |
341 | } | 384 | } |
342 | 385 | ||
@@ -352,14 +395,15 @@ struct device_node *of_get_next_child(const struct device_node *node, | |||
352 | struct device_node *prev) | 395 | struct device_node *prev) |
353 | { | 396 | { |
354 | struct device_node *next; | 397 | struct device_node *next; |
398 | unsigned long flags; | ||
355 | 399 | ||
356 | read_lock(&devtree_lock); | 400 | raw_spin_lock_irqsave(&devtree_lock, flags); |
357 | next = prev ? prev->sibling : node->child; | 401 | next = prev ? prev->sibling : node->child; |
358 | for (; next; next = next->sibling) | 402 | for (; next; next = next->sibling) |
359 | if (of_node_get(next)) | 403 | if (of_node_get(next)) |
360 | break; | 404 | break; |
361 | of_node_put(prev); | 405 | of_node_put(prev); |
362 | read_unlock(&devtree_lock); | 406 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
363 | return next; | 407 | return next; |
364 | } | 408 | } |
365 | EXPORT_SYMBOL(of_get_next_child); | 409 | EXPORT_SYMBOL(of_get_next_child); |
@@ -377,16 +421,16 @@ struct device_node *of_get_next_available_child(const struct device_node *node, | |||
377 | { | 421 | { |
378 | struct device_node *next; | 422 | struct device_node *next; |
379 | 423 | ||
380 | read_lock(&devtree_lock); | 424 | raw_spin_lock(&devtree_lock); |
381 | next = prev ? prev->sibling : node->child; | 425 | next = prev ? prev->sibling : node->child; |
382 | for (; next; next = next->sibling) { | 426 | for (; next; next = next->sibling) { |
383 | if (!of_device_is_available(next)) | 427 | if (!__of_device_is_available(next)) |
384 | continue; | 428 | continue; |
385 | if (of_node_get(next)) | 429 | if (of_node_get(next)) |
386 | break; | 430 | break; |
387 | } | 431 | } |
388 | of_node_put(prev); | 432 | of_node_put(prev); |
389 | read_unlock(&devtree_lock); | 433 | raw_spin_unlock(&devtree_lock); |
390 | return next; | 434 | return next; |
391 | } | 435 | } |
392 | EXPORT_SYMBOL(of_get_next_available_child); | 436 | EXPORT_SYMBOL(of_get_next_available_child); |
@@ -424,14 +468,15 @@ EXPORT_SYMBOL(of_get_child_by_name); | |||
424 | struct device_node *of_find_node_by_path(const char *path) | 468 | struct device_node *of_find_node_by_path(const char *path) |
425 | { | 469 | { |
426 | struct device_node *np = of_allnodes; | 470 | struct device_node *np = of_allnodes; |
471 | unsigned long flags; | ||
427 | 472 | ||
428 | read_lock(&devtree_lock); | 473 | raw_spin_lock_irqsave(&devtree_lock, flags); |
429 | for (; np; np = np->allnext) { | 474 | for (; np; np = np->allnext) { |
430 | if (np->full_name && (of_node_cmp(np->full_name, path) == 0) | 475 | if (np->full_name && (of_node_cmp(np->full_name, path) == 0) |
431 | && of_node_get(np)) | 476 | && of_node_get(np)) |
432 | break; | 477 | break; |
433 | } | 478 | } |
434 | read_unlock(&devtree_lock); | 479 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
435 | return np; | 480 | return np; |
436 | } | 481 | } |
437 | EXPORT_SYMBOL(of_find_node_by_path); | 482 | EXPORT_SYMBOL(of_find_node_by_path); |
@@ -451,15 +496,16 @@ struct device_node *of_find_node_by_name(struct device_node *from, | |||
451 | const char *name) | 496 | const char *name) |
452 | { | 497 | { |
453 | struct device_node *np; | 498 | struct device_node *np; |
499 | unsigned long flags; | ||
454 | 500 | ||
455 | read_lock(&devtree_lock); | 501 | raw_spin_lock_irqsave(&devtree_lock, flags); |
456 | np = from ? from->allnext : of_allnodes; | 502 | np = from ? from->allnext : of_allnodes; |
457 | for (; np; np = np->allnext) | 503 | for (; np; np = np->allnext) |
458 | if (np->name && (of_node_cmp(np->name, name) == 0) | 504 | if (np->name && (of_node_cmp(np->name, name) == 0) |
459 | && of_node_get(np)) | 505 | && of_node_get(np)) |
460 | break; | 506 | break; |
461 | of_node_put(from); | 507 | of_node_put(from); |
462 | read_unlock(&devtree_lock); | 508 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
463 | return np; | 509 | return np; |
464 | } | 510 | } |
465 | EXPORT_SYMBOL(of_find_node_by_name); | 511 | EXPORT_SYMBOL(of_find_node_by_name); |
@@ -480,15 +526,16 @@ struct device_node *of_find_node_by_type(struct device_node *from, | |||
480 | const char *type) | 526 | const char *type) |
481 | { | 527 | { |
482 | struct device_node *np; | 528 | struct device_node *np; |
529 | unsigned long flags; | ||
483 | 530 | ||
484 | read_lock(&devtree_lock); | 531 | raw_spin_lock_irqsave(&devtree_lock, flags); |
485 | np = from ? from->allnext : of_allnodes; | 532 | np = from ? from->allnext : of_allnodes; |
486 | for (; np; np = np->allnext) | 533 | for (; np; np = np->allnext) |
487 | if (np->type && (of_node_cmp(np->type, type) == 0) | 534 | if (np->type && (of_node_cmp(np->type, type) == 0) |
488 | && of_node_get(np)) | 535 | && of_node_get(np)) |
489 | break; | 536 | break; |
490 | of_node_put(from); | 537 | of_node_put(from); |
491 | read_unlock(&devtree_lock); | 538 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
492 | return np; | 539 | return np; |
493 | } | 540 | } |
494 | EXPORT_SYMBOL(of_find_node_by_type); | 541 | EXPORT_SYMBOL(of_find_node_by_type); |
@@ -511,18 +558,20 @@ struct device_node *of_find_compatible_node(struct device_node *from, | |||
511 | const char *type, const char *compatible) | 558 | const char *type, const char *compatible) |
512 | { | 559 | { |
513 | struct device_node *np; | 560 | struct device_node *np; |
561 | unsigned long flags; | ||
514 | 562 | ||
515 | read_lock(&devtree_lock); | 563 | raw_spin_lock_irqsave(&devtree_lock, flags); |
516 | np = from ? from->allnext : of_allnodes; | 564 | np = from ? from->allnext : of_allnodes; |
517 | for (; np; np = np->allnext) { | 565 | for (; np; np = np->allnext) { |
518 | if (type | 566 | if (type |
519 | && !(np->type && (of_node_cmp(np->type, type) == 0))) | 567 | && !(np->type && (of_node_cmp(np->type, type) == 0))) |
520 | continue; | 568 | continue; |
521 | if (of_device_is_compatible(np, compatible) && of_node_get(np)) | 569 | if (__of_device_is_compatible(np, compatible) && |
570 | of_node_get(np)) | ||
522 | break; | 571 | break; |
523 | } | 572 | } |
524 | of_node_put(from); | 573 | of_node_put(from); |
525 | read_unlock(&devtree_lock); | 574 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
526 | return np; | 575 | return np; |
527 | } | 576 | } |
528 | EXPORT_SYMBOL(of_find_compatible_node); | 577 | EXPORT_SYMBOL(of_find_compatible_node); |
@@ -544,8 +593,9 @@ struct device_node *of_find_node_with_property(struct device_node *from, | |||
544 | { | 593 | { |
545 | struct device_node *np; | 594 | struct device_node *np; |
546 | struct property *pp; | 595 | struct property *pp; |
596 | unsigned long flags; | ||
547 | 597 | ||
548 | read_lock(&devtree_lock); | 598 | raw_spin_lock_irqsave(&devtree_lock, flags); |
549 | np = from ? from->allnext : of_allnodes; | 599 | np = from ? from->allnext : of_allnodes; |
550 | for (; np; np = np->allnext) { | 600 | for (; np; np = np->allnext) { |
551 | for (pp = np->properties; pp; pp = pp->next) { | 601 | for (pp = np->properties; pp; pp = pp->next) { |
@@ -557,20 +607,14 @@ struct device_node *of_find_node_with_property(struct device_node *from, | |||
557 | } | 607 | } |
558 | out: | 608 | out: |
559 | of_node_put(from); | 609 | of_node_put(from); |
560 | read_unlock(&devtree_lock); | 610 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
561 | return np; | 611 | return np; |
562 | } | 612 | } |
563 | EXPORT_SYMBOL(of_find_node_with_property); | 613 | EXPORT_SYMBOL(of_find_node_with_property); |
564 | 614 | ||
565 | /** | 615 | static |
566 | * of_match_node - Tell if an device_node has a matching of_match structure | 616 | const struct of_device_id *__of_match_node(const struct of_device_id *matches, |
567 | * @matches: array of of device match structures to search in | 617 | const struct device_node *node) |
568 | * @node: the of device structure to match against | ||
569 | * | ||
570 | * Low level utility function used by device matching. | ||
571 | */ | ||
572 | const struct of_device_id *of_match_node(const struct of_device_id *matches, | ||
573 | const struct device_node *node) | ||
574 | { | 618 | { |
575 | if (!matches) | 619 | if (!matches) |
576 | return NULL; | 620 | return NULL; |
@@ -584,14 +628,33 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches, | |||
584 | match &= node->type | 628 | match &= node->type |
585 | && !strcmp(matches->type, node->type); | 629 | && !strcmp(matches->type, node->type); |
586 | if (matches->compatible[0]) | 630 | if (matches->compatible[0]) |
587 | match &= of_device_is_compatible(node, | 631 | match &= __of_device_is_compatible(node, |
588 | matches->compatible); | 632 | matches->compatible); |
589 | if (match) | 633 | if (match) |
590 | return matches; | 634 | return matches; |
591 | matches++; | 635 | matches++; |
592 | } | 636 | } |
593 | return NULL; | 637 | return NULL; |
594 | } | 638 | } |
639 | |||
640 | /** | ||
641 | * of_match_node - Tell if an device_node has a matching of_match structure | ||
642 | * @matches: array of of device match structures to search in | ||
643 | * @node: the of device structure to match against | ||
644 | * | ||
645 | * Low level utility function used by device matching. | ||
646 | */ | ||
647 | const struct of_device_id *of_match_node(const struct of_device_id *matches, | ||
648 | const struct device_node *node) | ||
649 | { | ||
650 | const struct of_device_id *match; | ||
651 | unsigned long flags; | ||
652 | |||
653 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
654 | match = __of_match_node(matches, node); | ||
655 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
656 | return match; | ||
657 | } | ||
595 | EXPORT_SYMBOL(of_match_node); | 658 | EXPORT_SYMBOL(of_match_node); |
596 | 659 | ||
597 | /** | 660 | /** |
@@ -612,21 +675,24 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from, | |||
612 | const struct of_device_id **match) | 675 | const struct of_device_id **match) |
613 | { | 676 | { |
614 | struct device_node *np; | 677 | struct device_node *np; |
678 | const struct of_device_id *m; | ||
679 | unsigned long flags; | ||
615 | 680 | ||
616 | if (match) | 681 | if (match) |
617 | *match = NULL; | 682 | *match = NULL; |
618 | 683 | ||
619 | read_lock(&devtree_lock); | 684 | raw_spin_lock_irqsave(&devtree_lock, flags); |
620 | np = from ? from->allnext : of_allnodes; | 685 | np = from ? from->allnext : of_allnodes; |
621 | for (; np; np = np->allnext) { | 686 | for (; np; np = np->allnext) { |
622 | if (of_match_node(matches, np) && of_node_get(np)) { | 687 | m = __of_match_node(matches, np); |
688 | if (m && of_node_get(np)) { | ||
623 | if (match) | 689 | if (match) |
624 | *match = matches; | 690 | *match = m; |
625 | break; | 691 | break; |
626 | } | 692 | } |
627 | } | 693 | } |
628 | of_node_put(from); | 694 | of_node_put(from); |
629 | read_unlock(&devtree_lock); | 695 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
630 | return np; | 696 | return np; |
631 | } | 697 | } |
632 | EXPORT_SYMBOL(of_find_matching_node_and_match); | 698 | EXPORT_SYMBOL(of_find_matching_node_and_match); |
@@ -669,12 +735,12 @@ struct device_node *of_find_node_by_phandle(phandle handle) | |||
669 | { | 735 | { |
670 | struct device_node *np; | 736 | struct device_node *np; |
671 | 737 | ||
672 | read_lock(&devtree_lock); | 738 | raw_spin_lock(&devtree_lock); |
673 | for (np = of_allnodes; np; np = np->allnext) | 739 | for (np = of_allnodes; np; np = np->allnext) |
674 | if (np->phandle == handle) | 740 | if (np->phandle == handle) |
675 | break; | 741 | break; |
676 | of_node_get(np); | 742 | of_node_get(np); |
677 | read_unlock(&devtree_lock); | 743 | raw_spin_unlock(&devtree_lock); |
678 | return np; | 744 | return np; |
679 | } | 745 | } |
680 | EXPORT_SYMBOL(of_find_node_by_phandle); | 746 | EXPORT_SYMBOL(of_find_node_by_phandle); |
@@ -1025,12 +1091,13 @@ EXPORT_SYMBOL(of_parse_phandle); | |||
1025 | * To get a device_node of the `node2' node you may call this: | 1091 | * To get a device_node of the `node2' node you may call this: |
1026 | * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); | 1092 | * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); |
1027 | */ | 1093 | */ |
1028 | int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, | 1094 | static int __of_parse_phandle_with_args(const struct device_node *np, |
1029 | const char *cells_name, int index, | 1095 | const char *list_name, |
1030 | struct of_phandle_args *out_args) | 1096 | const char *cells_name, int index, |
1097 | struct of_phandle_args *out_args) | ||
1031 | { | 1098 | { |
1032 | const __be32 *list, *list_end; | 1099 | const __be32 *list, *list_end; |
1033 | int size, cur_index = 0; | 1100 | int rc = 0, size, cur_index = 0; |
1034 | uint32_t count = 0; | 1101 | uint32_t count = 0; |
1035 | struct device_node *node = NULL; | 1102 | struct device_node *node = NULL; |
1036 | phandle phandle; | 1103 | phandle phandle; |
@@ -1043,6 +1110,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1043 | 1110 | ||
1044 | /* Loop over the phandles until all the requested entry is found */ | 1111 | /* Loop over the phandles until all the requested entry is found */ |
1045 | while (list < list_end) { | 1112 | while (list < list_end) { |
1113 | rc = -EINVAL; | ||
1046 | count = 0; | 1114 | count = 0; |
1047 | 1115 | ||
1048 | /* | 1116 | /* |
@@ -1059,13 +1127,13 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1059 | if (!node) { | 1127 | if (!node) { |
1060 | pr_err("%s: could not find phandle\n", | 1128 | pr_err("%s: could not find phandle\n", |
1061 | np->full_name); | 1129 | np->full_name); |
1062 | break; | 1130 | goto err; |
1063 | } | 1131 | } |
1064 | if (of_property_read_u32(node, cells_name, &count)) { | 1132 | if (of_property_read_u32(node, cells_name, &count)) { |
1065 | pr_err("%s: could not get %s for %s\n", | 1133 | pr_err("%s: could not get %s for %s\n", |
1066 | np->full_name, cells_name, | 1134 | np->full_name, cells_name, |
1067 | node->full_name); | 1135 | node->full_name); |
1068 | break; | 1136 | goto err; |
1069 | } | 1137 | } |
1070 | 1138 | ||
1071 | /* | 1139 | /* |
@@ -1075,7 +1143,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1075 | if (list + count > list_end) { | 1143 | if (list + count > list_end) { |
1076 | pr_err("%s: arguments longer than property\n", | 1144 | pr_err("%s: arguments longer than property\n", |
1077 | np->full_name); | 1145 | np->full_name); |
1078 | break; | 1146 | goto err; |
1079 | } | 1147 | } |
1080 | } | 1148 | } |
1081 | 1149 | ||
@@ -1085,9 +1153,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1085 | * index matches, then fill the out_args structure and return, | 1153 | * index matches, then fill the out_args structure and return, |
1086 | * or return -ENOENT for an empty entry. | 1154 | * or return -ENOENT for an empty entry. |
1087 | */ | 1155 | */ |
1156 | rc = -ENOENT; | ||
1088 | if (cur_index == index) { | 1157 | if (cur_index == index) { |
1089 | if (!phandle) | 1158 | if (!phandle) |
1090 | return -ENOENT; | 1159 | goto err; |
1091 | 1160 | ||
1092 | if (out_args) { | 1161 | if (out_args) { |
1093 | int i; | 1162 | int i; |
@@ -1098,6 +1167,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1098 | for (i = 0; i < count; i++) | 1167 | for (i = 0; i < count; i++) |
1099 | out_args->args[i] = be32_to_cpup(list++); | 1168 | out_args->args[i] = be32_to_cpup(list++); |
1100 | } | 1169 | } |
1170 | |||
1171 | /* Found it! return success */ | ||
1172 | if (node) | ||
1173 | of_node_put(node); | ||
1101 | return 0; | 1174 | return 0; |
1102 | } | 1175 | } |
1103 | 1176 | ||
@@ -1107,13 +1180,51 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1107 | cur_index++; | 1180 | cur_index++; |
1108 | } | 1181 | } |
1109 | 1182 | ||
1110 | /* Loop exited without finding a valid entry; return an error */ | 1183 | /* |
1184 | * Unlock node before returning result; will be one of: | ||
1185 | * -ENOENT : index is for empty phandle | ||
1186 | * -EINVAL : parsing error on data | ||
1187 | * [1..n] : Number of phandle (count mode; when index = -1) | ||
1188 | */ | ||
1189 | rc = index < 0 ? cur_index : -ENOENT; | ||
1190 | err: | ||
1111 | if (node) | 1191 | if (node) |
1112 | of_node_put(node); | 1192 | of_node_put(node); |
1113 | return -EINVAL; | 1193 | return rc; |
1194 | } | ||
1195 | |||
1196 | int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, | ||
1197 | const char *cells_name, int index, | ||
1198 | struct of_phandle_args *out_args) | ||
1199 | { | ||
1200 | if (index < 0) | ||
1201 | return -EINVAL; | ||
1202 | return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args); | ||
1114 | } | 1203 | } |
1115 | EXPORT_SYMBOL(of_parse_phandle_with_args); | 1204 | EXPORT_SYMBOL(of_parse_phandle_with_args); |
1116 | 1205 | ||
1206 | /** | ||
1207 | * of_count_phandle_with_args() - Find the number of phandles references in a property | ||
1208 | * @np: pointer to a device tree node containing a list | ||
1209 | * @list_name: property name that contains a list | ||
1210 | * @cells_name: property name that specifies phandles' arguments count | ||
1211 | * | ||
1212 | * Returns the number of phandle + argument tuples within a property. It | ||
1213 | * is a typical pattern to encode a list of phandle and variable | ||
1214 | * arguments into a single property. The number of arguments is encoded | ||
1215 | * by a property in the phandle-target node. For example, a gpios | ||
1216 | * property would contain a list of GPIO specifies consisting of a | ||
1217 | * phandle and 1 or more arguments. The number of arguments are | ||
1218 | * determined by the #gpio-cells property in the node pointed to by the | ||
1219 | * phandle. | ||
1220 | */ | ||
1221 | int of_count_phandle_with_args(const struct device_node *np, const char *list_name, | ||
1222 | const char *cells_name) | ||
1223 | { | ||
1224 | return __of_parse_phandle_with_args(np, list_name, cells_name, -1, NULL); | ||
1225 | } | ||
1226 | EXPORT_SYMBOL(of_count_phandle_with_args); | ||
1227 | |||
1117 | #if defined(CONFIG_OF_DYNAMIC) | 1228 | #if defined(CONFIG_OF_DYNAMIC) |
1118 | static int of_property_notify(int action, struct device_node *np, | 1229 | static int of_property_notify(int action, struct device_node *np, |
1119 | struct property *prop) | 1230 | struct property *prop) |
@@ -1146,18 +1257,18 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
1146 | return rc; | 1257 | return rc; |
1147 | 1258 | ||
1148 | prop->next = NULL; | 1259 | prop->next = NULL; |
1149 | write_lock_irqsave(&devtree_lock, flags); | 1260 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1150 | next = &np->properties; | 1261 | next = &np->properties; |
1151 | while (*next) { | 1262 | while (*next) { |
1152 | if (strcmp(prop->name, (*next)->name) == 0) { | 1263 | if (strcmp(prop->name, (*next)->name) == 0) { |
1153 | /* duplicate ! don't insert it */ | 1264 | /* duplicate ! don't insert it */ |
1154 | write_unlock_irqrestore(&devtree_lock, flags); | 1265 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1155 | return -1; | 1266 | return -1; |
1156 | } | 1267 | } |
1157 | next = &(*next)->next; | 1268 | next = &(*next)->next; |
1158 | } | 1269 | } |
1159 | *next = prop; | 1270 | *next = prop; |
1160 | write_unlock_irqrestore(&devtree_lock, flags); | 1271 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1161 | 1272 | ||
1162 | #ifdef CONFIG_PROC_DEVICETREE | 1273 | #ifdef CONFIG_PROC_DEVICETREE |
1163 | /* try to add to proc as well if it was initialized */ | 1274 | /* try to add to proc as well if it was initialized */ |
@@ -1187,7 +1298,7 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1187 | if (rc) | 1298 | if (rc) |
1188 | return rc; | 1299 | return rc; |
1189 | 1300 | ||
1190 | write_lock_irqsave(&devtree_lock, flags); | 1301 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1191 | next = &np->properties; | 1302 | next = &np->properties; |
1192 | while (*next) { | 1303 | while (*next) { |
1193 | if (*next == prop) { | 1304 | if (*next == prop) { |
@@ -1200,7 +1311,7 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1200 | } | 1311 | } |
1201 | next = &(*next)->next; | 1312 | next = &(*next)->next; |
1202 | } | 1313 | } |
1203 | write_unlock_irqrestore(&devtree_lock, flags); | 1314 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1204 | 1315 | ||
1205 | if (!found) | 1316 | if (!found) |
1206 | return -ENODEV; | 1317 | return -ENODEV; |
@@ -1240,7 +1351,7 @@ int of_update_property(struct device_node *np, struct property *newprop) | |||
1240 | if (!oldprop) | 1351 | if (!oldprop) |
1241 | return of_add_property(np, newprop); | 1352 | return of_add_property(np, newprop); |
1242 | 1353 | ||
1243 | write_lock_irqsave(&devtree_lock, flags); | 1354 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1244 | next = &np->properties; | 1355 | next = &np->properties; |
1245 | while (*next) { | 1356 | while (*next) { |
1246 | if (*next == oldprop) { | 1357 | if (*next == oldprop) { |
@@ -1254,7 +1365,7 @@ int of_update_property(struct device_node *np, struct property *newprop) | |||
1254 | } | 1365 | } |
1255 | next = &(*next)->next; | 1366 | next = &(*next)->next; |
1256 | } | 1367 | } |
1257 | write_unlock_irqrestore(&devtree_lock, flags); | 1368 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1258 | 1369 | ||
1259 | if (!found) | 1370 | if (!found) |
1260 | return -ENODEV; | 1371 | return -ENODEV; |
@@ -1327,12 +1438,12 @@ int of_attach_node(struct device_node *np) | |||
1327 | if (rc) | 1438 | if (rc) |
1328 | return rc; | 1439 | return rc; |
1329 | 1440 | ||
1330 | write_lock_irqsave(&devtree_lock, flags); | 1441 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1331 | np->sibling = np->parent->child; | 1442 | np->sibling = np->parent->child; |
1332 | np->allnext = of_allnodes; | 1443 | np->allnext = of_allnodes; |
1333 | np->parent->child = np; | 1444 | np->parent->child = np; |
1334 | of_allnodes = np; | 1445 | of_allnodes = np; |
1335 | write_unlock_irqrestore(&devtree_lock, flags); | 1446 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1336 | 1447 | ||
1337 | of_add_proc_dt_entry(np); | 1448 | of_add_proc_dt_entry(np); |
1338 | return 0; | 1449 | return 0; |
@@ -1375,17 +1486,17 @@ int of_detach_node(struct device_node *np) | |||
1375 | if (rc) | 1486 | if (rc) |
1376 | return rc; | 1487 | return rc; |
1377 | 1488 | ||
1378 | write_lock_irqsave(&devtree_lock, flags); | 1489 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1379 | 1490 | ||
1380 | if (of_node_check_flag(np, OF_DETACHED)) { | 1491 | if (of_node_check_flag(np, OF_DETACHED)) { |
1381 | /* someone already detached it */ | 1492 | /* someone already detached it */ |
1382 | write_unlock_irqrestore(&devtree_lock, flags); | 1493 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1383 | return rc; | 1494 | return rc; |
1384 | } | 1495 | } |
1385 | 1496 | ||
1386 | parent = np->parent; | 1497 | parent = np->parent; |
1387 | if (!parent) { | 1498 | if (!parent) { |
1388 | write_unlock_irqrestore(&devtree_lock, flags); | 1499 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1389 | return rc; | 1500 | return rc; |
1390 | } | 1501 | } |
1391 | 1502 | ||
@@ -1412,7 +1523,7 @@ int of_detach_node(struct device_node *np) | |||
1412 | } | 1523 | } |
1413 | 1524 | ||
1414 | of_node_set_flag(np, OF_DETACHED); | 1525 | of_node_set_flag(np, OF_DETACHED); |
1415 | write_unlock_irqrestore(&devtree_lock, flags); | 1526 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1416 | 1527 | ||
1417 | of_remove_proc_dt_entry(np); | 1528 | of_remove_proc_dt_entry(np); |
1418 | return rc; | 1529 | return rc; |