2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 * Tree building functions
27 void add_label(struct label
**labels
, char *label
)
31 /* Make sure the label isn't already there */
32 for_each_label(*labels
, new)
33 if (streq(new->label
, label
))
36 new = xmalloc(sizeof(*new));
42 struct property
*build_property(char *name
, struct data val
)
44 struct property
*new = xmalloc(sizeof(*new));
46 memset(new, 0, sizeof(*new));
54 struct property
*chain_property(struct property
*first
, struct property
*list
)
56 assert(first
->next
== NULL
);
62 struct property
*reverse_properties(struct property
*first
)
64 struct property
*p
= first
;
65 struct property
*head
= NULL
;
66 struct property
*next
;
77 struct node
*build_node(struct property
*proplist
, struct node
*children
)
79 struct node
*new = xmalloc(sizeof(*new));
82 memset(new, 0, sizeof(*new));
84 new->proplist
= reverse_properties(proplist
);
85 new->children
= children
;
87 for_each_child(new, child
) {
94 struct node
*name_node(struct node
*node
, char *name
)
96 assert(node
->name
== NULL
);
103 struct node
*merge_nodes(struct node
*old_node
, struct node
*new_node
)
105 struct property
*new_prop
, *old_prop
;
106 struct node
*new_child
, *old_child
;
109 /* Add new node labels to old node */
110 for_each_label(new_node
->labels
, l
)
111 add_label(&old_node
->labels
, l
->label
);
113 /* Move properties from the new node to the old node. If there
114 * is a collision, replace the old value with the new */
115 while (new_node
->proplist
) {
116 /* Pop the property off the list */
117 new_prop
= new_node
->proplist
;
118 new_node
->proplist
= new_prop
->next
;
119 new_prop
->next
= NULL
;
121 /* Look for a collision, set new value if there is */
122 for_each_property(old_node
, old_prop
) {
123 if (streq(old_prop
->name
, new_prop
->name
)) {
124 /* Add new labels to old property */
125 for_each_label(new_prop
->labels
, l
)
126 add_label(&old_prop
->labels
, l
->label
);
128 old_prop
->val
= new_prop
->val
;
135 /* if no collision occurred, add property to the old node. */
137 add_property(old_node
, new_prop
);
140 /* Move the override child nodes into the primary node. If
141 * there is a collision, then merge the nodes. */
142 while (new_node
->children
) {
143 /* Pop the child node off the list */
144 new_child
= new_node
->children
;
145 new_node
->children
= new_child
->next_sibling
;
146 new_child
->parent
= NULL
;
147 new_child
->next_sibling
= NULL
;
149 /* Search for a collision. Merge if there is */
150 for_each_child(old_node
, old_child
) {
151 if (streq(old_child
->name
, new_child
->name
)) {
152 merge_nodes(old_child
, new_child
);
158 /* if no collision occured, add child to the old node. */
160 add_child(old_node
, new_child
);
163 /* The new node contents are now merged into the old node. Free
170 struct node
*chain_node(struct node
*first
, struct node
*list
)
172 assert(first
->next_sibling
== NULL
);
174 first
->next_sibling
= list
;
178 void add_property(struct node
*node
, struct property
*prop
)
191 void add_child(struct node
*parent
, struct node
*child
)
195 child
->next_sibling
= NULL
;
196 child
->parent
= parent
;
198 p
= &parent
->children
;
200 p
= &((*p
)->next_sibling
);
205 struct reserve_info
*build_reserve_entry(uint64_t address
, uint64_t size
)
207 struct reserve_info
*new = xmalloc(sizeof(*new));
209 memset(new, 0, sizeof(*new));
211 new->re
.address
= address
;
217 struct reserve_info
*chain_reserve_entry(struct reserve_info
*first
,
218 struct reserve_info
*list
)
220 assert(first
->next
== NULL
);
226 struct reserve_info
*add_reserve_entry(struct reserve_info
*list
,
227 struct reserve_info
*new)
229 struct reserve_info
*last
;
236 for (last
= list
; last
->next
; last
= last
->next
)
244 struct boot_info
*build_boot_info(struct reserve_info
*reservelist
,
245 struct node
*tree
, uint32_t boot_cpuid_phys
)
247 struct boot_info
*bi
;
249 bi
= xmalloc(sizeof(*bi
));
250 bi
->reservelist
= reservelist
;
252 bi
->boot_cpuid_phys
= boot_cpuid_phys
;
258 * Tree accessor functions
261 const char *get_unitname(struct node
*node
)
263 if (node
->name
[node
->basenamelen
] == '\0')
266 return node
->name
+ node
->basenamelen
+ 1;
269 struct property
*get_property(struct node
*node
, const char *propname
)
271 struct property
*prop
;
273 for_each_property(node
, prop
)
274 if (streq(prop
->name
, propname
))
280 cell_t
propval_cell(struct property
*prop
)
282 assert(prop
->val
.len
== sizeof(cell_t
));
283 return fdt32_to_cpu(*((cell_t
*)prop
->val
.val
));
286 struct property
*get_property_by_label(struct node
*tree
, const char *label
,
289 struct property
*prop
;
294 for_each_property(tree
, prop
) {
297 for_each_label(prop
->labels
, l
)
298 if (streq(l
->label
, label
))
302 for_each_child(tree
, c
) {
303 prop
= get_property_by_label(c
, label
, node
);
312 struct marker
*get_marker_label(struct node
*tree
, const char *label
,
313 struct node
**node
, struct property
**prop
)
321 for_each_property(tree
, p
) {
324 for_each_marker_of_type(m
, LABEL
)
325 if (streq(m
->ref
, label
))
329 for_each_child(tree
, c
) {
330 m
= get_marker_label(c
, label
, node
, prop
);
340 struct node
*get_subnode(struct node
*node
, const char *nodename
)
344 for_each_child(node
, child
)
345 if (streq(child
->name
, nodename
))
351 struct node
*get_node_by_path(struct node
*tree
, const char *path
)
356 if (!path
|| ! (*path
))
359 while (path
[0] == '/')
362 p
= strchr(path
, '/');
364 for_each_child(tree
, child
) {
365 if (p
&& strneq(path
, child
->name
, p
-path
))
366 return get_node_by_path(child
, p
+1);
367 else if (!p
&& streq(path
, child
->name
))
374 struct node
*get_node_by_label(struct node
*tree
, const char *label
)
376 struct node
*child
, *node
;
379 assert(label
&& (strlen(label
) > 0));
381 for_each_label(tree
->labels
, l
)
382 if (streq(l
->label
, label
))
385 for_each_child(tree
, child
) {
386 node
= get_node_by_label(child
, label
);
394 struct node
*get_node_by_phandle(struct node
*tree
, cell_t phandle
)
396 struct node
*child
, *node
;
398 assert((phandle
!= 0) && (phandle
!= -1));
400 if (tree
->phandle
== phandle
)
403 for_each_child(tree
, child
) {
404 node
= get_node_by_phandle(child
, phandle
);
412 struct node
*get_node_by_ref(struct node
*tree
, const char *ref
)
415 return get_node_by_path(tree
, ref
);
417 return get_node_by_label(tree
, ref
);
420 cell_t
get_node_phandle(struct node
*root
, struct node
*node
)
422 static cell_t phandle
= 1; /* FIXME: ick, static local */
424 if ((node
->phandle
!= 0) && (node
->phandle
!= -1))
425 return node
->phandle
;
427 while (get_node_by_phandle(root
, phandle
))
430 node
->phandle
= phandle
;
432 if (!get_property(node
, "linux,phandle")
433 && (phandle_format
& PHANDLE_LEGACY
))
435 build_property("linux,phandle",
436 data_append_cell(empty_data
, phandle
)));
438 if (!get_property(node
, "phandle")
439 && (phandle_format
& PHANDLE_EPAPR
))
441 build_property("phandle",
442 data_append_cell(empty_data
, phandle
)));
444 /* If the node *does* have a phandle property, we must
445 * be dealing with a self-referencing phandle, which will be
446 * fixed up momentarily in the caller */
448 return node
->phandle
;
451 uint32_t guess_boot_cpuid(struct node
*tree
)
453 struct node
*cpus
, *bootcpu
;
454 struct property
*reg
;
456 cpus
= get_node_by_path(tree
, "/cpus");
461 bootcpu
= cpus
->children
;
465 reg
= get_property(bootcpu
, "reg");
466 if (!reg
|| (reg
->val
.len
!= sizeof(uint32_t)))
469 /* FIXME: Sanity check node? */
471 return propval_cell(reg
);
474 static int cmp_reserve_info(const void *ax
, const void *bx
)
476 const struct reserve_info
*a
, *b
;
478 a
= *((const struct reserve_info
* const *)ax
);
479 b
= *((const struct reserve_info
* const *)bx
);
481 if (a
->re
.address
< b
->re
.address
)
483 else if (a
->re
.address
> b
->re
.address
)
485 else if (a
->re
.size
< b
->re
.size
)
487 else if (a
->re
.size
> b
->re
.size
)
493 static void sort_reserve_entries(struct boot_info
*bi
)
495 struct reserve_info
*ri
, **tbl
;
498 for (ri
= bi
->reservelist
;
506 tbl
= xmalloc(n
* sizeof(*tbl
));
508 for (ri
= bi
->reservelist
;
513 qsort(tbl
, n
, sizeof(*tbl
), cmp_reserve_info
);
515 bi
->reservelist
= tbl
[0];
516 for (i
= 0; i
< (n
-1); i
++)
517 tbl
[i
]->next
= tbl
[i
+1];
518 tbl
[n
-1]->next
= NULL
;
523 static int cmp_prop(const void *ax
, const void *bx
)
525 const struct property
*a
, *b
;
527 a
= *((const struct property
* const *)ax
);
528 b
= *((const struct property
* const *)bx
);
530 return strcmp(a
->name
, b
->name
);
533 static void sort_properties(struct node
*node
)
536 struct property
*prop
, **tbl
;
538 for_each_property(node
, prop
)
544 tbl
= xmalloc(n
* sizeof(*tbl
));
546 for_each_property(node
, prop
)
549 qsort(tbl
, n
, sizeof(*tbl
), cmp_prop
);
551 node
->proplist
= tbl
[0];
552 for (i
= 0; i
< (n
-1); i
++)
553 tbl
[i
]->next
= tbl
[i
+1];
554 tbl
[n
-1]->next
= NULL
;
559 static int cmp_subnode(const void *ax
, const void *bx
)
561 const struct node
*a
, *b
;
563 a
= *((const struct node
* const *)ax
);
564 b
= *((const struct node
* const *)bx
);
566 return strcmp(a
->name
, b
->name
);
569 static void sort_subnodes(struct node
*node
)
572 struct node
*subnode
, **tbl
;
574 for_each_child(node
, subnode
)
580 tbl
= xmalloc(n
* sizeof(*tbl
));
582 for_each_child(node
, subnode
)
585 qsort(tbl
, n
, sizeof(*tbl
), cmp_subnode
);
587 node
->children
= tbl
[0];
588 for (i
= 0; i
< (n
-1); i
++)
589 tbl
[i
]->next_sibling
= tbl
[i
+1];
590 tbl
[n
-1]->next_sibling
= NULL
;
595 static void sort_node(struct node
*node
)
599 sort_properties(node
);
601 for_each_child(node
, c
)
605 void sort_tree(struct boot_info
*bi
)
607 sort_reserve_entries(bi
);