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_withdel(*labels
, new)
33 if (streq(new->label
, label
)) {
38 new = xmalloc(sizeof(*new));
39 memset(new, 0, sizeof(*new));
45 void delete_labels(struct label
**labels
)
49 for_each_label(*labels
, label
)
53 struct property
*build_property(char *name
, struct data val
)
55 struct property
*new = xmalloc(sizeof(*new));
57 memset(new, 0, sizeof(*new));
65 struct property
*build_property_delete(char *name
)
67 struct property
*new = xmalloc(sizeof(*new));
69 memset(new, 0, sizeof(*new));
77 struct property
*chain_property(struct property
*first
, struct property
*list
)
79 assert(first
->next
== NULL
);
85 struct property
*reverse_properties(struct property
*first
)
87 struct property
*p
= first
;
88 struct property
*head
= NULL
;
89 struct property
*next
;
100 struct node
*build_node(struct property
*proplist
, struct node
*children
)
102 struct node
*new = xmalloc(sizeof(*new));
105 memset(new, 0, sizeof(*new));
107 new->proplist
= reverse_properties(proplist
);
108 new->children
= children
;
110 for_each_child(new, child
) {
117 struct node
*build_node_delete(void)
119 struct node
*new = xmalloc(sizeof(*new));
121 memset(new, 0, sizeof(*new));
128 struct node
*name_node(struct node
*node
, char *name
)
130 assert(node
->name
== NULL
);
137 struct node
*merge_nodes(struct node
*old_node
, struct node
*new_node
)
139 struct property
*new_prop
, *old_prop
;
140 struct node
*new_child
, *old_child
;
143 old_node
->deleted
= 0;
145 /* Add new node labels to old node */
146 for_each_label_withdel(new_node
->labels
, l
)
147 add_label(&old_node
->labels
, l
->label
);
149 /* Move properties from the new node to the old node. If there
150 * is a collision, replace the old value with the new */
151 while (new_node
->proplist
) {
152 /* Pop the property off the list */
153 new_prop
= new_node
->proplist
;
154 new_node
->proplist
= new_prop
->next
;
155 new_prop
->next
= NULL
;
157 if (new_prop
->deleted
) {
158 delete_property_by_name(old_node
, new_prop
->name
);
163 /* Look for a collision, set new value if there is */
164 for_each_property_withdel(old_node
, old_prop
) {
165 if (streq(old_prop
->name
, new_prop
->name
)) {
166 /* Add new labels to old property */
167 for_each_label_withdel(new_prop
->labels
, l
)
168 add_label(&old_prop
->labels
, l
->label
);
170 old_prop
->val
= new_prop
->val
;
171 old_prop
->deleted
= 0;
178 /* if no collision occurred, add property to the old node. */
180 add_property(old_node
, new_prop
);
183 /* Move the override child nodes into the primary node. If
184 * there is a collision, then merge the nodes. */
185 while (new_node
->children
) {
186 /* Pop the child node off the list */
187 new_child
= new_node
->children
;
188 new_node
->children
= new_child
->next_sibling
;
189 new_child
->parent
= NULL
;
190 new_child
->next_sibling
= NULL
;
192 if (new_child
->deleted
) {
193 delete_node_by_name(old_node
, new_child
->name
);
198 /* Search for a collision. Merge if there is */
199 for_each_child_withdel(old_node
, old_child
) {
200 if (streq(old_child
->name
, new_child
->name
)) {
201 merge_nodes(old_child
, new_child
);
207 /* if no collision occured, add child to the old node. */
209 add_child(old_node
, new_child
);
212 /* The new node contents are now merged into the old node. Free
219 struct node
*chain_node(struct node
*first
, struct node
*list
)
221 assert(first
->next_sibling
== NULL
);
223 first
->next_sibling
= list
;
227 void add_property(struct node
*node
, struct property
*prop
)
240 void delete_property_by_name(struct node
*node
, char *name
)
242 struct property
*prop
= node
->proplist
;
245 if (!strcmp(prop
->name
, name
)) {
246 delete_property(prop
);
253 void delete_property(struct property
*prop
)
256 delete_labels(&prop
->labels
);
259 void add_child(struct node
*parent
, struct node
*child
)
263 child
->next_sibling
= NULL
;
264 child
->parent
= parent
;
266 p
= &parent
->children
;
268 p
= &((*p
)->next_sibling
);
273 void delete_node_by_name(struct node
*parent
, char *name
)
275 struct node
*node
= parent
->children
;
278 if (!strcmp(node
->name
, name
)) {
282 node
= node
->next_sibling
;
286 void delete_node(struct node
*node
)
288 struct property
*prop
;
292 for_each_child(node
, child
)
294 for_each_property(node
, prop
)
295 delete_property(prop
);
296 delete_labels(&node
->labels
);
299 struct reserve_info
*build_reserve_entry(uint64_t address
, uint64_t size
)
301 struct reserve_info
*new = xmalloc(sizeof(*new));
303 memset(new, 0, sizeof(*new));
305 new->re
.address
= address
;
311 struct reserve_info
*chain_reserve_entry(struct reserve_info
*first
,
312 struct reserve_info
*list
)
314 assert(first
->next
== NULL
);
320 struct reserve_info
*add_reserve_entry(struct reserve_info
*list
,
321 struct reserve_info
*new)
323 struct reserve_info
*last
;
330 for (last
= list
; last
->next
; last
= last
->next
)
338 struct boot_info
*build_boot_info(struct reserve_info
*reservelist
,
339 struct node
*tree
, uint32_t boot_cpuid_phys
)
341 struct boot_info
*bi
;
343 bi
= xmalloc(sizeof(*bi
));
344 bi
->reservelist
= reservelist
;
346 bi
->boot_cpuid_phys
= boot_cpuid_phys
;
352 * Tree accessor functions
355 const char *get_unitname(struct node
*node
)
357 if (node
->name
[node
->basenamelen
] == '\0')
360 return node
->name
+ node
->basenamelen
+ 1;
363 struct property
*get_property(struct node
*node
, const char *propname
)
365 struct property
*prop
;
367 for_each_property(node
, prop
)
368 if (streq(prop
->name
, propname
))
374 cell_t
propval_cell(struct property
*prop
)
376 assert(prop
->val
.len
== sizeof(cell_t
));
377 return fdt32_to_cpu(*((cell_t
*)prop
->val
.val
));
380 struct property
*get_property_by_label(struct node
*tree
, const char *label
,
383 struct property
*prop
;
388 for_each_property(tree
, prop
) {
391 for_each_label(prop
->labels
, l
)
392 if (streq(l
->label
, label
))
396 for_each_child(tree
, c
) {
397 prop
= get_property_by_label(c
, label
, node
);
406 struct marker
*get_marker_label(struct node
*tree
, const char *label
,
407 struct node
**node
, struct property
**prop
)
415 for_each_property(tree
, p
) {
418 for_each_marker_of_type(m
, LABEL
)
419 if (streq(m
->ref
, label
))
423 for_each_child(tree
, c
) {
424 m
= get_marker_label(c
, label
, node
, prop
);
434 struct node
*get_subnode(struct node
*node
, const char *nodename
)
438 for_each_child(node
, child
)
439 if (streq(child
->name
, nodename
))
445 struct node
*get_node_by_path(struct node
*tree
, const char *path
)
450 if (!path
|| ! (*path
)) {
456 while (path
[0] == '/')
459 p
= strchr(path
, '/');
461 for_each_child(tree
, child
) {
462 if (p
&& strneq(path
, child
->name
, p
-path
))
463 return get_node_by_path(child
, p
+1);
464 else if (!p
&& streq(path
, child
->name
))
471 struct node
*get_node_by_label(struct node
*tree
, const char *label
)
473 struct node
*child
, *node
;
476 assert(label
&& (strlen(label
) > 0));
478 for_each_label(tree
->labels
, l
)
479 if (streq(l
->label
, label
))
482 for_each_child(tree
, child
) {
483 node
= get_node_by_label(child
, label
);
491 struct node
*get_node_by_phandle(struct node
*tree
, cell_t phandle
)
493 struct node
*child
, *node
;
495 assert((phandle
!= 0) && (phandle
!= -1));
497 if (tree
->phandle
== phandle
) {
503 for_each_child(tree
, child
) {
504 node
= get_node_by_phandle(child
, phandle
);
512 struct node
*get_node_by_ref(struct node
*tree
, const char *ref
)
515 return get_node_by_path(tree
, ref
);
517 return get_node_by_label(tree
, ref
);
520 cell_t
get_node_phandle(struct node
*root
, struct node
*node
)
522 static cell_t phandle
= 1; /* FIXME: ick, static local */
524 if ((node
->phandle
!= 0) && (node
->phandle
!= -1))
525 return node
->phandle
;
527 while (get_node_by_phandle(root
, phandle
))
530 node
->phandle
= phandle
;
532 if (!get_property(node
, "linux,phandle")
533 && (phandle_format
& PHANDLE_LEGACY
))
535 build_property("linux,phandle",
536 data_append_cell(empty_data
, phandle
)));
538 if (!get_property(node
, "phandle")
539 && (phandle_format
& PHANDLE_EPAPR
))
541 build_property("phandle",
542 data_append_cell(empty_data
, phandle
)));
544 /* If the node *does* have a phandle property, we must
545 * be dealing with a self-referencing phandle, which will be
546 * fixed up momentarily in the caller */
548 return node
->phandle
;
551 uint32_t guess_boot_cpuid(struct node
*tree
)
553 struct node
*cpus
, *bootcpu
;
554 struct property
*reg
;
556 cpus
= get_node_by_path(tree
, "/cpus");
561 bootcpu
= cpus
->children
;
565 reg
= get_property(bootcpu
, "reg");
566 if (!reg
|| (reg
->val
.len
!= sizeof(uint32_t)))
569 /* FIXME: Sanity check node? */
571 return propval_cell(reg
);
574 static int cmp_reserve_info(const void *ax
, const void *bx
)
576 const struct reserve_info
*a
, *b
;
578 a
= *((const struct reserve_info
* const *)ax
);
579 b
= *((const struct reserve_info
* const *)bx
);
581 if (a
->re
.address
< b
->re
.address
)
583 else if (a
->re
.address
> b
->re
.address
)
585 else if (a
->re
.size
< b
->re
.size
)
587 else if (a
->re
.size
> b
->re
.size
)
593 static void sort_reserve_entries(struct boot_info
*bi
)
595 struct reserve_info
*ri
, **tbl
;
598 for (ri
= bi
->reservelist
;
606 tbl
= xmalloc(n
* sizeof(*tbl
));
608 for (ri
= bi
->reservelist
;
613 qsort(tbl
, n
, sizeof(*tbl
), cmp_reserve_info
);
615 bi
->reservelist
= tbl
[0];
616 for (i
= 0; i
< (n
-1); i
++)
617 tbl
[i
]->next
= tbl
[i
+1];
618 tbl
[n
-1]->next
= NULL
;
623 static int cmp_prop(const void *ax
, const void *bx
)
625 const struct property
*a
, *b
;
627 a
= *((const struct property
* const *)ax
);
628 b
= *((const struct property
* const *)bx
);
630 return strcmp(a
->name
, b
->name
);
633 static void sort_properties(struct node
*node
)
636 struct property
*prop
, **tbl
;
638 for_each_property_withdel(node
, prop
)
644 tbl
= xmalloc(n
* sizeof(*tbl
));
646 for_each_property_withdel(node
, prop
)
649 qsort(tbl
, n
, sizeof(*tbl
), cmp_prop
);
651 node
->proplist
= tbl
[0];
652 for (i
= 0; i
< (n
-1); i
++)
653 tbl
[i
]->next
= tbl
[i
+1];
654 tbl
[n
-1]->next
= NULL
;
659 static int cmp_subnode(const void *ax
, const void *bx
)
661 const struct node
*a
, *b
;
663 a
= *((const struct node
* const *)ax
);
664 b
= *((const struct node
* const *)bx
);
666 return strcmp(a
->name
, b
->name
);
669 static void sort_subnodes(struct node
*node
)
672 struct node
*subnode
, **tbl
;
674 for_each_child_withdel(node
, subnode
)
680 tbl
= xmalloc(n
* sizeof(*tbl
));
682 for_each_child_withdel(node
, subnode
)
685 qsort(tbl
, n
, sizeof(*tbl
), cmp_subnode
);
687 node
->children
= tbl
[0];
688 for (i
= 0; i
< (n
-1); i
++)
689 tbl
[i
]->next_sibling
= tbl
[i
+1];
690 tbl
[n
-1]->next_sibling
= NULL
;
695 static void sort_node(struct node
*node
)
699 sort_properties(node
);
701 for_each_child_withdel(node
, c
)
705 void sort_tree(struct boot_info
*bi
)
707 sort_reserve_entries(bi
);