Skip to content

Commit 611cad7

Browse files
Shawn Guoglikely
authored andcommitted
dt: add of_alias_scan and of_alias_get_id
The patch adds function of_alias_scan to populate a global lookup table with the properties of 'aliases' node and function of_alias_get_id for drivers to find alias id from the lookup table. v3: Split out automatic addition of aliases on id lookup so that it can be debated separately from the core functionality. v2: - Add of_chosen/of_aliases populating and of_alias_scan() invocation for OF_PROMTREE. - Add locking - rework parse loop Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
1 parent a81dd36 commit 611cad7

File tree

4 files changed

+138
-4
lines changed

4 files changed

+138
-4
lines changed

drivers/of/base.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,39 @@
1717
* as published by the Free Software Foundation; either version
1818
* 2 of the License, or (at your option) any later version.
1919
*/
20+
#include <linux/ctype.h>
2021
#include <linux/module.h>
2122
#include <linux/of.h>
2223
#include <linux/spinlock.h>
2324
#include <linux/slab.h>
2425
#include <linux/proc_fs.h>
2526

27+
/**
28+
* struct alias_prop - Alias property in 'aliases' node
29+
* @link: List node to link the structure in aliases_lookup list
30+
* @alias: Alias property name
31+
* @np: Pointer to device_node that the alias stands for
32+
* @id: Index value from end of alias name
33+
* @stem: Alias string without the index
34+
*
35+
* The structure represents one alias property of 'aliases' node as
36+
* an entry in aliases_lookup list.
37+
*/
38+
struct alias_prop {
39+
struct list_head link;
40+
const char *alias;
41+
struct device_node *np;
42+
int id;
43+
char stem[0];
44+
};
45+
46+
static LIST_HEAD(aliases_lookup);
47+
2648
struct device_node *allnodes;
2749
struct device_node *of_chosen;
50+
struct device_node *of_aliases;
51+
52+
static DEFINE_MUTEX(of_aliases_mutex);
2853

2954
/* use when traversing tree through the allnext, child, sibling,
3055
* or parent members of struct device_node.
@@ -988,3 +1013,99 @@ void of_detach_node(struct device_node *np)
9881013
}
9891014
#endif /* defined(CONFIG_OF_DYNAMIC) */
9901015

1016+
static void of_alias_add(struct alias_prop *ap, struct device_node *np,
1017+
int id, const char *stem, int stem_len)
1018+
{
1019+
ap->np = np;
1020+
ap->id = id;
1021+
strncpy(ap->stem, stem, stem_len);
1022+
ap->stem[stem_len] = 0;
1023+
list_add_tail(&ap->link, &aliases_lookup);
1024+
pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
1025+
ap->alias, ap->stem, ap->id, np ? np->full_name : NULL);
1026+
}
1027+
1028+
/**
1029+
* of_alias_scan - Scan all properties of 'aliases' node
1030+
*
1031+
* The function scans all the properties of 'aliases' node and populate
1032+
* the the global lookup table with the properties. It returns the
1033+
* number of alias_prop found, or error code in error case.
1034+
*
1035+
* @dt_alloc: An allocator that provides a virtual address to memory
1036+
* for the resulting tree
1037+
*/
1038+
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
1039+
{
1040+
struct property *pp;
1041+
1042+
of_chosen = of_find_node_by_path("/chosen");
1043+
if (of_chosen == NULL)
1044+
of_chosen = of_find_node_by_path("/chosen@0");
1045+
of_aliases = of_find_node_by_path("/aliases");
1046+
if (!of_aliases)
1047+
return;
1048+
1049+
for_each_property(pp, of_aliases->properties) {
1050+
const char *start = pp->name;
1051+
const char *end = start + strlen(start);
1052+
struct device_node *np;
1053+
struct alias_prop *ap;
1054+
int id, len;
1055+
1056+
/* Skip those we do not want to proceed */
1057+
if (!strcmp(pp->name, "name") ||
1058+
!strcmp(pp->name, "phandle") ||
1059+
!strcmp(pp->name, "linux,phandle"))
1060+
continue;
1061+
1062+
np = of_find_node_by_path(pp->value);
1063+
if (!np)
1064+
continue;
1065+
1066+
/* walk the alias backwards to extract the id and work out
1067+
* the 'stem' string */
1068+
while (isdigit(*(end-1)) && end > start)
1069+
end--;
1070+
len = end - start;
1071+
1072+
if (kstrtoint(end, 10, &id) < 0)
1073+
continue;
1074+
1075+
/* Allocate an alias_prop with enough space for the stem */
1076+
ap = dt_alloc(sizeof(*ap) + len + 1, 4);
1077+
if (!ap)
1078+
continue;
1079+
ap->alias = start;
1080+
of_alias_add(ap, np, id, start, len);
1081+
}
1082+
}
1083+
1084+
/**
1085+
* of_alias_get_id - Get alias id for the given device_node
1086+
* @np: Pointer to the given device_node
1087+
* @stem: Alias stem of the given device_node
1088+
*
1089+
* The function travels the lookup table to get alias id for the given
1090+
* device_node and alias stem. It returns the alias id if find it.
1091+
*/
1092+
int of_alias_get_id(struct device_node *np, const char *stem)
1093+
{
1094+
struct alias_prop *app;
1095+
int id = -ENODEV;
1096+
1097+
mutex_lock(&of_aliases_mutex);
1098+
list_for_each_entry(app, &aliases_lookup, link) {
1099+
if (strcmp(app->stem, stem) != 0)
1100+
continue;
1101+
1102+
if (np == app->np) {
1103+
id = app->id;
1104+
break;
1105+
}
1106+
}
1107+
mutex_unlock(&of_aliases_mutex);
1108+
1109+
return id;
1110+
}
1111+
EXPORT_SYMBOL_GPL(of_alias_get_id);

drivers/of/fdt.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -707,10 +707,8 @@ void __init unflatten_device_tree(void)
707707
__unflatten_device_tree(initial_boot_params, &allnodes,
708708
early_init_dt_alloc_memory_arch);
709709

710-
/* Get pointer to OF "/chosen" node for use everywhere */
711-
of_chosen = of_find_node_by_path("/chosen");
712-
if (of_chosen == NULL)
713-
of_chosen = of_find_node_by_path("/chosen@0");
710+
/* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
711+
of_alias_scan(early_init_dt_alloc_memory_arch);
714712
}
715713

716714
#endif /* CONFIG_OF_EARLY_FLATTREE */

drivers/of/pdt.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
229229
return ret;
230230
}
231231

232+
static void *kernel_tree_alloc(u64 size, u64 align)
233+
{
234+
return prom_early_alloc(size);
235+
}
236+
232237
void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
233238
{
234239
struct device_node **nextp;
@@ -245,4 +250,7 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
245250
nextp = &allnodes->allnext;
246251
allnodes->child = of_pdt_build_tree(allnodes,
247252
of_pdt_prom_ops->getchild(allnodes->phandle), &nextp);
253+
254+
/* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */
255+
of_alias_scan(kernel_tree_alloc);
248256
}

include/linux/of.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ struct device_node {
6868
/* Pointer for first entry in chain of all nodes. */
6969
extern struct device_node *allnodes;
7070
extern struct device_node *of_chosen;
71+
extern struct device_node *of_aliases;
7172
extern rwlock_t devtree_lock;
7273

7374
static inline bool of_have_populated_dt(void)
@@ -209,6 +210,9 @@ extern int of_device_is_available(const struct device_node *device);
209210
extern const void *of_get_property(const struct device_node *node,
210211
const char *name,
211212
int *lenp);
213+
#define for_each_property(pp, properties) \
214+
for (pp = properties; pp != NULL; pp = pp->next)
215+
212216
extern int of_n_addr_cells(struct device_node *np);
213217
extern int of_n_size_cells(struct device_node *np);
214218
extern const struct of_device_id *of_match_node(
@@ -221,6 +225,9 @@ extern int of_parse_phandles_with_args(struct device_node *np,
221225
const char *list_name, const char *cells_name, int index,
222226
struct device_node **out_node, const void **out_args);
223227

228+
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
229+
extern int of_alias_get_id(struct device_node *np, const char *stem);
230+
224231
extern int of_machine_is_compatible(const char *compat);
225232

226233
extern int prom_add_property(struct device_node* np, struct property* prop);

0 commit comments

Comments
 (0)