From: Mehmet Fide <[email protected]>

The sequence number an aliases entry gives a node can only be looked up
for a device, through dev_read_alias_seq(). A driver that has to know
the number of a node it does not own, one it reached through a phandle
for instance, has no livetree call for it and is left with fdtdec.

Move the body of dev_read_alias_seq() to the ofnode level and let both
of its variants call it. The flat lookup reads the tree the node belongs
to instead of gd->fdt_blob. The live lookup covered the control tree
only, as of_alias_scan() builds its table from that tree; a node of
another tree is now looked up in the /aliases node of its own tree. The
stem must match the alias exactly, which the previous patch makes the
flat lookup do as well.

Tests check the lookup on the live and on the flat tree, with a stem
that is only a prefix of an alias, and on another tree.

Signed-off-by: Mehmet Fide <[email protected]>
---

Notes:
    Changes in v6:
    - none
    
    Changes in v5:
    - the stem must match the alias exactly, as patch 1 makes the flat
      lookup do; the kernel-doc says so and the test checks a prefix stem
    - a node outside the control tree is looked up in the /aliases node of
      its own tree on the live tree too; a test uses the other tree of the
      sandbox tests, which gains two aliases
    - the checkpatch note moved here: the warnings are in the body the patch
      moves, which is unchanged, and the check is the DM_TEST layout every
      test in test/dm/ofnode.c uses
    
    Changes in v4:
    - added a test, run on the live and on the flat tree
    - the kernel-doc no longer promises -ENOENT for a missing alias, the
      live tree returns -ENODEV

 arch/sandbox/dts/other.dts |  5 ++++
 drivers/core/of_access.c   | 42 ++++++++++++++++++++++++++++++++
 drivers/core/ofnode.c      | 20 ++++++++++++++++
 drivers/core/read.c        | 20 ++--------------
 include/dm/of_access.h     |  7 ++++--
 include/dm/ofnode.h        | 16 +++++++++++++
 include/dm/read.h          |  8 ++-----
 test/dm/ofnode.c           | 49 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 141 insertions(+), 26 deletions(-)

diff --git a/arch/sandbox/dts/other.dts b/arch/sandbox/dts/other.dts
index 515d6348b3f..50597e2d570 100644
--- a/arch/sandbox/dts/other.dts
+++ b/arch/sandbox/dts/other.dts
@@ -15,6 +15,11 @@
        #address-cells = <1>;
        #size-cells = <1>;
 
+       aliases {
+               other-test0 = "/node";
+               other-test1 = "/node/subnode";
+       };
+
        node {
                other-phandle = <&target>;
 
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index f910cc9a31b..2d19dfec25c 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -971,11 +971,53 @@ int of_alias_scan(void)
        return 0;
 }
 
+/**
+ * of_tree_alias_get_id() - Get an alias id from the /aliases node of a tree
+ *
+ * The lookup table covers the control tree only; a node of another tree is
+ * looked up in the /aliases node of that tree.
+ *
+ * @root:      Root of the tree the node belongs to
+ * @np:                Pointer to the given device_node
+ * @stem:      Alias stem of the given device_node
+ * Return: alias ID, if found, else -ENODEV
+ */
+static int of_tree_alias_get_id(struct device_node *root,
+                               const struct device_node *np, const char *stem)
+{
+       const struct device_node *aliases;
+       int stem_len = strlen(stem);
+       struct property *pp;
+
+       aliases = of_find_node_opts_by_path(root, "/aliases", NULL);
+       if (!aliases)
+               return -ENODEV;
+
+       for_each_property_of_node(aliases, pp) {
+               const char *num = pp->name + stem_len;
+               ulong id;
+
+               if (strncmp(pp->name, stem, stem_len) || !isdigit(*num) ||
+                   strict_strtoul(num, 10, &id))
+                       continue;
+               if (of_find_node_opts_by_path(root, pp->value, NULL) == np)
+                       return id;
+       }
+
+       return -ENODEV;
+}
+
 int of_alias_get_id(const struct device_node *np, const char *stem)
 {
+       struct device_node *root = (struct device_node *)np;
        struct alias_prop *app;
        int id = -ENODEV;
 
+       while (root->parent)
+               root = root->parent;
+       if (root != gd->of_root)
+               return of_tree_alias_get_id(root, np, stem);
+
        mutex_lock(&of_mutex);
        list_for_each_entry(app, &aliases_lookup, link) {
                if (strcmp(app->stem, stem) != 0)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index b5d13c43db1..81d91ce5476 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -1233,6 +1233,26 @@ ofnode ofnode_get_aliases_node(const char *name)
        return ofnode_path(prop);
 }
 
+int ofnode_get_alias_seq(ofnode node, const char *stem, int *seqp)
+{
+       int ret = -ENOTSUPP;
+
+       if (ofnode_is_np(node)) {
+               ret = of_alias_get_id(ofnode_to_np(node), stem);
+               if (ret >= 0) {
+                       *seqp = ret;
+                       ret = 0;
+               }
+       } else {
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+               ret = fdtdec_get_alias_seq(ofnode_to_fdt(node), stem,
+                                          ofnode_to_offset(node), seqp);
+#endif
+       }
+
+       return ret;
+}
+
 int ofnode_get_child_count(ofnode parent)
 {
        ofnode child;
diff --git a/drivers/core/read.c b/drivers/core/read.c
index ba48862f44b..985f6128d97 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -356,24 +356,8 @@ const void *dev_read_prop_by_prop(struct ofprop *prop,
 
 int dev_read_alias_seq(const struct udevice *dev, int *devnump)
 {
-       ofnode node = dev_ofnode(dev);
-       const char *uc_name = dev->uclass->uc_drv->name;
-       int ret = -ENOTSUPP;
-
-       if (ofnode_is_np(node)) {
-               ret = of_alias_get_id(ofnode_to_np(node), uc_name);
-               if (ret >= 0) {
-                       *devnump = ret;
-                       ret = 0;
-               }
-       } else {
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-               ret = fdtdec_get_alias_seq(gd->fdt_blob, uc_name,
-                                          ofnode_to_offset(node), devnump);
-#endif
-       }
-
-       return ret;
+       return ofnode_get_alias_seq(dev_ofnode(dev),
+                                   dev->uclass->uc_drv->name, devnump);
 }
 
 int dev_read_u32_array(const struct udevice *dev, const char *propname,
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index fe0de73d7e2..afbd32b2990 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -651,10 +651,13 @@ int of_alias_scan(void);
  * of_alias_get_id - Get alias id for the given device_node
  *
  * Travels the lookup table to get the alias id for the given device_node and
- * alias stem.
+ * alias stem. A node outside the control tree is looked up in the /aliases
+ * node of its own tree.
  *
  * @np:                Pointer to the given device_node
- * @stem:      Alias stem of the given device_node
+ * @stem:      Alias stem of the given device_node; an alias matches when its
+ *             name is the stem followed by the number, so "usb" does not match
+ *             usbphy0
  * Return: alias ID, if found, else -ENODEV
  */
 int of_alias_get_id(const struct device_node *np, const char *stem);
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index c905e86b283..c6eaebb4c75 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -1180,6 +1180,22 @@ const void *ofnode_read_aliases_prop(const char 
*propname, int *sizep);
  */
 ofnode ofnode_get_aliases_node(const char *propname);
 
+/**
+ * ofnode_get_alias_seq() - get the sequence number of a node from its alias
+ *
+ * The aliases node can name a node with a stem and a number, such as
+ * "serial2". This looks the node up in the aliases of its tree and returns
+ * the number.
+ *
+ * @node: Node to look for
+ * @stem: Alias stem, e.g. "serial". The stem must match exactly: an alias
+ *     matches when its name is the stem followed by the number, so "usb"
+ *     does not find usbphy0
+ * @seqp: Returns the sequence number of the alias, if found
+ * Return: 0 if a sequence number was found, -ve if not
+ */
+int ofnode_get_alias_seq(ofnode node, const char *stem, int *seqp);
+
 struct display_timing;
 /**
  * ofnode_decode_display_timing() - decode display timings
diff --git a/include/dm/read.h b/include/dm/read.h
index 12dcde6645c..d0c17c3d343 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -1168,12 +1168,8 @@ static inline const void *dev_read_prop_by_prop(struct 
ofprop *prop,
 
 static inline int dev_read_alias_seq(const struct udevice *dev, int *devnump)
 {
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-       return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name,
-                                   dev_of_offset(dev), devnump);
-#else
-       return -ENOTSUPP;
-#endif
+       return ofnode_get_alias_seq(dev_ofnode(dev),
+                                   dev->uclass->uc_drv->name, devnump);
 }
 
 static inline int dev_read_u32_array(const struct udevice *dev,
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index 0f60c2a6281..d4c7380a412 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -523,6 +523,55 @@ static int dm_test_ofnode_read_aliases(struct 
unit_test_state *uts)
 }
 DM_TEST(dm_test_ofnode_read_aliases, UTF_SCAN_PDATA | UTF_SCAN_FDT);
 
+/* test ofnode_get_alias_seq() */
+static int dm_test_ofnode_get_alias_seq(struct unit_test_state *uts)
+{
+       int seq;
+
+       ut_assertok(ofnode_get_alias_seq(ofnode_path("/i2c@0"), "i2c", &seq));
+       ut_asserteq(0, seq);
+
+       ut_assertok(ofnode_get_alias_seq(ofnode_path("/some-bus/c-test@1"),
+                                        "testfdt", &seq));
+       ut_asserteq(12, seq);
+
+       ut_assert(ofnode_get_alias_seq(ofnode_path("/i2c@0"), "spi", &seq) < 0);
+       ut_assert(ofnode_get_alias_seq(ofnode_path("/some-bus"), "testfdt",
+                                      &seq) < 0);
+
+       /* the stem must match exactly: testbus3 is not a "test" alias */
+       ut_assert(ofnode_get_alias_seq(ofnode_path("/some-bus"), "test",
+                                      &seq) < 0);
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_get_alias_seq, UTF_SCAN_FDT);
+
+/* test ofnode_get_alias_seq() with the 'other' tree */
+static int dm_test_ofnode_get_alias_seq_ot(struct unit_test_state *uts)
+{
+       oftree otree = get_other_oftree(uts);
+       int seq;
+
+       ut_assertok(ofnode_get_alias_seq(oftree_path(otree, "/node"),
+                                        "other-test", &seq));
+       ut_asserteq(0, seq);
+       ut_assertok(ofnode_get_alias_seq(oftree_path(otree, "/node/subnode"),
+                                        "other-test", &seq));
+       ut_asserteq(1, seq);
+
+       /* a prefix of the stem, and the aliases of the other tree */
+       ut_assert(ofnode_get_alias_seq(oftree_path(otree, "/node"), "other",
+                                      &seq) < 0);
+       ut_assert(ofnode_get_alias_seq(oftree_path(otree, "/node"), "i2c",
+                                      &seq) < 0);
+       ut_assert(ofnode_get_alias_seq(ofnode_path("/i2c@0"), "other-test",
+                                      &seq) < 0);
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_get_alias_seq_ot, UTF_SCAN_FDT | UTF_OTHER_FDT);
+
 static int dm_test_ofnode_get_child_count(struct unit_test_state *uts)
 {
        ofnode node, child_node;
-- 
2.55.0

Reply via email to