aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-02-11 16:15:32 -0500
committerGrant Likely <grant.likely@secretlab.ca>2013-02-13 05:05:24 -0500
commitc31a0c052205e3ec24efc3fe18ef70c3e913f2d4 (patch)
tree0c9a9bfea6fd494caefd714fb016a863fc253adf /drivers/of
parentbfc4a58986ba3934bb256ef3567aeeab262aa959 (diff)
of: fix recursive locking in of_get_next_available_child()
of_get_next_available_child() acquires devtree_lock, then calls of_device_is_available() which calls of_get_property() which calls of_find_property() which tries to re-acquire devtree_lock, thus causing deadlock. To avoid this, create a new __of_device_is_available() which calls __of_get_property() instead, which calls __of_find_property(), which does not take the lock,. Update of_get_next_available_child() to call the new __of_device_is_available() since it already owns the lock. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/base.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index e8d65aff8639..f7a87ce1b480 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -290,19 +290,19 @@ int of_machine_is_compatible(const char *compat)
290EXPORT_SYMBOL(of_machine_is_compatible); 290EXPORT_SYMBOL(of_machine_is_compatible);
291 291
292/** 292/**
293 * 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
294 * 294 *
295 * @device: Node to check for availability 295 * @device: Node to check for availability, with locks already held
296 * 296 *
297 * 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",
298 * 0 otherwise 298 * 0 otherwise
299 */ 299 */
300int of_device_is_available(const struct device_node *device) 300static int __of_device_is_available(const struct device_node *device)
301{ 301{
302 const char *status; 302 const char *status;
303 int statlen; 303 int statlen;
304 304
305 status = of_get_property(device, "status", &statlen); 305 status = __of_get_property(device, "status", &statlen);
306 if (status == NULL) 306 if (status == NULL)
307 return 1; 307 return 1;
308 308
@@ -313,6 +313,26 @@ int of_device_is_available(const struct device_node *device)
313 313
314 return 0; 314 return 0;
315} 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 */
325int 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}
316EXPORT_SYMBOL(of_device_is_available); 336EXPORT_SYMBOL(of_device_is_available);
317 337
318/** 338/**
@@ -404,7 +424,7 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
404 raw_spin_lock(&devtree_lock); 424 raw_spin_lock(&devtree_lock);
405 next = prev ? prev->sibling : node->child; 425 next = prev ? prev->sibling : node->child;
406 for (; next; next = next->sibling) { 426 for (; next; next = next->sibling) {
407 if (!of_device_is_available(next)) 427 if (!__of_device_is_available(next))
408 continue; 428 continue;
409 if (of_node_get(next)) 429 if (of_node_get(next))
410 break; 430 break;