checks.c revision 204433
1204431Sraj/*
2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2007.
3204431Sraj *
4204431Sraj *
5204431Sraj * This program is free software; you can redistribute it and/or
6204431Sraj * modify it under the terms of the GNU General Public License as
7204431Sraj * published by the Free Software Foundation; either version 2 of the
8204431Sraj * License, or (at your option) any later version.
9204431Sraj *
10204431Sraj *  This program is distributed in the hope that it will be useful,
11204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13204431Sraj *  General Public License for more details.
14204431Sraj *
15204431Sraj *  You should have received a copy of the GNU General Public License
16204431Sraj *  along with this program; if not, write to the Free Software
17204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18204431Sraj *                                                                   USA
19204431Sraj */
20204431Sraj
21204431Sraj#include "dtc.h"
22204431Sraj
23204431Sraj#ifdef TRACE_CHECKS
24204431Sraj#define TRACE(c, ...) \
25204431Sraj	do { \
26204431Sraj		fprintf(stderr, "=== %s: ", (c)->name); \
27204431Sraj		fprintf(stderr, __VA_ARGS__); \
28204431Sraj		fprintf(stderr, "\n"); \
29204431Sraj	} while (0)
30204431Sraj#else
31204431Sraj#define TRACE(c, fmt, ...)	do { } while (0)
32204431Sraj#endif
33204431Sraj
34204431Srajenum checklevel {
35204431Sraj	IGNORE = 0,
36204431Sraj	WARN = 1,
37204431Sraj	ERROR = 2,
38204431Sraj};
39204431Sraj
40204431Srajenum checkstatus {
41204431Sraj	UNCHECKED = 0,
42204431Sraj	PREREQ,
43204431Sraj	PASSED,
44204431Sraj	FAILED,
45204431Sraj};
46204431Sraj
47204431Srajstruct check;
48204431Sraj
49204431Srajtypedef void (*tree_check_fn)(struct check *c, struct node *dt);
50204431Srajtypedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
51204431Srajtypedef void (*prop_check_fn)(struct check *c, struct node *dt,
52204431Sraj			      struct node *node, struct property *prop);
53204431Sraj
54204431Srajstruct check {
55204431Sraj	const char *name;
56204431Sraj	tree_check_fn tree_fn;
57204431Sraj	node_check_fn node_fn;
58204431Sraj	prop_check_fn prop_fn;
59204431Sraj	void *data;
60204431Sraj	enum checklevel level;
61204431Sraj	enum checkstatus status;
62204431Sraj	int inprogress;
63204431Sraj	int num_prereqs;
64204431Sraj	struct check **prereq;
65204431Sraj};
66204431Sraj
67204431Sraj#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \
68204431Sraj	static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
69204431Sraj	static struct check nm = { \
70204431Sraj		.name = #nm, \
71204431Sraj		.tree_fn = (tfn), \
72204431Sraj		.node_fn = (nfn), \
73204431Sraj		.prop_fn = (pfn), \
74204431Sraj		.data = (d), \
75204431Sraj		.level = (lvl), \
76204431Sraj		.status = UNCHECKED, \
77204431Sraj		.num_prereqs = ARRAY_SIZE(nm##_prereqs), \
78204431Sraj		.prereq = nm##_prereqs, \
79204431Sraj	};
80204431Sraj
81204431Sraj#define TREE_CHECK(nm, d, lvl, ...) \
82204431Sraj	CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__)
83204431Sraj#define NODE_CHECK(nm, d, lvl, ...) \
84204431Sraj	CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__)
85204431Sraj#define PROP_CHECK(nm, d, lvl, ...) \
86204431Sraj	CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__)
87204431Sraj#define BATCH_CHECK(nm, lvl, ...) \
88204431Sraj	CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__)
89204431Sraj
90204431Sraj#ifdef __GNUC__
91204431Srajstatic inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
92204431Sraj#endif
93204431Srajstatic inline void check_msg(struct check *c, const char *fmt, ...)
94204431Sraj{
95204431Sraj	va_list ap;
96204431Sraj	va_start(ap, fmt);
97204431Sraj
98204431Sraj	if ((c->level < WARN) || (c->level <= quiet))
99204431Sraj		return; /* Suppress message */
100204431Sraj
101204431Sraj	fprintf(stderr, "%s (%s): ",
102204431Sraj		(c->level == ERROR) ? "ERROR" : "Warning", c->name);
103204431Sraj	vfprintf(stderr, fmt, ap);
104204431Sraj	fprintf(stderr, "\n");
105204431Sraj}
106204431Sraj
107204431Sraj#define FAIL(c, ...) \
108204431Sraj	do { \
109204431Sraj		TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
110204431Sraj		(c)->status = FAILED; \
111204431Sraj		check_msg((c), __VA_ARGS__); \
112204431Sraj	} while (0)
113204431Sraj
114204431Srajstatic void check_nodes_props(struct check *c, struct node *dt, struct node *node)
115204431Sraj{
116204431Sraj	struct node *child;
117204431Sraj	struct property *prop;
118204431Sraj
119204431Sraj	TRACE(c, "%s", node->fullpath);
120204431Sraj	if (c->node_fn)
121204431Sraj		c->node_fn(c, dt, node);
122204431Sraj
123204431Sraj	if (c->prop_fn)
124204431Sraj		for_each_property(node, prop) {
125204431Sraj			TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
126204431Sraj			c->prop_fn(c, dt, node, prop);
127204431Sraj		}
128204431Sraj
129204431Sraj	for_each_child(node, child)
130204431Sraj		check_nodes_props(c, dt, child);
131204431Sraj}
132204431Sraj
133204431Srajstatic int run_check(struct check *c, struct node *dt)
134204431Sraj{
135204431Sraj	int error = 0;
136204431Sraj	int i;
137204431Sraj
138204431Sraj	assert(!c->inprogress);
139204431Sraj
140204431Sraj	if (c->status != UNCHECKED)
141204431Sraj		goto out;
142204431Sraj
143204431Sraj	c->inprogress = 1;
144204431Sraj
145204431Sraj	for (i = 0; i < c->num_prereqs; i++) {
146204431Sraj		struct check *prq = c->prereq[i];
147204431Sraj		error |= run_check(prq, dt);
148204431Sraj		if (prq->status != PASSED) {
149204431Sraj			c->status = PREREQ;
150204431Sraj			check_msg(c, "Failed prerequisite '%s'",
151204431Sraj				  c->prereq[i]->name);
152204431Sraj		}
153204431Sraj	}
154204431Sraj
155204431Sraj	if (c->status != UNCHECKED)
156204431Sraj		goto out;
157204431Sraj
158204431Sraj	if (c->node_fn || c->prop_fn)
159204431Sraj		check_nodes_props(c, dt, dt);
160204431Sraj
161204431Sraj	if (c->tree_fn)
162204431Sraj		c->tree_fn(c, dt);
163204431Sraj	if (c->status == UNCHECKED)
164204431Sraj		c->status = PASSED;
165204431Sraj
166204431Sraj	TRACE(c, "\tCompleted, status %d", c->status);
167204431Sraj
168204431Srajout:
169204431Sraj	c->inprogress = 0;
170204431Sraj	if ((c->status != PASSED) && (c->level == ERROR))
171204431Sraj		error = 1;
172204431Sraj	return error;
173204431Sraj}
174204431Sraj
175204431Sraj/*
176204431Sraj * Utility check functions
177204431Sraj */
178204431Sraj
179204431Srajstatic void check_is_string(struct check *c, struct node *root,
180204431Sraj			    struct node *node)
181204431Sraj{
182204431Sraj	struct property *prop;
183204431Sraj	char *propname = c->data;
184204431Sraj
185204431Sraj	prop = get_property(node, propname);
186204431Sraj	if (!prop)
187204431Sraj		return; /* Not present, assumed ok */
188204431Sraj
189204431Sraj	if (!data_is_one_string(prop->val))
190204431Sraj		FAIL(c, "\"%s\" property in %s is not a string",
191204431Sraj		     propname, node->fullpath);
192204431Sraj}
193204431Sraj#define CHECK_IS_STRING(nm, propname, lvl) \
194204431Sraj	CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl))
195204431Sraj
196204431Srajstatic void check_is_cell(struct check *c, struct node *root,
197204431Sraj			  struct node *node)
198204431Sraj{
199204431Sraj	struct property *prop;
200204431Sraj	char *propname = c->data;
201204431Sraj
202204431Sraj	prop = get_property(node, propname);
203204431Sraj	if (!prop)
204204431Sraj		return; /* Not present, assumed ok */
205204431Sraj
206204431Sraj	if (prop->val.len != sizeof(cell_t))
207204431Sraj		FAIL(c, "\"%s\" property in %s is not a single cell",
208204431Sraj		     propname, node->fullpath);
209204431Sraj}
210204431Sraj#define CHECK_IS_CELL(nm, propname, lvl) \
211204431Sraj	CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl))
212204431Sraj
213204431Sraj/*
214204431Sraj * Structural check functions
215204431Sraj */
216204431Sraj
217204431Srajstatic void check_duplicate_node_names(struct check *c, struct node *dt,
218204431Sraj				       struct node *node)
219204431Sraj{
220204431Sraj	struct node *child, *child2;
221204431Sraj
222204431Sraj	for_each_child(node, child)
223204431Sraj		for (child2 = child->next_sibling;
224204431Sraj		     child2;
225204431Sraj		     child2 = child2->next_sibling)
226204431Sraj			if (streq(child->name, child2->name))
227204431Sraj				FAIL(c, "Duplicate node name %s",
228204431Sraj				     child->fullpath);
229204431Sraj}
230204431SrajNODE_CHECK(duplicate_node_names, NULL, ERROR);
231204431Sraj
232204431Srajstatic void check_duplicate_property_names(struct check *c, struct node *dt,
233204431Sraj					   struct node *node)
234204431Sraj{
235204431Sraj	struct property *prop, *prop2;
236204431Sraj
237204431Sraj	for_each_property(node, prop)
238204431Sraj		for (prop2 = prop->next; prop2; prop2 = prop2->next)
239204431Sraj			if (streq(prop->name, prop2->name))
240204431Sraj				FAIL(c, "Duplicate property name %s in %s",
241204431Sraj				     prop->name, node->fullpath);
242204431Sraj}
243204431SrajNODE_CHECK(duplicate_property_names, NULL, ERROR);
244204431Sraj
245204431Sraj#define LOWERCASE	"abcdefghijklmnopqrstuvwxyz"
246204431Sraj#define UPPERCASE	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
247204431Sraj#define DIGITS		"0123456789"
248204431Sraj#define PROPNODECHARS	LOWERCASE UPPERCASE DIGITS ",._+*#?-"
249204431Sraj
250204431Srajstatic void check_node_name_chars(struct check *c, struct node *dt,
251204431Sraj				  struct node *node)
252204431Sraj{
253204431Sraj	int n = strspn(node->name, c->data);
254204431Sraj
255204431Sraj	if (n < strlen(node->name))
256204431Sraj		FAIL(c, "Bad character '%c' in node %s",
257204431Sraj		     node->name[n], node->fullpath);
258204431Sraj}
259204431SrajNODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
260204431Sraj
261204431Srajstatic void check_node_name_format(struct check *c, struct node *dt,
262204431Sraj				   struct node *node)
263204431Sraj{
264204431Sraj	if (strchr(get_unitname(node), '@'))
265204431Sraj		FAIL(c, "Node %s has multiple '@' characters in name",
266204431Sraj		     node->fullpath);
267204431Sraj}
268204431SrajNODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
269204431Sraj
270204431Srajstatic void check_property_name_chars(struct check *c, struct node *dt,
271204431Sraj				      struct node *node, struct property *prop)
272204431Sraj{
273204431Sraj	int n = strspn(prop->name, c->data);
274204431Sraj
275204431Sraj	if (n < strlen(prop->name))
276204431Sraj		FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
277204431Sraj		     prop->name[n], prop->name, node->fullpath);
278204431Sraj}
279204431SrajPROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
280204431Sraj
281204431Srajstatic void check_explicit_phandles(struct check *c, struct node *root,
282204433Sraj				    struct node *node, struct property *prop)
283204431Sraj{
284204433Sraj	struct marker *m;
285204431Sraj	struct node *other;
286204431Sraj	cell_t phandle;
287204431Sraj
288204433Sraj	if (!streq(prop->name, "phandle")
289204433Sraj	    && !streq(prop->name, "linux,phandle"))
290204433Sraj		return;
291204431Sraj
292204431Sraj	if (prop->val.len != sizeof(cell_t)) {
293204433Sraj		FAIL(c, "%s has bad length (%d) %s property",
294204433Sraj		     node->fullpath, prop->val.len, prop->name);
295204431Sraj		return;
296204431Sraj	}
297204431Sraj
298204433Sraj	m = prop->val.markers;
299204433Sraj	for_each_marker_of_type(m, REF_PHANDLE) {
300204433Sraj		assert(m->offset == 0);
301204433Sraj		if (node != get_node_by_ref(root, m->ref))
302204433Sraj			/* "Set this node's phandle equal to some
303204433Sraj			 * other node's phandle".  That's nonsensical
304204433Sraj			 * by construction. */ {
305204433Sraj			FAIL(c, "%s in %s is a reference to another node",
306204433Sraj			     prop->name, node->fullpath);
307204433Sraj			return;
308204433Sraj		}
309204433Sraj		/* But setting this node's phandle equal to its own
310204433Sraj		 * phandle is allowed - that means allocate a unique
311204433Sraj		 * phandle for this node, even if it's not otherwise
312204433Sraj		 * referenced.  The value will be filled in later, so
313204433Sraj		 * no further checking for now. */
314204433Sraj		return;
315204433Sraj	}
316204433Sraj
317204431Sraj	phandle = propval_cell(prop);
318204433Sraj
319204431Sraj	if ((phandle == 0) || (phandle == -1)) {
320204433Sraj		FAIL(c, "%s has bad value (0x%x) in %s property",
321204433Sraj		     node->fullpath, phandle, prop->name);
322204431Sraj		return;
323204431Sraj	}
324204431Sraj
325204433Sraj	if (node->phandle && (node->phandle != phandle))
326204433Sraj		FAIL(c, "%s has %s property which replaces existing phandle information",
327204433Sraj		     node->fullpath, prop->name);
328204433Sraj
329204431Sraj	other = get_node_by_phandle(root, phandle);
330204433Sraj	if (other && (other != node)) {
331204431Sraj		FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
332204431Sraj		     node->fullpath, phandle, other->fullpath);
333204431Sraj		return;
334204431Sraj	}
335204431Sraj
336204431Sraj	node->phandle = phandle;
337204431Sraj}
338204433SrajPROP_CHECK(explicit_phandles, NULL, ERROR);
339204431Sraj
340204431Srajstatic void check_name_properties(struct check *c, struct node *root,
341204431Sraj				  struct node *node)
342204431Sraj{
343204431Sraj	struct property **pp, *prop = NULL;
344204431Sraj
345204431Sraj	for (pp = &node->proplist; *pp; pp = &((*pp)->next))
346204431Sraj		if (streq((*pp)->name, "name")) {
347204431Sraj			prop = *pp;
348204431Sraj			break;
349204431Sraj		}
350204431Sraj
351204431Sraj	if (!prop)
352204431Sraj		return; /* No name property, that's fine */
353204431Sraj
354204431Sraj	if ((prop->val.len != node->basenamelen+1)
355204431Sraj	    || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
356204431Sraj		FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
357204431Sraj		     " of base node name)", node->fullpath, prop->val.val);
358204431Sraj	} else {
359204431Sraj		/* The name property is correct, and therefore redundant.
360204431Sraj		 * Delete it */
361204431Sraj		*pp = prop->next;
362204431Sraj		free(prop->name);
363204431Sraj		data_free(prop->val);
364204431Sraj		free(prop);
365204431Sraj	}
366204431Sraj}
367204431SrajCHECK_IS_STRING(name_is_string, "name", ERROR);
368204431SrajNODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
369204431Sraj
370204431Sraj/*
371204431Sraj * Reference fixup functions
372204431Sraj */
373204431Sraj
374204431Srajstatic void fixup_phandle_references(struct check *c, struct node *dt,
375204431Sraj				     struct node *node, struct property *prop)
376204431Sraj{
377204431Sraj	struct marker *m = prop->val.markers;
378204431Sraj	struct node *refnode;
379204431Sraj	cell_t phandle;
380204431Sraj
381204431Sraj	for_each_marker_of_type(m, REF_PHANDLE) {
382204431Sraj		assert(m->offset + sizeof(cell_t) <= prop->val.len);
383204431Sraj
384204431Sraj		refnode = get_node_by_ref(dt, m->ref);
385204431Sraj		if (! refnode) {
386204431Sraj			FAIL(c, "Reference to non-existent node or label \"%s\"\n",
387204431Sraj			     m->ref);
388204431Sraj			continue;
389204431Sraj		}
390204431Sraj
391204431Sraj		phandle = get_node_phandle(dt, refnode);
392204431Sraj		*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
393204431Sraj	}
394204431Sraj}
395204431SrajCHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
396204431Sraj      &duplicate_node_names, &explicit_phandles);
397204431Sraj
398204431Srajstatic void fixup_path_references(struct check *c, struct node *dt,
399204431Sraj				  struct node *node, struct property *prop)
400204431Sraj{
401204431Sraj	struct marker *m = prop->val.markers;
402204431Sraj	struct node *refnode;
403204431Sraj	char *path;
404204431Sraj
405204431Sraj	for_each_marker_of_type(m, REF_PATH) {
406204431Sraj		assert(m->offset <= prop->val.len);
407204431Sraj
408204431Sraj		refnode = get_node_by_ref(dt, m->ref);
409204431Sraj		if (!refnode) {
410204431Sraj			FAIL(c, "Reference to non-existent node or label \"%s\"\n",
411204431Sraj			     m->ref);
412204431Sraj			continue;
413204431Sraj		}
414204431Sraj
415204431Sraj		path = refnode->fullpath;
416204431Sraj		prop->val = data_insert_at_marker(prop->val, m, path,
417204431Sraj						  strlen(path) + 1);
418204431Sraj	}
419204431Sraj}
420204431SrajCHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
421204431Sraj      &duplicate_node_names);
422204431Sraj
423204431Sraj/*
424204431Sraj * Semantic checks
425204431Sraj */
426204431SrajCHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
427204431SrajCHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
428204431SrajCHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
429204431Sraj
430204431SrajCHECK_IS_STRING(device_type_is_string, "device_type", WARN);
431204431SrajCHECK_IS_STRING(model_is_string, "model", WARN);
432204431SrajCHECK_IS_STRING(status_is_string, "status", WARN);
433204431Sraj
434204431Srajstatic void fixup_addr_size_cells(struct check *c, struct node *dt,
435204431Sraj				  struct node *node)
436204431Sraj{
437204431Sraj	struct property *prop;
438204431Sraj
439204431Sraj	node->addr_cells = -1;
440204431Sraj	node->size_cells = -1;
441204431Sraj
442204431Sraj	prop = get_property(node, "#address-cells");
443204431Sraj	if (prop)
444204431Sraj		node->addr_cells = propval_cell(prop);
445204431Sraj
446204431Sraj	prop = get_property(node, "#size-cells");
447204431Sraj	if (prop)
448204431Sraj		node->size_cells = propval_cell(prop);
449204431Sraj}
450204431SrajCHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
451204431Sraj      &address_cells_is_cell, &size_cells_is_cell);
452204431Sraj
453204431Sraj#define node_addr_cells(n) \
454204431Sraj	(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
455204431Sraj#define node_size_cells(n) \
456204431Sraj	(((n)->size_cells == -1) ? 1 : (n)->size_cells)
457204431Sraj
458204431Srajstatic void check_reg_format(struct check *c, struct node *dt,
459204431Sraj			     struct node *node)
460204431Sraj{
461204431Sraj	struct property *prop;
462204431Sraj	int addr_cells, size_cells, entrylen;
463204431Sraj
464204431Sraj	prop = get_property(node, "reg");
465204431Sraj	if (!prop)
466204431Sraj		return; /* No "reg", that's fine */
467204431Sraj
468204431Sraj	if (!node->parent) {
469204431Sraj		FAIL(c, "Root node has a \"reg\" property");
470204431Sraj		return;
471204431Sraj	}
472204431Sraj
473204431Sraj	if (prop->val.len == 0)
474204431Sraj		FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
475204431Sraj
476204431Sraj	addr_cells = node_addr_cells(node->parent);
477204431Sraj	size_cells = node_size_cells(node->parent);
478204431Sraj	entrylen = (addr_cells + size_cells) * sizeof(cell_t);
479204431Sraj
480204431Sraj	if ((prop->val.len % entrylen) != 0)
481204431Sraj		FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
482204431Sraj		     "(#address-cells == %d, #size-cells == %d)",
483204431Sraj		     node->fullpath, prop->val.len, addr_cells, size_cells);
484204431Sraj}
485204431SrajNODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
486204431Sraj
487204431Srajstatic void check_ranges_format(struct check *c, struct node *dt,
488204431Sraj				struct node *node)
489204431Sraj{
490204431Sraj	struct property *prop;
491204431Sraj	int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
492204431Sraj
493204431Sraj	prop = get_property(node, "ranges");
494204431Sraj	if (!prop)
495204431Sraj		return;
496204431Sraj
497204431Sraj	if (!node->parent) {
498204431Sraj		FAIL(c, "Root node has a \"ranges\" property");
499204431Sraj		return;
500204431Sraj	}
501204431Sraj
502204431Sraj	p_addr_cells = node_addr_cells(node->parent);
503204431Sraj	p_size_cells = node_size_cells(node->parent);
504204431Sraj	c_addr_cells = node_addr_cells(node);
505204431Sraj	c_size_cells = node_size_cells(node);
506204431Sraj	entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
507204431Sraj
508204431Sraj	if (prop->val.len == 0) {
509204431Sraj		if (p_addr_cells != c_addr_cells)
510204431Sraj			FAIL(c, "%s has empty \"ranges\" property but its "
511204431Sraj			     "#address-cells (%d) differs from %s (%d)",
512204431Sraj			     node->fullpath, c_addr_cells, node->parent->fullpath,
513204431Sraj			     p_addr_cells);
514204431Sraj		if (p_size_cells != c_size_cells)
515204431Sraj			FAIL(c, "%s has empty \"ranges\" property but its "
516204431Sraj			     "#size-cells (%d) differs from %s (%d)",
517204431Sraj			     node->fullpath, c_size_cells, node->parent->fullpath,
518204431Sraj			     p_size_cells);
519204431Sraj	} else if ((prop->val.len % entrylen) != 0) {
520204431Sraj		FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
521204431Sraj		     "(parent #address-cells == %d, child #address-cells == %d, "
522204431Sraj		     "#size-cells == %d)", node->fullpath, prop->val.len,
523204431Sraj		     p_addr_cells, c_addr_cells, c_size_cells);
524204431Sraj	}
525204431Sraj}
526204431SrajNODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
527204431Sraj
528204431Sraj/*
529204431Sraj * Style checks
530204431Sraj */
531204431Srajstatic void check_avoid_default_addr_size(struct check *c, struct node *dt,
532204431Sraj					  struct node *node)
533204431Sraj{
534204431Sraj	struct property *reg, *ranges;
535204431Sraj
536204431Sraj	if (!node->parent)
537204431Sraj		return; /* Ignore root node */
538204431Sraj
539204431Sraj	reg = get_property(node, "reg");
540204431Sraj	ranges = get_property(node, "ranges");
541204431Sraj
542204431Sraj	if (!reg && !ranges)
543204431Sraj		return;
544204431Sraj
545204431Sraj	if ((node->parent->addr_cells == -1))
546204431Sraj		FAIL(c, "Relying on default #address-cells value for %s",
547204431Sraj		     node->fullpath);
548204431Sraj
549204431Sraj	if ((node->parent->size_cells == -1))
550204431Sraj		FAIL(c, "Relying on default #size-cells value for %s",
551204431Sraj		     node->fullpath);
552204431Sraj}
553204431SrajNODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
554204431Sraj
555204431Srajstatic void check_obsolete_chosen_interrupt_controller(struct check *c,
556204431Sraj						       struct node *dt)
557204431Sraj{
558204431Sraj	struct node *chosen;
559204431Sraj	struct property *prop;
560204431Sraj
561204431Sraj	chosen = get_node_by_path(dt, "/chosen");
562204431Sraj	if (!chosen)
563204431Sraj		return;
564204431Sraj
565204431Sraj	prop = get_property(chosen, "interrupt-controller");
566204431Sraj	if (prop)
567204431Sraj		FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
568204431Sraj		     "property");
569204431Sraj}
570204431SrajTREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
571204431Sraj
572204431Srajstatic struct check *check_table[] = {
573204431Sraj	&duplicate_node_names, &duplicate_property_names,
574204431Sraj	&node_name_chars, &node_name_format, &property_name_chars,
575204431Sraj	&name_is_string, &name_properties,
576204431Sraj	&explicit_phandles,
577204431Sraj	&phandle_references, &path_references,
578204431Sraj
579204431Sraj	&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
580204431Sraj	&device_type_is_string, &model_is_string, &status_is_string,
581204431Sraj
582204431Sraj	&addr_size_cells, &reg_format, &ranges_format,
583204431Sraj
584204431Sraj	&avoid_default_addr_size,
585204431Sraj	&obsolete_chosen_interrupt_controller,
586204431Sraj};
587204431Sraj
588204431Srajvoid process_checks(int force, struct boot_info *bi)
589204431Sraj{
590204431Sraj	struct node *dt = bi->dt;
591204431Sraj	int i;
592204431Sraj	int error = 0;
593204431Sraj
594204431Sraj	for (i = 0; i < ARRAY_SIZE(check_table); i++) {
595204431Sraj		struct check *c = check_table[i];
596204431Sraj
597204431Sraj		if (c->level != IGNORE)
598204431Sraj			error = error || run_check(c, dt);
599204431Sraj	}
600204431Sraj
601204431Sraj	if (error) {
602204431Sraj		if (!force) {
603204431Sraj			fprintf(stderr, "ERROR: Input tree has errors, aborting "
604204431Sraj				"(use -f to force output)\n");
605204431Sraj			exit(2);
606204431Sraj		} else if (quiet < 3) {
607204431Sraj			fprintf(stderr, "Warning: Input tree has errors, "
608204431Sraj				"output forced\n");
609204431Sraj		}
610204431Sraj	}
611204431Sraj}
612