1168793Sthompsa/*
2168793Sthompsa * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3168793Sthompsa *
4168793Sthompsa *
5174721Sthompsa * This program is free software; you can redistribute it and/or
6294615Saraujo * modify it under the terms of the GNU General Public License as
7168793Sthompsa * published by the Free Software Foundation; either version 2 of the
8168793Sthompsa * License, or (at your option) any later version.
9168793Sthompsa *
10168793Sthompsa *  This program is distributed in the hope that it will be useful,
11168793Sthompsa *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12168793Sthompsa *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13168793Sthompsa *  General Public License for more details.
14168793Sthompsa *
15168793Sthompsa *  You should have received a copy of the GNU General Public License
16168793Sthompsa *  along with this program; if not, write to the Free Software
17168793Sthompsa *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18168793Sthompsa *                                                                   USA
19168793Sthompsa */
20168793Sthompsa
21168793Sthompsa#include "dtc.h"
22168793Sthompsa
23168793Sthompsa/*
24168793Sthompsa * Tree building functions
25168793Sthompsa */
26168793Sthompsa
27168793Sthompsavoid add_label(struct label **labels, char *label)
28168793Sthompsa{
29168793Sthompsa	struct label *new;
30168793Sthompsa
31168793Sthompsa	/* Make sure the label isn't already there */
32168793Sthompsa	for_each_label_withdel(*labels, new)
33168793Sthompsa		if (streq(new->label, label)) {
34168793Sthompsa			new->deleted = 0;
35168793Sthompsa			return;
36168793Sthompsa		}
37168793Sthompsa
38168793Sthompsa	new = xmalloc(sizeof(*new));
39169569Sthompsa	memset(new, 0, sizeof(*new));
40255038Sadrian	new->label = label;
41318329Smav	new->next = *labels;
42169329Sthompsa	*labels = new;
43203548Seri}
44168793Sthompsa
45168793Sthompsavoid delete_labels(struct label **labels)
46168793Sthompsa{
47168793Sthompsa	struct label *label;
48168793Sthompsa
49168793Sthompsa	for_each_label(*labels, label)
50168793Sthompsa		label->deleted = 1;
51168793Sthompsa}
52168793Sthompsa
53168793Sthompsastruct property *build_property(char *name, struct data val)
54272386Shrs{
55168793Sthompsa	struct property *new = xmalloc(sizeof(*new));
56221130Sbz
57221130Sbz	memset(new, 0, sizeof(*new));
58264498Srmacklem
59221130Sbz	new->name = name;
60168793Sthompsa	new->val = val;
61168793Sthompsa
62168793Sthompsa	return new;
63168793Sthompsa}
64168793Sthompsa
65168793Sthompsastruct property *build_property_delete(char *name)
66168793Sthompsa{
67252511Shrs	struct property *new = xmalloc(sizeof(*new));
68252511Shrs
69168793Sthompsa	memset(new, 0, sizeof(*new));
70168793Sthompsa
71168793Sthompsa	new->name = name;
72168793Sthompsa	new->deleted = 1;
73168793Sthompsa
74168793Sthompsa	return new;
75168793Sthompsa}
76168793Sthompsa
77168793Sthompsastruct property *chain_property(struct property *first, struct property *list)
78168793Sthompsa{
79168793Sthompsa	assert(first->next == NULL);
80168793Sthompsa
81168793Sthompsa	first->next = list;
82168793Sthompsa	return first;
83168793Sthompsa}
84168793Sthompsa
85272386Shrsstruct property *reverse_properties(struct property *first)
86272386Shrs{
87272386Shrs	struct property *p = first;
88272386Shrs	struct property *head = NULL;
89272386Shrs	struct property *next;
90272386Shrs
91272386Shrs	while (p) {
92272386Shrs		next = p->next;
93272386Shrs		p->next = head;
94168793Sthompsa		head = p;
95168793Sthompsa		p = next;
96168793Sthompsa	}
97168793Sthompsa	return head;
98272386Shrs}
99272386Shrs
100241610Sglebiusstruct node *build_node(struct property *proplist, struct node *children)
101241610Sglebius{
102171661Sthompsa	struct node *new = xmalloc(sizeof(*new));
103168793Sthompsa	struct node *child;
104168793Sthompsa
105168793Sthompsa	memset(new, 0, sizeof(*new));
106173895Sthompsa
107292402Ssmh	new->proplist = reverse_properties(proplist);
108168793Sthompsa	new->children = children;
109168793Sthompsa
110249925Sglebius	for_each_child(new, child) {
111168793Sthompsa		child->parent = new;
112201803Strasz	}
113168793Sthompsa
114201803Strasz	return new;
115168793Sthompsa}
116168793Sthompsa
117168793Sthompsastruct node *build_node_delete(void)
118168793Sthompsa{
119318329Smav	struct node *new = xmalloc(sizeof(*new));
120318329Smav
121318329Smav	memset(new, 0, sizeof(*new));
122168793Sthompsa
123168793Sthompsa	new->deleted = 1;
124168793Sthompsa
125272211Smelifaro	return new;
126240742Sglebius}
127240742Sglebius
128168793Sthompsastruct node *name_node(struct node *node, char *name)
129168793Sthompsa{
130168793Sthompsa	assert(node->name == NULL);
131168793Sthompsa
132168793Sthompsa	node->name = name;
133168793Sthompsa
134272161Sglebius	return node;
135168793Sthompsa}
136168793Sthompsa
137168793Sthompsastruct node *omit_node_if_unused(struct node *node)
138168793Sthompsa{
139168793Sthompsa	node->omit_if_unused = 1;
140168793Sthompsa
141168793Sthompsa	return node;
142168793Sthompsa}
143168793Sthompsa
144168793Sthompsastruct node *reference_node(struct node *node)
145272161Sglebius{
146272158Sglebius	node->is_referenced = 1;
147168793Sthompsa
148168793Sthompsa	return node;
149168793Sthompsa}
150168793Sthompsa
151168793Sthompsastruct node *merge_nodes(struct node *old_node, struct node *new_node)
152168793Sthompsa{
153168793Sthompsa	struct property *new_prop, *old_prop;
154271732Saraujo	struct node *new_child, *old_child;
155271732Saraujo	struct label *l;
156271732Saraujo
157272175Sglebius	old_node->deleted = 0;
158271732Saraujo
159168793Sthompsa	/* Add new node labels to old node */
160272161Sglebius	for_each_label_withdel(new_node->labels, l)
161272158Sglebius		add_label(&old_node->labels, l->label);
162168793Sthompsa
163168793Sthompsa	/* Move properties from the new node to the old node.  If there
164168793Sthompsa	 * is a collision, replace the old value with the new */
165168793Sthompsa	while (new_node->proplist) {
166168793Sthompsa		/* Pop the property off the list */
167168793Sthompsa		new_prop = new_node->proplist;
168272161Sglebius		new_node->proplist = new_prop->next;
169272170Sglebius		new_prop->next = NULL;
170272170Sglebius
171272170Sglebius		if (new_prop->deleted) {
172272178Sglebius			delete_property_by_name(old_node, new_prop->name);
173272178Sglebius			free(new_prop);
174272178Sglebius			continue;
175272178Sglebius		}
176272178Sglebius
177272178Sglebius		/* Look for a collision, set new value if there is */
178272178Sglebius		for_each_property_withdel(old_node, old_prop) {
179272178Sglebius			if (streq(old_prop->name, new_prop->name)) {
180272178Sglebius				/* Add new labels to old property */
181272178Sglebius				for_each_label_withdel(new_prop->labels, l)
182272178Sglebius					add_label(&old_prop->labels, l->label);
183168793Sthompsa
184272170Sglebius				old_prop->val = new_prop->val;
185272170Sglebius				old_prop->deleted = 0;
186272170Sglebius				free(new_prop);
187272170Sglebius				new_prop = NULL;
188272170Sglebius				break;
189272170Sglebius			}
190272178Sglebius		}
191272178Sglebius
192272170Sglebius		/* if no collision occurred, add property to the old node. */
193272170Sglebius		if (new_prop)
194272170Sglebius			add_property(old_node, new_prop);
195272178Sglebius	}
196272178Sglebius
197272170Sglebius	/* Move the override child nodes into the primary node.  If
198272170Sglebius	 * there is a collision, then merge the nodes. */
199272170Sglebius	while (new_node->children) {
200272170Sglebius		/* Pop the child node off the list */
201272170Sglebius		new_child = new_node->children;
202272178Sglebius		new_node->children = new_child->next_sibling;
203272178Sglebius		new_child->parent = NULL;
204272178Sglebius		new_child->next_sibling = NULL;
205272178Sglebius
206272170Sglebius		if (new_child->deleted) {
207272170Sglebius			delete_node_by_name(old_node, new_child->name);
208272170Sglebius			free(new_child);
209272170Sglebius			continue;
210272170Sglebius		}
211272178Sglebius
212272178Sglebius		/* Search for a collision.  Merge if there is */
213272178Sglebius		for_each_child_withdel(old_node, old_child) {
214272178Sglebius			if (streq(old_child->name, new_child->name)) {
215272178Sglebius				merge_nodes(old_child, new_child);
216272178Sglebius				new_child = NULL;
217272178Sglebius				break;
218272178Sglebius			}
219272178Sglebius		}
220272178Sglebius
221272170Sglebius		/* if no collision occurred, add child to the old node. */
222272170Sglebius		if (new_child)
223272170Sglebius			add_child(old_node, new_child);
224272178Sglebius	}
225272178Sglebius
226272170Sglebius	/* The new node contents are now merged into the old node.  Free
227168793Sthompsa	 * the new node. */
228168793Sthompsa	free(new_node);
229212100Semaste
230253314Sadrian	return old_node;
231227309Sed}
232212100Semaste
233272386Shrsstruct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
234272386Shrs{
235272386Shrs	static unsigned int next_orphan_fragment = 0;
236272386Shrs	struct node *node;
237272386Shrs	struct property *p;
238212100Semaste	struct data d = empty_data;
239272386Shrs	char *name;
240275358Shselasky
241332318Ssmh	if (ref[0] == '/') {
242272386Shrs		d = data_append_data(d, ref, strlen(ref) + 1);
243267992Shselasky
244272386Shrs		p = build_property("target-path", d);
245232080Sthompsa	} else {
246272386Shrs		d = data_add_marker(d, REF_PHANDLE, ref);
247275358Shselasky		d = data_append_integer(d, 0xffffffff, 32);
248272386Shrs
249272386Shrs		p = build_property("target", d);
250267992Shselasky	}
251272386Shrs
252260070Sscottl	xasprintf(&name, "fragment@%u",
253212100Semaste			next_orphan_fragment++);
254272386Shrs	name_node(new_node, "__overlay__");
255272386Shrs	node = build_node(p, new_node);
256272386Shrs	name_node(node, name);
257272386Shrs
258272386Shrs	add_child(dt, node);
259272386Shrs	return dt;
260272386Shrs}
261272386Shrs
262272386Shrsstruct node *chain_node(struct node *first, struct node *list)
263272386Shrs{
264272386Shrs	assert(first->next_sibling == NULL);
265272386Shrs
266272386Shrs	first->next_sibling = list;
267272386Shrs	return first;
268272386Shrs}
269272386Shrs
270272386Shrsvoid add_property(struct node *node, struct property *prop)
271272386Shrs{
272272386Shrs	struct property **p;
273302054Sbz
274272386Shrs	prop->next = NULL;
275272386Shrs
276168793Sthompsa	p = &node->proplist;
277168793Sthompsa	while (*p)
278168793Sthompsa		p = &((*p)->next);
279168793Sthompsa
280168793Sthompsa	*p = prop;
281168793Sthompsa}
282168793Sthompsa
283168793Sthompsavoid delete_property_by_name(struct node *node, char *name)
284168793Sthompsa{
285168793Sthompsa	struct property *prop = node->proplist;
286168793Sthompsa
287168793Sthompsa	while (prop) {
288168793Sthompsa		if (streq(prop->name, name)) {
289168793Sthompsa			delete_property(prop);
290168793Sthompsa			return;
291168793Sthompsa		}
292168793Sthompsa		prop = prop->next;
293168793Sthompsa	}
294168793Sthompsa}
295168793Sthompsa
296168793Sthompsavoid delete_property(struct property *prop)
297168793Sthompsa{
298168793Sthompsa	prop->deleted = 1;
299168793Sthompsa	delete_labels(&prop->labels);
300168793Sthompsa}
301168793Sthompsa
302168793Sthompsavoid add_child(struct node *parent, struct node *child)
303241394Skevlo{
304168793Sthompsa	struct node **p;
305168793Sthompsa
306168793Sthompsa	child->next_sibling = NULL;
307224571Spluknet	child->parent = parent;
308168793Sthompsa
309272170Sglebius	p = &parent->children;
310272170Sglebius	while (*p)
311272170Sglebius		p = &((*p)->next_sibling);
312272170Sglebius
313318329Smav	*p = child;
314272170Sglebius}
315272170Sglebius
316272170Sglebiusvoid delete_node_by_name(struct node *parent, char *name)
317272170Sglebius{
318272170Sglebius	struct node *node = parent->children;
319272170Sglebius
320272178Sglebius	while (node) {
321272178Sglebius		if (streq(node->name, name)) {
322272170Sglebius			delete_node(node);
323272170Sglebius			return;
324272170Sglebius		}
325272170Sglebius		node = node->next_sibling;
326272170Sglebius	}
327272170Sglebius}
328272170Sglebius
329272170Sglebiusvoid delete_node(struct node *node)
330318329Smav{
331272170Sglebius	struct property *prop;
332272170Sglebius	struct node *child;
333272175Sglebius
334272170Sglebius	node->deleted = 1;
335272170Sglebius	for_each_child(node, child)
336272170Sglebius		delete_node(child);
337272170Sglebius	for_each_property(node, prop)
338272170Sglebius		delete_property(prop);
339272170Sglebius	delete_labels(&node->labels);
340272170Sglebius}
341272178Sglebius
342272178Sglebiusvoid append_to_property(struct node *node,
343272178Sglebius				    char *name, const void *data, int len)
344272178Sglebius{
345272178Sglebius	struct data d;
346272178Sglebius	struct property *p;
347272178Sglebius
348272178Sglebius	p = get_property(node, name);
349272178Sglebius	if (p) {
350272178Sglebius		d = data_append_data(p->val, data, len);
351272178Sglebius		p->val = d;
352272178Sglebius	} else {
353272178Sglebius		d = data_append_data(empty_data, data, len);
354272178Sglebius		p = build_property(name, d);
355272178Sglebius		add_property(node, p);
356272178Sglebius	}
357272178Sglebius}
358272178Sglebius
359272178Sglebiusstruct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
360272178Sglebius{
361272178Sglebius	struct reserve_info *new = xmalloc(sizeof(*new));
362272178Sglebius
363272178Sglebius	memset(new, 0, sizeof(*new));
364272178Sglebius
365272178Sglebius	new->address = address;
366272178Sglebius	new->size = size;
367272178Sglebius
368272178Sglebius	return new;
369272178Sglebius}
370272178Sglebius
371272178Sglebiusstruct reserve_info *chain_reserve_entry(struct reserve_info *first,
372272178Sglebius					struct reserve_info *list)
373272178Sglebius{
374272178Sglebius	assert(first->next == NULL);
375272178Sglebius
376272178Sglebius	first->next = list;
377272178Sglebius	return first;
378272178Sglebius}
379272178Sglebius
380272178Sglebiusstruct reserve_info *add_reserve_entry(struct reserve_info *list,
381272178Sglebius				      struct reserve_info *new)
382272178Sglebius{
383272178Sglebius	struct reserve_info *last;
384272178Sglebius
385272178Sglebius	new->next = NULL;
386272178Sglebius
387272178Sglebius	if (! list)
388272178Sglebius		return new;
389272178Sglebius
390272178Sglebius	for (last = list; last->next; last = last->next)
391272178Sglebius		;
392272178Sglebius
393272178Sglebius	last->next = new;
394272178Sglebius
395272178Sglebius	return list;
396272178Sglebius}
397272178Sglebius
398272178Sglebiusstruct dt_info *build_dt_info(unsigned int dtsflags,
399272178Sglebius			      struct reserve_info *reservelist,
400272178Sglebius			      struct node *tree, uint32_t boot_cpuid_phys)
401272178Sglebius{
402272178Sglebius	struct dt_info *dti;
403272178Sglebius
404272178Sglebius	dti = xmalloc(sizeof(*dti));
405272178Sglebius	dti->dtsflags = dtsflags;
406272178Sglebius	dti->reservelist = reservelist;
407272178Sglebius	dti->dt = tree;
408272178Sglebius	dti->boot_cpuid_phys = boot_cpuid_phys;
409272178Sglebius
410272178Sglebius	return dti;
411272178Sglebius}
412272178Sglebius
413272178Sglebius/*
414272178Sglebius * Tree accessor functions
415272178Sglebius */
416272178Sglebius
417272178Sglebiusconst char *get_unitname(struct node *node)
418272178Sglebius{
419272178Sglebius	if (node->name[node->basenamelen] == '\0')
420272178Sglebius		return "";
421203548Seri	else
422203548Seri		return node->name + node->basenamelen + 1;
423203548Seri}
424203548Seri
425203548Seristruct property *get_property(struct node *node, const char *propname)
426203548Seri{
427203548Seri	struct property *prop;
428272175Sglebius
429272175Sglebius	for_each_property(node, prop)
430203548Seri		if (streq(prop->name, propname))
431272175Sglebius			return prop;
432272175Sglebius
433203548Seri	return NULL;
434318329Smav}
435317699Smav
436317699Smavcell_t propval_cell(struct property *prop)
437318329Smav{
438203548Seri	assert(prop->val.len == sizeof(cell_t));
439203548Seri	return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
440203548Seri}
441203548Seri
442203548Sericell_t propval_cell_n(struct property *prop, int n)
443203548Seri{
444203548Seri	assert(prop->val.len / sizeof(cell_t) >= n);
445203548Seri	return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
446203548Seri}
447272175Sglebius
448272175Sglebiusstruct property *get_property_by_label(struct node *tree, const char *label,
449203548Seri				       struct node **node)
450272175Sglebius{
451272175Sglebius	struct property *prop;
452203548Seri	struct node *c;
453318329Smav
454317699Smav	*node = tree;
455317699Smav
456318329Smav	for_each_property(tree, prop) {
457203548Seri		struct label *l;
458203548Seri
459168793Sthompsa		for_each_label(prop->labels, l)
460168793Sthompsa			if (streq(l->label, label))
461168793Sthompsa				return prop;
462168793Sthompsa	}
463168793Sthompsa
464168793Sthompsa	for_each_child(tree, c) {
465168793Sthompsa		prop = get_property_by_label(c, label, node);
466168793Sthompsa		if (prop)
467168793Sthompsa			return prop;
468168793Sthompsa	}
469168793Sthompsa
470168793Sthompsa	*node = NULL;
471168793Sthompsa	return NULL;
472318329Smav}
473318329Smav
474168793Sthompsastruct marker *get_marker_label(struct node *tree, const char *label,
475318329Smav				struct node **node, struct property **prop)
476272386Shrs{
477272386Shrs	struct marker *m;
478272386Shrs	struct property *p;
479272386Shrs	struct node *c;
480232629Sthompsa
481279891Shselasky	*node = tree;
482232008Sthompsa
483272170Sglebius	for_each_property(tree, p) {
484272170Sglebius		*prop = p;
485168793Sthompsa		m = p->val.markers;
486168793Sthompsa		for_each_marker_of_type(m, LABEL)
487168793Sthompsa			if (streq(m->ref, label))
488168793Sthompsa				return m;
489168793Sthompsa	}
490168793Sthompsa
491168793Sthompsa	for_each_child(tree, c) {
492168793Sthompsa		m = get_marker_label(c, label, node, prop);
493241610Sglebius		if (m)
494168793Sthompsa			return m;
495240742Sglebius	}
496240742Sglebius
497168793Sthompsa	*prop = NULL;
498168793Sthompsa	*node = NULL;
499272211Smelifaro	return NULL;
500168793Sthompsa}
501256218Sglebius
502168793Sthompsastruct node *get_subnode(struct node *node, const char *nodename)
503168793Sthompsa{
504227459Sbrooks	struct node *child;
505168793Sthompsa
506168793Sthompsa	for_each_child(node, child)
507168793Sthompsa		if (streq(child->name, nodename))
508168793Sthompsa			return child;
509203548Seri
510203548Seri	return NULL;
511203548Seri}
512203548Seri
513203548Seristruct node *get_node_by_path(struct node *tree, const char *path)
514168793Sthompsa{
515272386Shrs	const char *p;
516272386Shrs	struct node *child;
517272386Shrs
518318329Smav	if (!path || ! (*path)) {
519168793Sthompsa		if (tree->deleted)
520168793Sthompsa			return NULL;
521168793Sthompsa		return tree;
522168793Sthompsa	}
523168793Sthompsa
524168793Sthompsa	while (path[0] == '/')
525168793Sthompsa		path++;
526168793Sthompsa
527168793Sthompsa	p = strchr(path, '/');
528168793Sthompsa
529318329Smav	for_each_child(tree, child) {
530318329Smav		if (p && (strlen(child->name) == p-path) &&
531168793Sthompsa		    strprefixeq(path, p - path, child->name))
532168793Sthompsa			return get_node_by_path(child, p+1);
533168793Sthompsa		else if (!p && streq(path, child->name))
534203548Seri			return child;
535203548Seri	}
536203548Seri
537168793Sthompsa	return NULL;
538318329Smav}
539168793Sthompsa
540318329Smavstruct node *get_node_by_label(struct node *tree, const char *label)
541168793Sthompsa{
542318329Smav	struct node *child, *node;
543272170Sglebius	struct label *l;
544290239Smelifaro
545318329Smav	assert(label && (strlen(label) > 0));
546168793Sthompsa
547168793Sthompsa	for_each_label(tree->labels, l)
548168793Sthompsa		if (streq(l->label, label))
549227459Sbrooks			return tree;
550168793Sthompsa
551272386Shrs	for_each_child(tree, child) {
552272386Shrs		node = get_node_by_label(child, label);
553272386Shrs		if (node)
554168793Sthompsa			return node;
555318329Smav	}
556168793Sthompsa
557168793Sthompsa	return NULL;
558168793Sthompsa}
559168793Sthompsa
560171661Sthompsastruct node *get_node_by_phandle(struct node *tree, cell_t phandle)
561168793Sthompsa{
562168793Sthompsa	struct node *child, *node;
563168793Sthompsa
564319696Smav	if ((phandle == 0) || (phandle == -1)) {
565319696Smav		assert(generate_fixups);
566271946Shselasky		return NULL;
567168793Sthompsa	}
568318329Smav
569168793Sthompsa	if (tree->phandle == phandle) {
570319696Smav		if (tree->deleted)
571319696Smav			return NULL;
572319696Smav		return tree;
573319696Smav	}
574319696Smav
575319696Smav	for_each_child(tree, child) {
576319696Smav		node = get_node_by_phandle(child, phandle);
577319696Smav		if (node)
578319696Smav			return node;
579319696Smav	}
580319696Smav
581319696Smav	return NULL;
582319696Smav}
583319696Smav
584319696Smavstruct node *get_node_by_ref(struct node *tree, const char *ref)
585319696Smav{
586319696Smav	if (streq(ref, "/"))
587319696Smav		return tree;
588319696Smav	else if (ref[0] == '/')
589319696Smav		return get_node_by_path(tree, ref);
590319696Smav	else
591271946Shselasky		return get_node_by_label(tree, ref);
592171661Sthompsa}
593171661Sthompsa
594186195Sthompsacell_t get_node_phandle(struct node *root, struct node *node)
595271946Shselasky{
596171661Sthompsa	static cell_t phandle = 1; /* FIXME: ick, static local */
597171661Sthompsa
598319696Smav	if ((node->phandle != 0) && (node->phandle != -1))
599168793Sthompsa		return node->phandle;
600171661Sthompsa
601186195Sthompsa	while (get_node_by_phandle(root, phandle))
602264469Srmacklem		phandle++;
603271946Shselasky
604171661Sthompsa	node->phandle = phandle;
605171661Sthompsa
606186195Sthompsa	if (!get_property(node, "linux,phandle")
607171661Sthompsa	    && (phandle_format & PHANDLE_LEGACY))
608171661Sthompsa		add_property(node,
609171661Sthompsa			     build_property("linux,phandle",
610171661Sthompsa					    data_append_cell(empty_data, phandle)));
611171661Sthompsa
612168793Sthompsa	if (!get_property(node, "phandle")
613168793Sthompsa	    && (phandle_format & PHANDLE_EPAPR))
614168793Sthompsa		add_property(node,
615168793Sthompsa			     build_property("phandle",
616168793Sthompsa					    data_append_cell(empty_data, phandle)));
617168793Sthompsa
618168793Sthompsa	/* If the node *does* have a phandle property, we must
619272176Sae	 * be dealing with a self-referencing phandle, which will be
620342206Smav	 * fixed up momentarily in the caller */
621342206Smav
622272211Smelifaro	return node->phandle;
623168793Sthompsa}
624318329Smav
625168793Sthompsauint32_t guess_boot_cpuid(struct node *tree)
626342206Smav{
627342206Smav	struct node *cpus, *bootcpu;
628342206Smav	struct property *reg;
629342206Smav
630342206Smav	cpus = get_node_by_path(tree, "/cpus");
631342206Smav	if (!cpus)
632168793Sthompsa		return 0;
633168793Sthompsa
634168793Sthompsa
635168793Sthompsa	bootcpu = cpus->children;
636168793Sthompsa	if (!bootcpu)
637236178Srea		return 0;
638236178Srea
639236178Srea	reg = get_property(bootcpu, "reg");
640236178Srea	if (!reg || (reg->val.len != sizeof(uint32_t)))
641236178Srea		return 0;
642168793Sthompsa
643236178Srea	/* FIXME: Sanity check node? */
644168793Sthompsa
645168793Sthompsa	return propval_cell(reg);
646290239Smelifaro}
647168793Sthompsa
648168793Sthompsastatic int cmp_reserve_info(const void *ax, const void *bx)
649171661Sthompsa{
650342206Smav	const struct reserve_info *a, *b;
651342206Smav
652171661Sthompsa	a = *((const struct reserve_info * const *)ax);
653342206Smav	b = *((const struct reserve_info * const *)bx);
654342206Smav
655342206Smav	if (a->address < b->address)
656342206Smav		return -1;
657342206Smav	else if (a->address > b->address)
658342206Smav		return 1;
659342206Smav	else if (a->size < b->size)
660342206Smav		return -1;
661342206Smav	else if (a->size > b->size)
662342206Smav		return 1;
663342206Smav	else
664342206Smav		return 0;
665342206Smav}
666342206Smav
667342206Smavstatic void sort_reserve_entries(struct dt_info *dti)
668342206Smav{
669171661Sthompsa	struct reserve_info *ri, **tbl;
670171661Sthompsa	int n = 0, i = 0;
671318329Smav
672318329Smav	for (ri = dti->reservelist;
673168793Sthompsa	     ri;
674168793Sthompsa	     ri = ri->next)
675272386Shrs		n++;
676272386Shrs
677168793Sthompsa	if (n == 0)
678272386Shrs		return;
679168793Sthompsa
680342206Smav	tbl = xmalloc(n * sizeof(*tbl));
681342206Smav
682342206Smav	for (ri = dti->reservelist;
683168793Sthompsa	     ri;
684201803Strasz	     ri = ri->next)
685201803Strasz		tbl[i++] = ri;
686168793Sthompsa
687168793Sthompsa	qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
688168793Sthompsa
689272386Shrs	dti->reservelist = tbl[0];
690168793Sthompsa	for (i = 0; i < (n-1); i++)
691342206Smav		tbl[i]->next = tbl[i+1];
692342206Smav	tbl[n-1]->next = NULL;
693342206Smav
694168793Sthompsa	free(tbl);
695168793Sthompsa}
696201803Strasz
697168793Sthompsastatic int cmp_prop(const void *ax, const void *bx)
698168793Sthompsa{
699272386Shrs	const struct property *a, *b;
700168793Sthompsa
701318329Smav	a = *((const struct property * const *)ax);
702318329Smav	b = *((const struct property * const *)bx);
703318329Smav
704318329Smav	return strcmp(a->name, b->name);
705318329Smav}
706318329Smav
707318329Smavstatic void sort_properties(struct node *node)
708318329Smav{
709318329Smav	int n = 0, i = 0;
710318329Smav	struct property *prop, **tbl;
711318329Smav
712318329Smav	for_each_property_withdel(node, prop)
713318329Smav		n++;
714318329Smav
715318329Smav	if (n == 0)
716318329Smav		return;
717318329Smav
718318329Smav	tbl = xmalloc(n * sizeof(*tbl));
719318329Smav
720318329Smav	for_each_property_withdel(node, prop)
721168793Sthompsa		tbl[i++] = prop;
722168793Sthompsa
723168793Sthompsa	qsort(tbl, n, sizeof(*tbl), cmp_prop);
724168793Sthompsa
725168793Sthompsa	node->proplist = tbl[0];
726168793Sthompsa	for (i = 0; i < (n-1); i++)
727168793Sthompsa		tbl[i]->next = tbl[i+1];
728168793Sthompsa	tbl[n-1]->next = NULL;
729168793Sthompsa
730318329Smav	free(tbl);
731318329Smav}
732318329Smav
733318329Smavstatic int cmp_subnode(const void *ax, const void *bx)
734168793Sthompsa{
735277295Sae	const struct node *a, *b;
736277295Sae
737277295Sae	a = *((const struct node * const *)ax);
738277295Sae	b = *((const struct node * const *)bx);
739277295Sae
740277295Sae	return strcmp(a->name, b->name);
741272176Sae}
742272176Sae
743272176Saestatic void sort_subnodes(struct node *node)
744277295Sae{
745272176Sae	int n = 0, i = 0;
746272176Sae	struct node *subnode, **tbl;
747272176Sae
748272176Sae	for_each_child_withdel(node, subnode)
749272176Sae		n++;
750272176Sae
751272176Sae	if (n == 0)
752168793Sthompsa		return;
753168793Sthompsa
754318329Smav	tbl = xmalloc(n * sizeof(*tbl));
755168793Sthompsa
756272178Sglebius	for_each_child_withdel(node, subnode)
757272178Sglebius		tbl[i++] = subnode;
758168793Sthompsa
759342206Smav	qsort(tbl, n, sizeof(*tbl), cmp_subnode);
760342206Smav
761318329Smav	node->children = tbl[0];
762168793Sthompsa	for (i = 0; i < (n-1); i++)
763168793Sthompsa		tbl[i]->next_sibling = tbl[i+1];
764168793Sthompsa	tbl[n-1]->next_sibling = NULL;
765318329Smav
766318329Smav	free(tbl);
767318329Smav}
768318329Smav
769318329Smavstatic void sort_node(struct node *node)
770318329Smav{
771272178Sglebius	struct node *c;
772168793Sthompsa
773168793Sthompsa	sort_properties(node);
774201803Strasz	sort_subnodes(node);
775168793Sthompsa	for_each_child_withdel(node, c)
776168793Sthompsa		sort_node(c);
777168793Sthompsa}
778168793Sthompsa
779168793Sthompsavoid sort_tree(struct dt_info *dti)
780168793Sthompsa{
781168793Sthompsa	sort_reserve_entries(dti);
782318329Smav	sort_node(dti->dt);
783168793Sthompsa}
784168793Sthompsa
785168793Sthompsa/* utility helper to avoid code duplication */
786168793Sthompsastatic struct node *build_and_name_child_node(struct node *parent, char *name)
787168793Sthompsa{
788168793Sthompsa	struct node *node;
789168793Sthompsa
790168793Sthompsa	node = build_node(NULL, NULL);
791168793Sthompsa	name_node(node, xstrdup(name));
792201803Strasz	add_child(parent, node);
793168793Sthompsa
794168793Sthompsa	return node;
795272178Sglebius}
796168793Sthompsa
797170599Sthompsastatic struct node *build_root_node(struct node *dt, char *name)
798288980Shrs{
799168793Sthompsa	struct node *an;
800272211Smelifaro
801272211Smelifaro	an = get_subnode(dt, name);
802168793Sthompsa	if (!an)
803318329Smav		an = build_and_name_child_node(dt, name);
804168793Sthompsa
805318329Smav	if (!an)
806318329Smav		die("Could not build root node /%s\n", name);
807272178Sglebius
808318329Smav	return an;
809318329Smav}
810168793Sthompsa
811318329Smavstatic bool any_label_tree(struct dt_info *dti, struct node *node)
812318329Smav{
813168793Sthompsa	struct node *c;
814168793Sthompsa
815168793Sthompsa	if (node->labels)
816168793Sthompsa		return true;
817168793Sthompsa
818168793Sthompsa	for_each_child(node, c)
819168793Sthompsa		if (any_label_tree(dti, c))
820272211Smelifaro			return true;
821272211Smelifaro
822272354Sglebius	return false;
823272211Smelifaro}
824272244Sglebius
825272211Smelifarostatic void generate_label_tree_internal(struct dt_info *dti,
826272211Smelifaro					 struct node *an, struct node *node,
827168793Sthompsa					 bool allocph)
828168793Sthompsa{
829168793Sthompsa	struct node *dt = dti->dt;
830168793Sthompsa	struct node *c;
831168793Sthompsa	struct property *p;
832168793Sthompsa	struct label *l;
833168793Sthompsa
834168793Sthompsa	/* if there are labels */
835318329Smav	if (node->labels) {
836168793Sthompsa
837318329Smav		/* now add the label in the node */
838318329Smav		for_each_label(node->labels, l) {
839290239Smelifaro
840318329Smav			/* check whether the label already exists */
841318329Smav			p = get_property(an, l->label);
842318329Smav			if (p) {
843318329Smav				fprintf(stderr, "WARNING: label %s already"
844318329Smav					" exists in /%s", l->label,
845318329Smav					an->name);
846318329Smav				continue;
847290239Smelifaro			}
848288980Shrs
849318329Smav			/* insert it */
850318329Smav			p = build_property(l->label,
851288980Shrs				data_copy_mem(node->fullpath,
852168793Sthompsa						strlen(node->fullpath) + 1));
853318329Smav			add_property(an, p);
854318329Smav		}
855318329Smav
856168793Sthompsa		/* force allocation of a phandle for this node */
857168793Sthompsa		if (allocph)
858168793Sthompsa			(void)get_node_phandle(dt, node);
859168793Sthompsa	}
860318329Smav
861318329Smav	for_each_child(node, c)
862318329Smav		generate_label_tree_internal(dti, an, c, allocph);
863318329Smav}
864318329Smav
865318329Smavstatic bool any_fixup_tree(struct dt_info *dti, struct node *node)
866317698Smav{
867168793Sthompsa	struct node *c;
868168793Sthompsa	struct property *prop;
869168793Sthompsa	struct marker *m;
870171661Sthompsa
871173895Sthompsa	for_each_property(node, prop) {
872168793Sthompsa		m = prop->val.markers;
873168793Sthompsa		for_each_marker_of_type(m, REF_PHANDLE) {
874168793Sthompsa			if (!get_node_by_ref(dti->dt, m->ref))
875168793Sthompsa				return true;
876168793Sthompsa		}
877168793Sthompsa	}
878168793Sthompsa
879168793Sthompsa	for_each_child(node, c) {
880168793Sthompsa		if (any_fixup_tree(dti, c))
881168793Sthompsa			return true;
882168793Sthompsa	}
883168793Sthompsa
884168793Sthompsa	return false;
885168793Sthompsa}
886170599Sthompsa
887168793Sthompsastatic void add_fixup_entry(struct dt_info *dti, struct node *fn,
888168793Sthompsa			    struct node *node, struct property *prop,
889168793Sthompsa			    struct marker *m)
890168793Sthompsa{
891168793Sthompsa	char *entry;
892168793Sthompsa
893168793Sthompsa	/* m->ref can only be a REF_PHANDLE, but check anyway */
894168793Sthompsa	assert(m->type == REF_PHANDLE);
895168793Sthompsa
896168793Sthompsa	/* there shouldn't be any ':' in the arguments */
897318329Smav	if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
898171603Sthompsa		die("arguments should not contain ':'\n");
899168793Sthompsa
900318329Smav	xasprintf(&entry, "%s:%s:%u",
901168793Sthompsa			node->fullpath, prop->name, m->offset);
902168793Sthompsa	append_to_property(fn, m->ref, entry, strlen(entry) + 1);
903168793Sthompsa
904168793Sthompsa	free(entry);
905318329Smav}
906168793Sthompsa
907171661Sthompsastatic void generate_fixups_tree_internal(struct dt_info *dti,
908171661Sthompsa					  struct node *fn,
909171661Sthompsa					  struct node *node)
910171661Sthompsa{
911171661Sthompsa	struct node *dt = dti->dt;
912171661Sthompsa	struct node *c;
913171661Sthompsa	struct property *prop;
914171661Sthompsa	struct marker *m;
915171661Sthompsa	struct node *refnode;
916171661Sthompsa
917171661Sthompsa	for_each_property(node, prop) {
918318329Smav		m = prop->val.markers;
919171661Sthompsa		for_each_marker_of_type(m, REF_PHANDLE) {
920318329Smav			refnode = get_node_by_ref(dt, m->ref);
921319697Smav			if (!refnode)
922171661Sthompsa				add_fixup_entry(dti, fn, node, prop, m);
923171661Sthompsa		}
924171661Sthompsa	}
925171661Sthompsa
926171661Sthompsa	for_each_child(node, c)
927171661Sthompsa		generate_fixups_tree_internal(dti, fn, c);
928171661Sthompsa}
929168793Sthompsa
930168793Sthompsastatic bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
931168793Sthompsa{
932168793Sthompsa	struct node *c;
933168793Sthompsa	struct property *prop;
934168793Sthompsa	struct marker *m;
935168793Sthompsa
936313108Sasomers	for_each_property(node, prop) {
937168793Sthompsa		m = prop->val.markers;
938168793Sthompsa		for_each_marker_of_type(m, REF_PHANDLE) {
939168793Sthompsa			if (get_node_by_ref(dti->dt, m->ref))
940168793Sthompsa				return true;
941168793Sthompsa		}
942234936Semaste	}
943272211Smelifaro
944272211Smelifaro	for_each_child(node, c) {
945272211Smelifaro		if (any_local_fixup_tree(dti, c))
946272211Smelifaro			return true;
947272211Smelifaro	}
948272211Smelifaro
949272211Smelifaro	return false;
950272211Smelifaro}
951272211Smelifaro
952272211Smelifarostatic void add_local_fixup_entry(struct dt_info *dti,
953272211Smelifaro		struct node *lfn, struct node *node,
954272211Smelifaro		struct property *prop, struct marker *m,
955272211Smelifaro		struct node *refnode)
956272211Smelifaro{
957272211Smelifaro	struct node *wn, *nwn;	/* local fixup node, walk node, new */
958272211Smelifaro	fdt32_t value_32;
959272211Smelifaro	char **compp;
960272211Smelifaro	int i, depth;
961272211Smelifaro
962272211Smelifaro	/* walk back retreiving depth */
963272211Smelifaro	depth = 0;
964272244Sglebius	for (wn = node; wn; wn = wn->parent)
965272244Sglebius		depth++;
966272211Smelifaro
967272211Smelifaro	/* allocate name array */
968272211Smelifaro	compp = xmalloc(sizeof(*compp) * depth);
969272211Smelifaro
970272211Smelifaro	/* store names in the array */
971272211Smelifaro	for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
972272211Smelifaro		compp[i] = wn->name;
973272244Sglebius
974272211Smelifaro	/* walk the path components creating nodes if they don't exist */
975272211Smelifaro	for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
976272211Smelifaro		/* if no node exists, create it */
977272211Smelifaro		nwn = get_subnode(wn, compp[i]);
978272211Smelifaro		if (!nwn)
979272211Smelifaro			nwn = build_and_name_child_node(wn, compp[i]);
980272211Smelifaro	}
981272211Smelifaro
982272211Smelifaro	free(compp);
983272211Smelifaro
984272211Smelifaro	value_32 = cpu_to_fdt32(m->offset);
985272211Smelifaro	append_to_property(wn, prop->name, &value_32, sizeof(value_32));
986272211Smelifaro}
987272211Smelifaro
988272211Smelifarostatic void generate_local_fixups_tree_internal(struct dt_info *dti,
989272211Smelifaro						struct node *lfn,
990272244Sglebius						struct node *node)
991272211Smelifaro{
992272211Smelifaro	struct node *dt = dti->dt;
993272211Smelifaro	struct node *c;
994272211Smelifaro	struct property *prop;
995272211Smelifaro	struct marker *m;
996272211Smelifaro	struct node *refnode;
997272211Smelifaro
998234936Semaste	for_each_property(node, prop) {
999234936Semaste		m = prop->val.markers;
1000168793Sthompsa		for_each_marker_of_type(m, REF_PHANDLE) {
1001168793Sthompsa			refnode = get_node_by_ref(dt, m->ref);
1002249925Sglebius			if (refnode)
1003168793Sthompsa				add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
1004168793Sthompsa		}
1005168793Sthompsa	}
1006168793Sthompsa
1007168793Sthompsa	for_each_child(node, c)
1008168793Sthompsa		generate_local_fixups_tree_internal(dti, lfn, c);
1009191148Skmacy}
1010168793Sthompsa
1011168793Sthompsavoid generate_label_tree(struct dt_info *dti, char *name, bool allocph)
1012168793Sthompsa{
1013168793Sthompsa	if (!any_label_tree(dti, dti->dt))
1014245741Sglebius		return;
1015168793Sthompsa	generate_label_tree_internal(dti, build_root_node(dti->dt, name),
1016168793Sthompsa				     dti->dt, allocph);
1017168793Sthompsa}
1018168793Sthompsa
1019168793Sthompsavoid generate_fixups_tree(struct dt_info *dti, char *name)
1020168793Sthompsa{
1021168793Sthompsa	if (!any_fixup_tree(dti, dti->dt))
1022168793Sthompsa		return;
1023168793Sthompsa	generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
1024168793Sthompsa				      dti->dt);
1025237852Sthompsa}
1026237852Sthompsa
1027237852Sthompsavoid generate_local_fixups_tree(struct dt_info *dti, char *name)
1028168793Sthompsa{
1029170599Sthompsa	if (!any_local_fixup_tree(dti, dti->dt))
1030168793Sthompsa		return;
1031318329Smav	generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
1032318329Smav					    dti->dt);
1033168793Sthompsa}
1034318329Smav