Add a function to find the next node that has a given property,
whatever its value, walking the tree in depth-first order. This is
needed by the MTD virtual concat support to find all partitions with a
"part-concat-next" property.

Also export ofnode_dfs_next(), which it uses to step through the tree,
and add tests for both.

Signed-off-by: Padmarao Begari <[email protected]>
---
Changes in v2:
- New patch: move the DFS helpers from the MTD driver to ofnode and add
  tests

checkpatch reports 'Please use a blank line after
function/struct/union/enum declarations' for each DM_TEST() line.
DM_TEST() is placed directly after its test function, as in the other
tests.

 drivers/core/ofnode.c | 31 ++++++++++++++++++++++++
 include/dm/ofnode.h   | 23 ++++++++++++++++++
 test/dm/ofnode.c      | 55 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+)

diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index b5d13c43db1..29d2041086a 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -1791,6 +1791,37 @@ ofnode ofnode_by_prop_value(ofnode from, const char 
*propname,
        }
 }
 
+ofnode ofnode_dfs_next(ofnode node)
+{
+       ofnode child, sibling;
+
+       child = ofnode_first_subnode(node);
+       if (ofnode_valid(child))
+               return child;
+
+       while (ofnode_valid(node)) {
+               sibling = ofnode_next_subnode(node);
+               if (ofnode_valid(sibling))
+                       return sibling;
+               node = ofnode_get_parent(node);
+       }
+
+       return ofnode_null();
+}
+
+ofnode ofnode_find_node_with_property(ofnode from, const char *propname)
+{
+       ofnode node;
+
+       node = ofnode_valid(from) ? ofnode_dfs_next(from) : ofnode_root();
+       for (; ofnode_valid(node); node = ofnode_dfs_next(node)) {
+               if (ofnode_has_property(node, propname))
+                       return node;
+       }
+
+       return ofnode_null();
+}
+
 int ofnode_write_prop(ofnode node, const char *propname, const void *value,
                      int len, bool copy)
 {
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index c905e86b283..5cd378e9735 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -1488,6 +1488,29 @@ ofnode ofnode_by_compatible(ofnode from, const char 
*compat);
 ofnode ofnode_by_prop_value(ofnode from, const char *propname,
                            const void *propval, int proplen);
 
+/**
+ * ofnode_dfs_next() - Get the next node in depth-first order
+ *
+ * Return the first subnode of @node if it has one, otherwise its next sibling,
+ * otherwise the next sibling of the nearest parent that has one.
+ *
+ * @node: valid node to start from
+ * Return: next node, or ofnode_null() at the end of the tree
+ */
+ofnode ofnode_dfs_next(ofnode node);
+
+/**
+ * ofnode_find_node_with_property() - Find the next node with a property
+ *
+ * Walk the tree in depth-first order, starting after @from, and return the
+ * first node that has a property called @propname, whatever its value.
+ *
+ * @from: ofnode to start after (use ofnode_null() to start at the root)
+ * @propname: name of the property to look for
+ * Return: ofnode found, or ofnode_null() if none
+ */
+ofnode ofnode_find_node_with_property(ofnode from, const char *propname);
+
 /**
  * ofnode_for_each_subnode() - iterate over all subnodes of a parent
  *
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index 0f60c2a6281..4fb9bf8ce6e 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -212,6 +212,61 @@ static int dm_test_ofnode_by_prop_value_ot(struct 
unit_test_state *uts)
 DM_TEST(dm_test_ofnode_by_prop_value_ot,
        UTF_SCAN_FDT | UTF_OTHER_FDT);
 
+/* test ofnode_dfs_next() */
+static int dm_test_ofnode_dfs_next(struct unit_test_state *uts)
+{
+       ofnode node;
+
+       /* down into the first subnode */
+       node = ofnode_dfs_next(ofnode_path("/some-bus"));
+       ut_asserteq_str("c-test@5", ofnode_get_name(node));
+
+       /* across to the next sibling */
+       node = ofnode_dfs_next(node);
+       ut_asserteq_str("c-test@0", ofnode_get_name(node));
+
+       /* back up to the parent's next sibling */
+       node = ofnode_dfs_next(ofnode_path("/buttons/btn2"));
+       ut_asserteq_str("buttons2", ofnode_get_name(node));
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_dfs_next, UTF_SCAN_FDT);
+
+/* test ofnode_find_node_with_property() */
+static int dm_test_ofnode_find_node_with_property(struct unit_test_state *uts)
+{
+       static const char *const expect[] = {
+               "a-test", "b-test", "some-bus", "c-test@5", "c-test@0",
+               "c-test@1",
+       };
+       ofnode node = ofnode_null();
+       int i;
+
+       /*
+        * Nodes are found in depth-first order, whatever the value. Other
+        * tests may add nodes to /some-bus in the live tree, so stop there.
+        */
+       for (i = 0; i < ARRAY_SIZE(expect); i++) {
+               node = ofnode_find_node_with_property(node, "ping-expect");
+               ut_assert(ofnode_valid(node));
+               ut_asserteq_str(expect[i], ofnode_get_name(node));
+       }
+
+       /* the search can start from any node and runs to the end of the tree */
+       node = ofnode_find_node_with_property(ofnode_path("/d-test"),
+                                             "ping-expect");
+       ut_asserteq_str("e-test", ofnode_get_name(node));
+       node = ofnode_find_node_with_property(node, "ping-expect");
+       ut_assert(!ofnode_valid(node));
+
+       node = ofnode_find_node_with_property(ofnode_null(), "no-such-prop");
+       ut_assert(!ofnode_valid(node));
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_find_node_with_property, UTF_SCAN_FDT);
+
 /* test ofnode_read_fmap_entry() */
 static int dm_test_ofnode_fmap(struct unit_test_state *uts)
 {
-- 
2.34.1

Reply via email to