[PATCH] of/flattree: Early "find node by alias" function
Pawel Moll
pawel.moll at arm.com
Sat Oct 22 02:16:59 EST 2011
This patch adds a function for finding a node in flat tree
based on an alias name. It can be used in early boot code.
Typical use case is a situation when early code needs data
from a arbitrary tree node, eg. base address of "serial0" to
initialise debug output or some sort of ID register to
probe hardware.
The tree source could look like that:
/ {
aliases {
serial0 = &uart0;
};
uart0: uart at f0001000 {
reg = <0xf0001000 0x1000>;
};
}
Signed-off-by: Pawel Moll <pawel.moll at arm.com>
---
drivers/of/fdt.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_fdt.h | 3 +
2 files changed, 120 insertions(+), 0 deletions(-)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 65200af..0968809 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -502,6 +502,123 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
}
/**
+ * Routines used by of_flat_dt_find_node_by_alias()
+ */
+
+struct of_flat_dt_find_node_by_alias_state {
+ const char *alias;
+ unsigned long node;
+ const char *path;
+ int depth;
+ int token_len;
+
+};
+
+static int __init of_flat_dt_scan_path_legacy(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ struct of_flat_dt_find_node_by_alias_state *state = data;
+
+ pr_debug("%s: uname='%s', state->path='%s'\n",
+ __func__, uname, state->path);
+
+ return strcmp(state->path, uname) == 0;
+}
+
+static int __init of_flat_dt_scan_path(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ struct of_flat_dt_find_node_by_alias_state *state = data;
+
+ pr_debug("%s: uname='%s', depth=%d, state->path='%s', state->depth=%d,"
+ " state->token_len=%d\n", __func__, uname, depth,
+ state->path, state->depth, state->token_len);
+
+ /* If the depth decreases, we didn't find the path */
+ if (depth < state->depth)
+ return -ENODEV;
+
+ /* Check if path ~= /^uname[\/\0]/ */
+ if (strncmp(state->path, uname, state->token_len) == 0 &&
+ uname[state->token_len] == 0) {
+ const char *slash;
+
+ state->depth++;
+ state->path += state->token_len; /* Next token */
+ if (*state->path == 0) { /* All path tokens processed? */
+ state->node = node;
+ return 1; /* Success! */
+ }
+ BUG_ON(*state->path != '/');
+ state->path++; /* Skip leading slash */
+ slash = strchr(state->path, '/');
+ if (!slash)
+ state->token_len = strlen(state->path);
+ else
+ state->token_len = slash - state->path;
+ }
+
+ return 0;
+}
+
+static int __init of_flat_dt_scan_aliases(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ int err;
+ struct of_flat_dt_find_node_by_alias_state *state = data;
+
+ if (depth != 1 || strcmp(uname, "aliases") != 0)
+ return 0;
+
+ state->path = of_get_flat_dt_prop(node, state->alias, NULL);
+ if (!state->path)
+ return -ENXIO;
+ if (*state->path != '/')
+ return -EFAULT;
+
+ state->token_len = 0; /* Root node has no name */
+
+ /* FDTs prior to version 16 (0x10) had full path in every node */
+ if (be32_to_cpu(initial_boot_params->version) < 0x10)
+ err = of_scan_flat_dt(of_flat_dt_scan_path_legacy, state);
+ else
+ err = of_scan_flat_dt(of_flat_dt_scan_path, state);
+
+ if (err == 0) /* Whole tree scanned, no path found */
+ err = -ENODEV;
+
+ return err;
+}
+
+/**
+ * of_flat_dt_find_node_by_alias - find a root node referenced by an alias
+ *
+ * @alias: alias name
+ * @node: pointer to a node reference to be filled on success
+ *
+ * returns 0 on success, negative value on error.
+ *
+ * This function can be used at boot time, before the tree is unflattened.
+ */
+int __init of_flat_dt_find_node_by_alias(const char *alias, unsigned long *node)
+{
+ int err;
+ struct of_flat_dt_find_node_by_alias_state state = {
+ .alias = alias,
+ };
+
+ err = of_scan_flat_dt(of_flat_dt_scan_aliases, &state);
+ if (err == 0) /* No 'aliases' node */
+ err = -ENOENT;
+ if (err > 0) {
+ /* Node found */
+ *node = state.node;
+ err = 0;
+ }
+ return err;
+}
+
+/**
* of_get_flat_dt_root - find the root node in the flat blob
*/
unsigned long __init of_get_flat_dt_root(void)
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index c84d900..8212e47 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -85,6 +85,9 @@ extern char *find_flat_dt_string(u32 offset);
extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname,
int depth, void *data),
void *data);
+extern int of_flat_dt_find_node_by_alias(const char *alias,
+ unsigned long *node);
+
extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
unsigned long *size);
extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
--
1.6.3.3
More information about the devicetree-discuss
mailing list