[U-Boot] [RFC PATCH 1/2] fdt: Add fdtdec_find_aliases() to deal with alias nodes
Simon Glass
sjg at chromium.org
Tue Jan 3 23:34:48 CET 2012
Hi,
On Mon, Dec 26, 2011 at 2:31 PM, Simon Glass <sjg at chromium.org> wrote:
> Stephen Warren pointed out that we should use nodes whether or not they
> have an alias in the /aliases section. The aliases section specifies the
> order so far as it can, but is not essential. Operating without alisses
> is useful when the enumerated order of nodes does not matter (admittedly
> rare in U-Boot).
>
> This is considerably more complex, and it is important to keep this
> complexity out of driver code. This patch creates a function
> fdtdec_find_aliases() which returns an ordered list of node offsets
> for a particular compatible ID, taking account of alias nodes.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
Does this look like a reasonable solution to the problem as described?
Any comments before I respin as a real patch?
Regards,
Simon
> ---
> include/fdtdec.h | 51 +++++++++++++++++++++++++++++++
> lib/fdtdec.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 140 insertions(+), 0 deletions(-)
>
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index 5547676..0992130 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -228,3 +228,54 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
> * @return 0 if all ok or gpio was FDT_GPIO_NONE; -1 on error
> */
> int fdtdec_setup_gpio(struct fdt_gpio_state *gpio);
> +
> +/**
> + * Find the nodes for a peripheral and return a list of them in the correct
> + * order. This is used to enumerate all the peripherals of a certain type.
> + *
> + * To use this, optionally set up a /aliases node with alias properties for
> + * a peripheral. For example, for usb you could have:
> + *
> + * aliases {
> + * usb0 = "/ehci at c5008000";
> + * usb1 = "/ehci at c5000000";
> + * };
> + *
> + * Pass "usb" as the name to this function and will return a list of two
> + * nodes offsets: /ehci at c5008000 and ehci at c5000000.
> + *
> + * All nodes returned will match the compatible ID, as it is assumed that
> + * all peripherals use the same driver.
> + *
> + * If no alias node is found, then the node list will be returned in the
> + * order found in the fdt. If the aliases mention a node which doesn't
> + * exist, then this will be ignored. If nodes are found with no aliases,
> + * they will be added in any order.
> + *
> + * The array returned will not have any gaps.
> + *
> + * If there is a gap in the aliases, then this function will only return up
> + * to the number of nodes it found until the gap. It will also print a warning
> + * in this case. As an example, say you define aliases for usb2 and usb3, and
> + * have 3 nodes. Then in this case the node without an alias will become usb0
> + * and the aliases will be use for usb2 and usb3. But since there is no
> + * usb1, this function will only list one node (usb0), and will print a
> + * warning.
> + *
> + * This function does not check node properties - so it is possible that the
> + * node is marked disabled (status = "disabled"). The caller is expected to
> + * deal with this.
> + * TBD: It might be nicer to handle this here since we don't want a
> + * discontiguous list to result in the caller.
> + *
> + * Note: the algorithm used is O(maxcount).
> + *
> + * @param blob FDT blob to use
> + * @param name Root name of alias to search for
> + * @param id Compatible ID to look for
> + * @param node Place to put list of found nodes
> + * @param maxcount Maximum number of nodes to find
> + * @return number of nodes found on success, FTD_ERR_... on error
> + */
> +int fdtdec_find_aliases(const void *blob, const char *name,
> + enum fdt_compat_id id, int *node_list, int maxcount);
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index fb3d79d..b01978d 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -147,6 +147,95 @@ int fdtdec_next_alias(const void *blob, const char *name,
> return node;
> }
>
> +/* TODO: Can we tighten this code up a little? */
> +int fdtdec_find_aliases(const void *blob, const char *name,
> + enum fdt_compat_id id, int *node_list, int maxcount)
> +{
> + int nodes[maxcount];
> + int num_found = 0;
> + int alias_node;
> + int node;
> + int count;
> + int i, j;
> +
> + /* find the alias node if present */
> + alias_node = fdt_path_offset(blob, "/aliases");
> +
> + /*
> + * start with nothing, and we can assume that the root node can't
> + * match
> + */
> + memset(nodes, '\0', sizeof(nodes));
> +
> + /* First find all the compatible nodes */
> + node = 0;
> + for (node = count = 0; node >= 0 && count < maxcount;) {
> + node = fdtdec_next_compatible(blob, node, id);
> + if (node > 0)
> + nodes[count++] = node;
> + }
> +
> + /* Now find all the aliases */
> + memset(node_list, '\0', sizeof(*node_list) * maxcount);
> + for (i = 0; i < maxcount; i++) {
> + int found;
> + const char *path;
> +
> + path = fdt_getprop(blob, alias_node, name, NULL);
> + node = path ? fdt_path_offset(blob, path) : 0;
> + if (node <= 0)
> + continue;
> +
> + /* Make sure the node we found is in our list! */
> + found = -1;
> + for (j = 0; j < count; j++)
> + if (nodes[j] == node) {
> + found = j;
> + break;
> + }
> +
> + if (found == -1) {
> + printf("%s: warning: alias '%s' points to a node "
> + "'%s' that is missing or is not compatible "
> + " with '%s'\n", __func__, path,
> + fdt_get_name(blob, node, NULL),
> + compat_names[id]);
> + continue;
> + }
> +
> + /*
> + * Add this node to our list in the right place, and mark it
> + * as done.
> + */
> + node_list[i] = node;
> + nodes[j] = 0;
> + if (j >= num_found)
> + num_found = j + 1;
> + }
> +
> + /* Add any nodes not mentioned by an alias */
> + for (i = j = 0; i < maxcount; i++) {
> + if (!node_list[i]) {
> + for (; j < maxcount && !nodes[j]; j++)
> + ;
> +
> + /* Have we run out of nodes to add? */
> + if (j == maxcount)
> + break;
> +
> + node_list[i] = nodes[j];
> + }
> + }
> +
> + if (i != num_found) {
> + printf("%s: warning: for alias '%s' we found aliases up to "
> + "%d but only %d nodes, thus leaving a gap. Returning "
> + "only %d nodes\n", __func__, name, num_found, i, i);
> + }
> +
> + return i;
> +}
> +
> /*
> * This function is a little odd in that it accesses global data. At some
> * point if the architecture board.c files merge this will make more sense.
> --
> 1.7.3.1
>
More information about the U-Boot
mailing list