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 checkstatus {
35204431Sraj	UNCHECKED = 0,
36204431Sraj	PREREQ,
37204431Sraj	PASSED,
38204431Sraj	FAILED,
39204431Sraj};
40204431Sraj
41204431Srajstruct check;
42204431Sraj
43318102Sgonzotypedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
44204431Sraj
45204431Srajstruct check {
46204431Sraj	const char *name;
47318102Sgonzo	check_fn fn;
48204431Sraj	void *data;
49238742Simp	bool warn, error;
50204431Sraj	enum checkstatus status;
51261215Simp	bool inprogress;
52204431Sraj	int num_prereqs;
53204431Sraj	struct check **prereq;
54204431Sraj};
55204431Sraj
56318102Sgonzo#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...)	       \
57318102Sgonzo	static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
58318102Sgonzo	static struct check _nm = { \
59318102Sgonzo		.name = #_nm, \
60318102Sgonzo		.fn = (_fn), \
61318102Sgonzo		.data = (_d), \
62318102Sgonzo		.warn = (_w), \
63318102Sgonzo		.error = (_e), \
64204431Sraj		.status = UNCHECKED, \
65318102Sgonzo		.num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
66318102Sgonzo		.prereq = _nm##_prereqs, \
67204431Sraj	};
68318102Sgonzo#define WARNING(_nm, _fn, _d, ...) \
69318102Sgonzo	CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
70318102Sgonzo#define ERROR(_nm, _fn, _d, ...) \
71318102Sgonzo	CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
72318102Sgonzo#define CHECK(_nm, _fn, _d, ...) \
73318102Sgonzo	CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
74204431Sraj
75204431Sraj#ifdef __GNUC__
76318102Sgonzostatic inline void check_msg(struct check *c, struct dt_info *dti,
77318102Sgonzo			     const char *fmt, ...) __attribute__((format (printf, 3, 4)));
78204431Sraj#endif
79318102Sgonzostatic inline void check_msg(struct check *c, struct dt_info *dti,
80318102Sgonzo			     const char *fmt, ...)
81204431Sraj{
82204431Sraj	va_list ap;
83204431Sraj	va_start(ap, fmt);
84204431Sraj
85238742Simp	if ((c->warn && (quiet < 1))
86238742Simp	    || (c->error && (quiet < 2))) {
87318102Sgonzo		fprintf(stderr, "%s: %s (%s): ",
88318102Sgonzo			strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
89238742Simp			(c->error) ? "ERROR" : "Warning", c->name);
90238742Simp		vfprintf(stderr, fmt, ap);
91238742Simp		fprintf(stderr, "\n");
92238742Simp	}
93318102Sgonzo	va_end(ap);
94204431Sraj}
95204431Sraj
96318102Sgonzo#define FAIL(c, dti, ...)						\
97318102Sgonzo	do {								\
98318102Sgonzo		TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__);	\
99318102Sgonzo		(c)->status = FAILED;					\
100318102Sgonzo		check_msg((c), dti, __VA_ARGS__);			\
101204431Sraj	} while (0)
102204431Sraj
103318102Sgonzostatic void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
104204431Sraj{
105204431Sraj	struct node *child;
106204431Sraj
107204431Sraj	TRACE(c, "%s", node->fullpath);
108318102Sgonzo	if (c->fn)
109318102Sgonzo		c->fn(c, dti, node);
110204431Sraj
111204431Sraj	for_each_child(node, child)
112318102Sgonzo		check_nodes_props(c, dti, child);
113204431Sraj}
114204431Sraj
115318102Sgonzostatic bool run_check(struct check *c, struct dt_info *dti)
116204431Sraj{
117318102Sgonzo	struct node *dt = dti->dt;
118261215Simp	bool error = false;
119204431Sraj	int i;
120204431Sraj
121204431Sraj	assert(!c->inprogress);
122204431Sraj
123204431Sraj	if (c->status != UNCHECKED)
124204431Sraj		goto out;
125204431Sraj
126261215Simp	c->inprogress = true;
127204431Sraj
128204431Sraj	for (i = 0; i < c->num_prereqs; i++) {
129204431Sraj		struct check *prq = c->prereq[i];
130318102Sgonzo		error = error || run_check(prq, dti);
131204431Sraj		if (prq->status != PASSED) {
132204431Sraj			c->status = PREREQ;
133318102Sgonzo			check_msg(c, dti, "Failed prerequisite '%s'",
134204431Sraj				  c->prereq[i]->name);
135204431Sraj		}
136204431Sraj	}
137204431Sraj
138204431Sraj	if (c->status != UNCHECKED)
139204431Sraj		goto out;
140204431Sraj
141318102Sgonzo	check_nodes_props(c, dti, dt);
142204431Sraj
143204431Sraj	if (c->status == UNCHECKED)
144204431Sraj		c->status = PASSED;
145204431Sraj
146204431Sraj	TRACE(c, "\tCompleted, status %d", c->status);
147204431Sraj
148204431Srajout:
149261215Simp	c->inprogress = false;
150238742Simp	if ((c->status != PASSED) && (c->error))
151261215Simp		error = true;
152204431Sraj	return error;
153204431Sraj}
154204431Sraj
155204431Sraj/*
156204431Sraj * Utility check functions
157204431Sraj */
158204431Sraj
159238742Simp/* A check which always fails, for testing purposes only */
160318102Sgonzostatic inline void check_always_fail(struct check *c, struct dt_info *dti,
161318102Sgonzo				     struct node *node)
162238742Simp{
163318102Sgonzo	FAIL(c, dti, "always_fail check");
164238742Simp}
165318102SgonzoCHECK(always_fail, check_always_fail, NULL);
166238742Simp
167318102Sgonzostatic void check_is_string(struct check *c, struct dt_info *dti,
168204431Sraj			    struct node *node)
169204431Sraj{
170204431Sraj	struct property *prop;
171204431Sraj	char *propname = c->data;
172204431Sraj
173204431Sraj	prop = get_property(node, propname);
174204431Sraj	if (!prop)
175204431Sraj		return; /* Not present, assumed ok */
176204431Sraj
177204431Sraj	if (!data_is_one_string(prop->val))
178318102Sgonzo		FAIL(c, dti, "\"%s\" property in %s is not a string",
179204431Sraj		     propname, node->fullpath);
180204431Sraj}
181238742Simp#define WARNING_IF_NOT_STRING(nm, propname) \
182318102Sgonzo	WARNING(nm, check_is_string, (propname))
183238742Simp#define ERROR_IF_NOT_STRING(nm, propname) \
184318102Sgonzo	ERROR(nm, check_is_string, (propname))
185204431Sraj
186318102Sgonzostatic void check_is_cell(struct check *c, struct dt_info *dti,
187204431Sraj			  struct node *node)
188204431Sraj{
189204431Sraj	struct property *prop;
190204431Sraj	char *propname = c->data;
191204431Sraj
192204431Sraj	prop = get_property(node, propname);
193204431Sraj	if (!prop)
194204431Sraj		return; /* Not present, assumed ok */
195204431Sraj
196204431Sraj	if (prop->val.len != sizeof(cell_t))
197318102Sgonzo		FAIL(c, dti, "\"%s\" property in %s is not a single cell",
198204431Sraj		     propname, node->fullpath);
199204431Sraj}
200238742Simp#define WARNING_IF_NOT_CELL(nm, propname) \
201318102Sgonzo	WARNING(nm, check_is_cell, (propname))
202238742Simp#define ERROR_IF_NOT_CELL(nm, propname) \
203318102Sgonzo	ERROR(nm, check_is_cell, (propname))
204204431Sraj
205204431Sraj/*
206204431Sraj * Structural check functions
207204431Sraj */
208204431Sraj
209318102Sgonzostatic void check_duplicate_node_names(struct check *c, struct dt_info *dti,
210204431Sraj				       struct node *node)
211204431Sraj{
212204431Sraj	struct node *child, *child2;
213204431Sraj
214204431Sraj	for_each_child(node, child)
215204431Sraj		for (child2 = child->next_sibling;
216204431Sraj		     child2;
217204431Sraj		     child2 = child2->next_sibling)
218204431Sraj			if (streq(child->name, child2->name))
219318102Sgonzo				FAIL(c, dti, "Duplicate node name %s",
220204431Sraj				     child->fullpath);
221204431Sraj}
222318102SgonzoERROR(duplicate_node_names, check_duplicate_node_names, NULL);
223204431Sraj
224318102Sgonzostatic void check_duplicate_property_names(struct check *c, struct dt_info *dti,
225204431Sraj					   struct node *node)
226204431Sraj{
227204431Sraj	struct property *prop, *prop2;
228204431Sraj
229261215Simp	for_each_property(node, prop) {
230261215Simp		for (prop2 = prop->next; prop2; prop2 = prop2->next) {
231261215Simp			if (prop2->deleted)
232261215Simp				continue;
233204431Sraj			if (streq(prop->name, prop2->name))
234318102Sgonzo				FAIL(c, dti, "Duplicate property name %s in %s",
235204431Sraj				     prop->name, node->fullpath);
236261215Simp		}
237261215Simp	}
238204431Sraj}
239318102SgonzoERROR(duplicate_property_names, check_duplicate_property_names, NULL);
240204431Sraj
241204431Sraj#define LOWERCASE	"abcdefghijklmnopqrstuvwxyz"
242204431Sraj#define UPPERCASE	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
243204431Sraj#define DIGITS		"0123456789"
244204431Sraj#define PROPNODECHARS	LOWERCASE UPPERCASE DIGITS ",._+*#?-"
245318102Sgonzo#define PROPNODECHARSSTRICT	LOWERCASE UPPERCASE DIGITS ",-"
246204431Sraj
247318102Sgonzostatic void check_node_name_chars(struct check *c, struct dt_info *dti,
248204431Sraj				  struct node *node)
249204431Sraj{
250204431Sraj	int n = strspn(node->name, c->data);
251204431Sraj
252204431Sraj	if (n < strlen(node->name))
253318102Sgonzo		FAIL(c, dti, "Bad character '%c' in node %s",
254204431Sraj		     node->name[n], node->fullpath);
255204431Sraj}
256318102SgonzoERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
257204431Sraj
258318102Sgonzostatic void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
259318102Sgonzo					 struct node *node)
260318102Sgonzo{
261318102Sgonzo	int n = strspn(node->name, c->data);
262318102Sgonzo
263318102Sgonzo	if (n < node->basenamelen)
264318102Sgonzo		FAIL(c, dti, "Character '%c' not recommended in node %s",
265318102Sgonzo		     node->name[n], node->fullpath);
266318102Sgonzo}
267318102SgonzoCHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
268318102Sgonzo
269318102Sgonzostatic void check_node_name_format(struct check *c, struct dt_info *dti,
270204431Sraj				   struct node *node)
271204431Sraj{
272204431Sraj	if (strchr(get_unitname(node), '@'))
273318102Sgonzo		FAIL(c, dti, "Node %s has multiple '@' characters in name",
274204431Sraj		     node->fullpath);
275204431Sraj}
276318102SgonzoERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
277204431Sraj
278318102Sgonzostatic void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
279318102Sgonzo				      struct node *node)
280204431Sraj{
281318102Sgonzo	const char *unitname = get_unitname(node);
282318102Sgonzo	struct property *prop = get_property(node, "reg");
283204431Sraj
284318102Sgonzo	if (!prop) {
285318102Sgonzo		prop = get_property(node, "ranges");
286318102Sgonzo		if (prop && !prop->val.len)
287318102Sgonzo			prop = NULL;
288318102Sgonzo	}
289318102Sgonzo
290318102Sgonzo	if (prop) {
291318102Sgonzo		if (!unitname[0])
292318102Sgonzo			FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name",
293318102Sgonzo			    node->fullpath);
294318102Sgonzo	} else {
295318102Sgonzo		if (unitname[0])
296318102Sgonzo			FAIL(c, dti, "Node %s has a unit name, but no reg property",
297318102Sgonzo			    node->fullpath);
298318102Sgonzo	}
299204431Sraj}
300318102SgonzoWARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
301204431Sraj
302318102Sgonzostatic void check_property_name_chars(struct check *c, struct dt_info *dti,
303318102Sgonzo				      struct node *node)
304318102Sgonzo{
305318102Sgonzo	struct property *prop;
306318102Sgonzo
307318102Sgonzo	for_each_property(node, prop) {
308318102Sgonzo		int n = strspn(prop->name, c->data);
309318102Sgonzo
310318102Sgonzo		if (n < strlen(prop->name))
311318102Sgonzo			FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s",
312318102Sgonzo			     prop->name[n], prop->name, node->fullpath);
313318102Sgonzo	}
314318102Sgonzo}
315318102SgonzoERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
316318102Sgonzo
317318102Sgonzostatic void check_property_name_chars_strict(struct check *c,
318318102Sgonzo					     struct dt_info *dti,
319318102Sgonzo					     struct node *node)
320318102Sgonzo{
321318102Sgonzo	struct property *prop;
322318102Sgonzo
323318102Sgonzo	for_each_property(node, prop) {
324318102Sgonzo		const char *name = prop->name;
325318102Sgonzo		int n = strspn(name, c->data);
326318102Sgonzo
327318102Sgonzo		if (n == strlen(prop->name))
328318102Sgonzo			continue;
329318102Sgonzo
330318102Sgonzo		/* Certain names are whitelisted */
331318102Sgonzo		if (streq(name, "device_type"))
332318102Sgonzo			continue;
333318102Sgonzo
334318102Sgonzo		/*
335318102Sgonzo		 * # is only allowed at the beginning of property names not counting
336318102Sgonzo		 * the vendor prefix.
337318102Sgonzo		 */
338318102Sgonzo		if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) {
339318102Sgonzo			name += n + 1;
340318102Sgonzo			n = strspn(name, c->data);
341318102Sgonzo		}
342318102Sgonzo		if (n < strlen(name))
343318102Sgonzo			FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s",
344318102Sgonzo			     name[n], prop->name, node->fullpath);
345318102Sgonzo	}
346318102Sgonzo}
347318102SgonzoCHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
348318102Sgonzo
349238742Simp#define DESCLABEL_FMT	"%s%s%s%s%s"
350238742Simp#define DESCLABEL_ARGS(node,prop,mark)		\
351238742Simp	((mark) ? "value of " : ""),		\
352238742Simp	((prop) ? "'" : ""), \
353238742Simp	((prop) ? (prop)->name : ""), \
354238742Simp	((prop) ? "' in " : ""), (node)->fullpath
355238742Simp
356318102Sgonzostatic void check_duplicate_label(struct check *c, struct dt_info *dti,
357238742Simp				  const char *label, struct node *node,
358238742Simp				  struct property *prop, struct marker *mark)
359238742Simp{
360318102Sgonzo	struct node *dt = dti->dt;
361238742Simp	struct node *othernode = NULL;
362238742Simp	struct property *otherprop = NULL;
363238742Simp	struct marker *othermark = NULL;
364238742Simp
365238742Simp	othernode = get_node_by_label(dt, label);
366238742Simp
367238742Simp	if (!othernode)
368238742Simp		otherprop = get_property_by_label(dt, label, &othernode);
369238742Simp	if (!othernode)
370238742Simp		othermark = get_marker_label(dt, label, &othernode,
371238742Simp					       &otherprop);
372238742Simp
373238742Simp	if (!othernode)
374238742Simp		return;
375238742Simp
376238742Simp	if ((othernode != node) || (otherprop != prop) || (othermark != mark))
377318102Sgonzo		FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT
378238742Simp		     " and " DESCLABEL_FMT,
379238742Simp		     label, DESCLABEL_ARGS(node, prop, mark),
380238742Simp		     DESCLABEL_ARGS(othernode, otherprop, othermark));
381238742Simp}
382238742Simp
383318102Sgonzostatic void check_duplicate_label_node(struct check *c, struct dt_info *dti,
384238742Simp				       struct node *node)
385238742Simp{
386238742Simp	struct label *l;
387318102Sgonzo	struct property *prop;
388238742Simp
389238742Simp	for_each_label(node->labels, l)
390318102Sgonzo		check_duplicate_label(c, dti, l->label, node, NULL, NULL);
391238742Simp
392318102Sgonzo	for_each_property(node, prop) {
393318102Sgonzo		struct marker *m = prop->val.markers;
394238742Simp
395318102Sgonzo		for_each_label(prop->labels, l)
396318102Sgonzo			check_duplicate_label(c, dti, l->label, node, prop, NULL);
397318102Sgonzo
398318102Sgonzo		for_each_marker_of_type(m, LABEL)
399318102Sgonzo			check_duplicate_label(c, dti, m->ref, node, prop, m);
400318102Sgonzo	}
401238742Simp}
402318102SgonzoERROR(duplicate_label, check_duplicate_label_node, NULL);
403238742Simp
404318102Sgonzostatic cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
405318102Sgonzo				 struct node *node, const char *propname)
406204431Sraj{
407318102Sgonzo	struct node *root = dti->dt;
408318102Sgonzo	struct property *prop;
409204433Sraj	struct marker *m;
410204431Sraj	cell_t phandle;
411204431Sraj
412318102Sgonzo	prop = get_property(node, propname);
413318102Sgonzo	if (!prop)
414318102Sgonzo		return 0;
415204431Sraj
416204431Sraj	if (prop->val.len != sizeof(cell_t)) {
417318102Sgonzo		FAIL(c, dti, "%s has bad length (%d) %s property",
418204433Sraj		     node->fullpath, prop->val.len, prop->name);
419318102Sgonzo		return 0;
420204431Sraj	}
421204431Sraj
422204433Sraj	m = prop->val.markers;
423204433Sraj	for_each_marker_of_type(m, REF_PHANDLE) {
424204433Sraj		assert(m->offset == 0);
425204433Sraj		if (node != get_node_by_ref(root, m->ref))
426204433Sraj			/* "Set this node's phandle equal to some
427204433Sraj			 * other node's phandle".  That's nonsensical
428204433Sraj			 * by construction. */ {
429318102Sgonzo			FAIL(c, dti, "%s in %s is a reference to another node",
430204433Sraj			     prop->name, node->fullpath);
431204433Sraj		}
432204433Sraj		/* But setting this node's phandle equal to its own
433204433Sraj		 * phandle is allowed - that means allocate a unique
434204433Sraj		 * phandle for this node, even if it's not otherwise
435204433Sraj		 * referenced.  The value will be filled in later, so
436318102Sgonzo		 * we treat it as having no phandle data for now. */
437318102Sgonzo		return 0;
438204433Sraj	}
439204433Sraj
440204431Sraj	phandle = propval_cell(prop);
441204433Sraj
442204431Sraj	if ((phandle == 0) || (phandle == -1)) {
443318102Sgonzo		FAIL(c, dti, "%s has bad value (0x%x) in %s property",
444204433Sraj		     node->fullpath, phandle, prop->name);
445318102Sgonzo		return 0;
446204431Sraj	}
447204431Sraj
448318102Sgonzo	return phandle;
449318102Sgonzo}
450204433Sraj
451318102Sgonzostatic void check_explicit_phandles(struct check *c, struct dt_info *dti,
452318102Sgonzo				    struct node *node)
453318102Sgonzo{
454318102Sgonzo	struct node *root = dti->dt;
455318102Sgonzo	struct node *other;
456318102Sgonzo	cell_t phandle, linux_phandle;
457318102Sgonzo
458318102Sgonzo	/* Nothing should have assigned phandles yet */
459318102Sgonzo	assert(!node->phandle);
460318102Sgonzo
461318102Sgonzo	phandle = check_phandle_prop(c, dti, node, "phandle");
462318102Sgonzo
463318102Sgonzo	linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle");
464318102Sgonzo
465318102Sgonzo	if (!phandle && !linux_phandle)
466318102Sgonzo		/* No valid phandles; nothing further to check */
467318102Sgonzo		return;
468318102Sgonzo
469318102Sgonzo	if (linux_phandle && phandle && (phandle != linux_phandle))
470318102Sgonzo		FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'"
471318102Sgonzo		     " properties", node->fullpath);
472318102Sgonzo
473318102Sgonzo	if (linux_phandle && !phandle)
474318102Sgonzo		phandle = linux_phandle;
475318102Sgonzo
476204431Sraj	other = get_node_by_phandle(root, phandle);
477204433Sraj	if (other && (other != node)) {
478318102Sgonzo		FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)",
479204431Sraj		     node->fullpath, phandle, other->fullpath);
480204431Sraj		return;
481204431Sraj	}
482204431Sraj
483204431Sraj	node->phandle = phandle;
484204431Sraj}
485318102SgonzoERROR(explicit_phandles, check_explicit_phandles, NULL);
486204431Sraj
487318102Sgonzostatic void check_name_properties(struct check *c, struct dt_info *dti,
488204431Sraj				  struct node *node)
489204431Sraj{
490204431Sraj	struct property **pp, *prop = NULL;
491204431Sraj
492204431Sraj	for (pp = &node->proplist; *pp; pp = &((*pp)->next))
493204431Sraj		if (streq((*pp)->name, "name")) {
494204431Sraj			prop = *pp;
495204431Sraj			break;
496204431Sraj		}
497204431Sraj
498204431Sraj	if (!prop)
499204431Sraj		return; /* No name property, that's fine */
500204431Sraj
501204431Sraj	if ((prop->val.len != node->basenamelen+1)
502204431Sraj	    || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
503318102Sgonzo		FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead"
504204431Sraj		     " of base node name)", node->fullpath, prop->val.val);
505204431Sraj	} else {
506204431Sraj		/* The name property is correct, and therefore redundant.
507204431Sraj		 * Delete it */
508204431Sraj		*pp = prop->next;
509204431Sraj		free(prop->name);
510204431Sraj		data_free(prop->val);
511204431Sraj		free(prop);
512204431Sraj	}
513204431Sraj}
514238742SimpERROR_IF_NOT_STRING(name_is_string, "name");
515318102SgonzoERROR(name_properties, check_name_properties, NULL, &name_is_string);
516204431Sraj
517204431Sraj/*
518204431Sraj * Reference fixup functions
519204431Sraj */
520204431Sraj
521318102Sgonzostatic void fixup_phandle_references(struct check *c, struct dt_info *dti,
522318102Sgonzo				     struct node *node)
523204431Sraj{
524318102Sgonzo	struct node *dt = dti->dt;
525318102Sgonzo	struct property *prop;
526204431Sraj
527318102Sgonzo	for_each_property(node, prop) {
528318102Sgonzo		struct marker *m = prop->val.markers;
529318102Sgonzo		struct node *refnode;
530318102Sgonzo		cell_t phandle;
531204431Sraj
532318102Sgonzo		for_each_marker_of_type(m, REF_PHANDLE) {
533318102Sgonzo			assert(m->offset + sizeof(cell_t) <= prop->val.len);
534318102Sgonzo
535318102Sgonzo			refnode = get_node_by_ref(dt, m->ref);
536318102Sgonzo			if (! refnode) {
537318102Sgonzo				if (!(dti->dtsflags & DTSF_PLUGIN))
538318102Sgonzo					FAIL(c, dti, "Reference to non-existent node or "
539318102Sgonzo							"label \"%s\"\n", m->ref);
540318102Sgonzo				else /* mark the entry as unresolved */
541318102Sgonzo					*((cell_t *)(prop->val.val + m->offset)) =
542318102Sgonzo						cpu_to_fdt32(0xffffffff);
543318102Sgonzo				continue;
544318102Sgonzo			}
545318102Sgonzo
546318102Sgonzo			phandle = get_node_phandle(dt, refnode);
547318102Sgonzo			*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
548204431Sraj		}
549204431Sraj	}
550204431Sraj}
551318102SgonzoERROR(phandle_references, fixup_phandle_references, NULL,
552204431Sraj      &duplicate_node_names, &explicit_phandles);
553204431Sraj
554318102Sgonzostatic void fixup_path_references(struct check *c, struct dt_info *dti,
555318102Sgonzo				  struct node *node)
556204431Sraj{
557318102Sgonzo	struct node *dt = dti->dt;
558318102Sgonzo	struct property *prop;
559204431Sraj
560318102Sgonzo	for_each_property(node, prop) {
561318102Sgonzo		struct marker *m = prop->val.markers;
562318102Sgonzo		struct node *refnode;
563318102Sgonzo		char *path;
564204431Sraj
565318102Sgonzo		for_each_marker_of_type(m, REF_PATH) {
566318102Sgonzo			assert(m->offset <= prop->val.len);
567318102Sgonzo
568318102Sgonzo			refnode = get_node_by_ref(dt, m->ref);
569318102Sgonzo			if (!refnode) {
570318102Sgonzo				FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n",
571318102Sgonzo				     m->ref);
572318102Sgonzo				continue;
573318102Sgonzo			}
574318102Sgonzo
575318102Sgonzo			path = refnode->fullpath;
576318102Sgonzo			prop->val = data_insert_at_marker(prop->val, m, path,
577318102Sgonzo							  strlen(path) + 1);
578204431Sraj		}
579204431Sraj	}
580204431Sraj}
581318102SgonzoERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
582204431Sraj
583204431Sraj/*
584204431Sraj * Semantic checks
585204431Sraj */
586238742SimpWARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
587238742SimpWARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
588238742SimpWARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
589204431Sraj
590238742SimpWARNING_IF_NOT_STRING(device_type_is_string, "device_type");
591238742SimpWARNING_IF_NOT_STRING(model_is_string, "model");
592238742SimpWARNING_IF_NOT_STRING(status_is_string, "status");
593204431Sraj
594318102Sgonzostatic void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
595204431Sraj				  struct node *node)
596204431Sraj{
597204431Sraj	struct property *prop;
598204431Sraj
599204431Sraj	node->addr_cells = -1;
600204431Sraj	node->size_cells = -1;
601204431Sraj
602204431Sraj	prop = get_property(node, "#address-cells");
603204431Sraj	if (prop)
604204431Sraj		node->addr_cells = propval_cell(prop);
605204431Sraj
606204431Sraj	prop = get_property(node, "#size-cells");
607204431Sraj	if (prop)
608204431Sraj		node->size_cells = propval_cell(prop);
609204431Sraj}
610318102SgonzoWARNING(addr_size_cells, fixup_addr_size_cells, NULL,
611238742Simp	&address_cells_is_cell, &size_cells_is_cell);
612204431Sraj
613204431Sraj#define node_addr_cells(n) \
614204431Sraj	(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
615204431Sraj#define node_size_cells(n) \
616204431Sraj	(((n)->size_cells == -1) ? 1 : (n)->size_cells)
617204431Sraj
618318102Sgonzostatic void check_reg_format(struct check *c, struct dt_info *dti,
619204431Sraj			     struct node *node)
620204431Sraj{
621204431Sraj	struct property *prop;
622204431Sraj	int addr_cells, size_cells, entrylen;
623204431Sraj
624204431Sraj	prop = get_property(node, "reg");
625204431Sraj	if (!prop)
626204431Sraj		return; /* No "reg", that's fine */
627204431Sraj
628204431Sraj	if (!node->parent) {
629318102Sgonzo		FAIL(c, dti, "Root node has a \"reg\" property");
630204431Sraj		return;
631204431Sraj	}
632204431Sraj
633204431Sraj	if (prop->val.len == 0)
634318102Sgonzo		FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath);
635204431Sraj
636204431Sraj	addr_cells = node_addr_cells(node->parent);
637204431Sraj	size_cells = node_size_cells(node->parent);
638204431Sraj	entrylen = (addr_cells + size_cells) * sizeof(cell_t);
639204431Sraj
640318102Sgonzo	if (!entrylen || (prop->val.len % entrylen) != 0)
641318102Sgonzo		FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) "
642204431Sraj		     "(#address-cells == %d, #size-cells == %d)",
643204431Sraj		     node->fullpath, prop->val.len, addr_cells, size_cells);
644204431Sraj}
645318102SgonzoWARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
646204431Sraj
647318102Sgonzostatic void check_ranges_format(struct check *c, struct dt_info *dti,
648204431Sraj				struct node *node)
649204431Sraj{
650204431Sraj	struct property *prop;
651204431Sraj	int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
652204431Sraj
653204431Sraj	prop = get_property(node, "ranges");
654204431Sraj	if (!prop)
655204431Sraj		return;
656204431Sraj
657204431Sraj	if (!node->parent) {
658318102Sgonzo		FAIL(c, dti, "Root node has a \"ranges\" property");
659204431Sraj		return;
660204431Sraj	}
661204431Sraj
662204431Sraj	p_addr_cells = node_addr_cells(node->parent);
663204431Sraj	p_size_cells = node_size_cells(node->parent);
664204431Sraj	c_addr_cells = node_addr_cells(node);
665204431Sraj	c_size_cells = node_size_cells(node);
666204431Sraj	entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
667204431Sraj
668204431Sraj	if (prop->val.len == 0) {
669204431Sraj		if (p_addr_cells != c_addr_cells)
670318102Sgonzo			FAIL(c, dti, "%s has empty \"ranges\" property but its "
671204431Sraj			     "#address-cells (%d) differs from %s (%d)",
672204431Sraj			     node->fullpath, c_addr_cells, node->parent->fullpath,
673204431Sraj			     p_addr_cells);
674204431Sraj		if (p_size_cells != c_size_cells)
675318102Sgonzo			FAIL(c, dti, "%s has empty \"ranges\" property but its "
676204431Sraj			     "#size-cells (%d) differs from %s (%d)",
677204431Sraj			     node->fullpath, c_size_cells, node->parent->fullpath,
678204431Sraj			     p_size_cells);
679204431Sraj	} else if ((prop->val.len % entrylen) != 0) {
680318102Sgonzo		FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) "
681204431Sraj		     "(parent #address-cells == %d, child #address-cells == %d, "
682204431Sraj		     "#size-cells == %d)", node->fullpath, prop->val.len,
683204431Sraj		     p_addr_cells, c_addr_cells, c_size_cells);
684204431Sraj	}
685204431Sraj}
686318102SgonzoWARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
687204431Sraj
688204431Sraj/*
689204431Sraj * Style checks
690204431Sraj */
691318102Sgonzostatic void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
692204431Sraj					  struct node *node)
693204431Sraj{
694204431Sraj	struct property *reg, *ranges;
695204431Sraj
696204431Sraj	if (!node->parent)
697204431Sraj		return; /* Ignore root node */
698204431Sraj
699204431Sraj	reg = get_property(node, "reg");
700204431Sraj	ranges = get_property(node, "ranges");
701204431Sraj
702204431Sraj	if (!reg && !ranges)
703204431Sraj		return;
704204431Sraj
705284041Ssbruno	if (node->parent->addr_cells == -1)
706318102Sgonzo		FAIL(c, dti, "Relying on default #address-cells value for %s",
707204431Sraj		     node->fullpath);
708204431Sraj
709284041Ssbruno	if (node->parent->size_cells == -1)
710318102Sgonzo		FAIL(c, dti, "Relying on default #size-cells value for %s",
711204431Sraj		     node->fullpath);
712204431Sraj}
713318102SgonzoWARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
714318102Sgonzo	&addr_size_cells);
715204431Sraj
716204431Srajstatic void check_obsolete_chosen_interrupt_controller(struct check *c,
717318102Sgonzo						       struct dt_info *dti,
718318102Sgonzo						       struct node *node)
719204431Sraj{
720318102Sgonzo	struct node *dt = dti->dt;
721204431Sraj	struct node *chosen;
722204431Sraj	struct property *prop;
723204431Sraj
724318102Sgonzo	if (node != dt)
725318102Sgonzo		return;
726318102Sgonzo
727318102Sgonzo
728204431Sraj	chosen = get_node_by_path(dt, "/chosen");
729204431Sraj	if (!chosen)
730204431Sraj		return;
731204431Sraj
732204431Sraj	prop = get_property(chosen, "interrupt-controller");
733204431Sraj	if (prop)
734318102Sgonzo		FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" "
735204431Sraj		     "property");
736204431Sraj}
737318102SgonzoWARNING(obsolete_chosen_interrupt_controller,
738318102Sgonzo	check_obsolete_chosen_interrupt_controller, NULL);
739204431Sraj
740204431Srajstatic struct check *check_table[] = {
741204431Sraj	&duplicate_node_names, &duplicate_property_names,
742204431Sraj	&node_name_chars, &node_name_format, &property_name_chars,
743204431Sraj	&name_is_string, &name_properties,
744238742Simp
745238742Simp	&duplicate_label,
746238742Simp
747204431Sraj	&explicit_phandles,
748204431Sraj	&phandle_references, &path_references,
749204431Sraj
750204431Sraj	&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
751204431Sraj	&device_type_is_string, &model_is_string, &status_is_string,
752204431Sraj
753318102Sgonzo	&property_name_chars_strict,
754318102Sgonzo	&node_name_chars_strict,
755318102Sgonzo
756204431Sraj	&addr_size_cells, &reg_format, &ranges_format,
757204431Sraj
758318102Sgonzo	&unit_address_vs_reg,
759318102Sgonzo
760204431Sraj	&avoid_default_addr_size,
761204431Sraj	&obsolete_chosen_interrupt_controller,
762238742Simp
763238742Simp	&always_fail,
764204431Sraj};
765204431Sraj
766238742Simpstatic void enable_warning_error(struct check *c, bool warn, bool error)
767238742Simp{
768238742Simp	int i;
769238742Simp
770238742Simp	/* Raising level, also raise it for prereqs */
771238742Simp	if ((warn && !c->warn) || (error && !c->error))
772238742Simp		for (i = 0; i < c->num_prereqs; i++)
773238742Simp			enable_warning_error(c->prereq[i], warn, error);
774238742Simp
775238742Simp	c->warn = c->warn || warn;
776238742Simp	c->error = c->error || error;
777238742Simp}
778238742Simp
779238742Simpstatic void disable_warning_error(struct check *c, bool warn, bool error)
780238742Simp{
781238742Simp	int i;
782238742Simp
783238742Simp	/* Lowering level, also lower it for things this is the prereq
784238742Simp	 * for */
785238742Simp	if ((warn && c->warn) || (error && c->error)) {
786238742Simp		for (i = 0; i < ARRAY_SIZE(check_table); i++) {
787238742Simp			struct check *cc = check_table[i];
788238742Simp			int j;
789238742Simp
790238742Simp			for (j = 0; j < cc->num_prereqs; j++)
791238742Simp				if (cc->prereq[j] == c)
792238742Simp					disable_warning_error(cc, warn, error);
793238742Simp		}
794238742Simp	}
795238742Simp
796238742Simp	c->warn = c->warn && !warn;
797238742Simp	c->error = c->error && !error;
798238742Simp}
799238742Simp
800318102Sgonzovoid parse_checks_option(bool warn, bool error, const char *arg)
801238742Simp{
802238742Simp	int i;
803318102Sgonzo	const char *name = arg;
804238742Simp	bool enable = true;
805238742Simp
806318102Sgonzo	if ((strncmp(arg, "no-", 3) == 0)
807318102Sgonzo	    || (strncmp(arg, "no_", 3) == 0)) {
808318102Sgonzo		name = arg + 3;
809238742Simp		enable = false;
810238742Simp	}
811238742Simp
812238742Simp	for (i = 0; i < ARRAY_SIZE(check_table); i++) {
813238742Simp		struct check *c = check_table[i];
814238742Simp
815238742Simp		if (streq(c->name, name)) {
816238742Simp			if (enable)
817238742Simp				enable_warning_error(c, warn, error);
818238742Simp			else
819238742Simp				disable_warning_error(c, warn, error);
820238742Simp			return;
821238742Simp		}
822238742Simp	}
823238742Simp
824238742Simp	die("Unrecognized check name \"%s\"\n", name);
825238742Simp}
826238742Simp
827318102Sgonzovoid process_checks(bool force, struct dt_info *dti)
828204431Sraj{
829204431Sraj	int i;
830204431Sraj	int error = 0;
831204431Sraj
832204431Sraj	for (i = 0; i < ARRAY_SIZE(check_table); i++) {
833204431Sraj		struct check *c = check_table[i];
834204431Sraj
835238742Simp		if (c->warn || c->error)
836318102Sgonzo			error = error || run_check(c, dti);
837204431Sraj	}
838204431Sraj
839204431Sraj	if (error) {
840204431Sraj		if (!force) {
841204431Sraj			fprintf(stderr, "ERROR: Input tree has errors, aborting "
842204431Sraj				"(use -f to force output)\n");
843204431Sraj			exit(2);
844204431Sraj		} else if (quiet < 3) {
845204431Sraj			fprintf(stderr, "Warning: Input tree has errors, "
846204431Sraj				"output forced\n");
847204431Sraj		}
848204431Sraj	}
849204431Sraj}
850