@@ -815,11 +815,26 @@ struct fwnode_handle *device_get_next_child_node(const struct device *dev,
}
/* Try to find a child in primary fwnode */
- next = fwnode_get_next_child_node(fwnode, child);
- if (next)
- return next;
+ if (!child || fwnode_get_parent(child) == fwnode) {
+ next = fwnode_get_next_child_node(fwnode, child);
+ if (next)
+ return next;
+ /*
+ * We ran out of children in primary - reset the child
+ * node to start from the beginning when scanning secondary
+ * node.
+ */
+ child = NULL;
+ }
/* When no more children in primary, continue with secondary */
+
+ if (IS_ERR_OR_NULL(fwnode->secondary) ||
+ (child && fwnode_get_parent(child) != fwnode->secondary)) {
+ fwnode_handle_put(child);
+ return NULL;
+ }
+
return fwnode_get_next_child_node(fwnode->secondary, child);
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
fwnode_get_next_child_node() always drops reference to the node passed as the "child" argument, which makes "child" pointer no longer valid and we can not use it to scan the secondary node in case there are no more children in primary one. Also, it is not obvious whether it is safe to pass children of the secondary node to fwnode_get_next_child_node() called on the primary node in subsequent calls to device_get_next_child_node(). Fix the issue by checking whether the child node passed in is indeed a child of primary or secondary node, and do not call fwnode_get_next_child_node() for the wrong parent node. Also set the "child" to NULL after unsuccessful call to fwnode_get_next_child_node() on primary node to make sure secondary node's children are scanned from the beginning. Fixes: 114dbb4fa7c4 ("drivers property: When no children in primary, try secondary") Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> --- drivers/base/property.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)