summaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-02-11 21:15:32 (GMT)
committerScott Wood <scottwood@freescale.com>2013-04-04 22:09:05 (GMT)
commit10188d8cc7d3010388e5d0259fe26670228139d3 (patch)
tree8d24e2372ae55e5100832a0da113df555eec6537 /drivers/of
parentd0b25b2988e9b836b81a1a80d1fedf044b22b65e (diff)
downloadlinux-fsl-qoriq-10188d8cc7d3010388e5d0259fe26670228139d3.tar.xz
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 662e009..ec2fd1f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -307,19 +307,19 @@ int of_machine_is_compatible(const char *compat)
EXPORT_SYMBOL(of_machine_is_compatible);
/**
- * of_device_is_available - check if a device is available for use
+ * __of_device_is_available - check if a device is available for use
*
- * @device: Node to check for availability
+ * @device: Node to check for availability, with locks already held
*
* Returns 1 if the status property is absent or set to "okay" or "ok",
* 0 otherwise
*/
-int of_device_is_available(const struct device_node *device)
+static int __of_device_is_available(const struct device_node *device)
{
const char *status;
int statlen;
- status = of_get_property(device, "status", &statlen);
+ status = __of_get_property(device, "status", &statlen);
if (status == NULL)
return 1;
@@ -330,6 +330,26 @@ int of_device_is_available(const struct device_node *device)
return 0;
}
+
+/**
+ * of_device_is_available - check if a device is available for use
+ *
+ * @device: Node to check for availability
+ *
+ * Returns 1 if the status property is absent or set to "okay" or "ok",
+ * 0 otherwise
+ */
+int of_device_is_available(const struct device_node *device)
+{
+ unsigned long flags;
+ int res;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ res = __of_device_is_available(device);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return res;
+
+}
EXPORT_SYMBOL(of_device_is_available);
/**
@@ -421,7 +441,7 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
raw_spin_lock(&devtree_lock);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
- if (!of_device_is_available(next))
+ if (!__of_device_is_available(next))
continue;
if (of_node_get(next))
break;