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 43204431Srajtypedef void (*tree_check_fn)(struct check *c, struct node *dt); 44204431Srajtypedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); 45204431Srajtypedef void (*prop_check_fn)(struct check *c, struct node *dt, 46204431Sraj struct node *node, struct property *prop); 47204431Sraj 48204431Srajstruct check { 49204431Sraj const char *name; 50204431Sraj tree_check_fn tree_fn; 51204431Sraj node_check_fn node_fn; 52204431Sraj prop_check_fn prop_fn; 53204431Sraj void *data; 54238742Simp bool warn, error; 55204431Sraj enum checkstatus status; 56266130Sian bool inprogress; 57204431Sraj int num_prereqs; 58204431Sraj struct check **prereq; 59204431Sraj}; 60204431Sraj 61238742Simp#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ 62204431Sraj static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ 63204431Sraj static struct check nm = { \ 64204431Sraj .name = #nm, \ 65204431Sraj .tree_fn = (tfn), \ 66204431Sraj .node_fn = (nfn), \ 67204431Sraj .prop_fn = (pfn), \ 68204431Sraj .data = (d), \ 69238742Simp .warn = (w), \ 70238742Simp .error = (e), \ 71204431Sraj .status = UNCHECKED, \ 72204431Sraj .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ 73204431Sraj .prereq = nm##_prereqs, \ 74204431Sraj }; 75238742Simp#define WARNING(nm, tfn, nfn, pfn, d, ...) \ 76238742Simp CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) 77238742Simp#define ERROR(nm, tfn, nfn, pfn, d, ...) \ 78238742Simp CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) 79238742Simp#define CHECK(nm, tfn, nfn, pfn, d, ...) \ 80238742Simp CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) 81204431Sraj 82238742Simp#define TREE_WARNING(nm, d, ...) \ 83238742Simp WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 84238742Simp#define TREE_ERROR(nm, d, ...) \ 85238742Simp ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 86238742Simp#define TREE_CHECK(nm, d, ...) \ 87238742Simp CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 88238742Simp#define NODE_WARNING(nm, d, ...) \ 89238742Simp WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 90238742Simp#define NODE_ERROR(nm, d, ...) \ 91238742Simp ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 92238742Simp#define NODE_CHECK(nm, d, ...) \ 93238742Simp CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 94238742Simp#define PROP_WARNING(nm, d, ...) \ 95238742Simp WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 96238742Simp#define PROP_ERROR(nm, d, ...) \ 97238742Simp ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 98238742Simp#define PROP_CHECK(nm, d, ...) \ 99238742Simp CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 100204431Sraj 101204431Sraj#ifdef __GNUC__ 102204431Srajstatic inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); 103204431Sraj#endif 104204431Srajstatic inline void check_msg(struct check *c, const char *fmt, ...) 105204431Sraj{ 106204431Sraj va_list ap; 107204431Sraj va_start(ap, fmt); 108204431Sraj 109238742Simp if ((c->warn && (quiet < 1)) 110238742Simp || (c->error && (quiet < 2))) { 111238742Simp fprintf(stderr, "%s (%s): ", 112238742Simp (c->error) ? "ERROR" : "Warning", c->name); 113238742Simp vfprintf(stderr, fmt, ap); 114238742Simp fprintf(stderr, "\n"); 115238742Simp } 116204431Sraj} 117204431Sraj 118204431Sraj#define FAIL(c, ...) \ 119204431Sraj do { \ 120204431Sraj TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ 121204431Sraj (c)->status = FAILED; \ 122204431Sraj check_msg((c), __VA_ARGS__); \ 123204431Sraj } while (0) 124204431Sraj 125204431Srajstatic void check_nodes_props(struct check *c, struct node *dt, struct node *node) 126204431Sraj{ 127204431Sraj struct node *child; 128204431Sraj struct property *prop; 129204431Sraj 130204431Sraj TRACE(c, "%s", node->fullpath); 131204431Sraj if (c->node_fn) 132204431Sraj c->node_fn(c, dt, node); 133204431Sraj 134204431Sraj if (c->prop_fn) 135204431Sraj for_each_property(node, prop) { 136204431Sraj TRACE(c, "%s\t'%s'", node->fullpath, prop->name); 137204431Sraj c->prop_fn(c, dt, node, prop); 138204431Sraj } 139204431Sraj 140204431Sraj for_each_child(node, child) 141204431Sraj check_nodes_props(c, dt, child); 142204431Sraj} 143204431Sraj 144266130Sianstatic bool run_check(struct check *c, struct node *dt) 145204431Sraj{ 146266130Sian bool error = false; 147204431Sraj int i; 148204431Sraj 149204431Sraj assert(!c->inprogress); 150204431Sraj 151204431Sraj if (c->status != UNCHECKED) 152204431Sraj goto out; 153204431Sraj 154266130Sian c->inprogress = true; 155204431Sraj 156204431Sraj for (i = 0; i < c->num_prereqs; i++) { 157204431Sraj struct check *prq = c->prereq[i]; 158266130Sian error = error || run_check(prq, dt); 159204431Sraj if (prq->status != PASSED) { 160204431Sraj c->status = PREREQ; 161204431Sraj check_msg(c, "Failed prerequisite '%s'", 162204431Sraj c->prereq[i]->name); 163204431Sraj } 164204431Sraj } 165204431Sraj 166204431Sraj if (c->status != UNCHECKED) 167204431Sraj goto out; 168204431Sraj 169204431Sraj if (c->node_fn || c->prop_fn) 170204431Sraj check_nodes_props(c, dt, dt); 171204431Sraj 172204431Sraj if (c->tree_fn) 173204431Sraj c->tree_fn(c, dt); 174204431Sraj if (c->status == UNCHECKED) 175204431Sraj c->status = PASSED; 176204431Sraj 177204431Sraj TRACE(c, "\tCompleted, status %d", c->status); 178204431Sraj 179204431Srajout: 180266130Sian c->inprogress = false; 181238742Simp if ((c->status != PASSED) && (c->error)) 182266130Sian error = true; 183204431Sraj return error; 184204431Sraj} 185204431Sraj 186204431Sraj/* 187204431Sraj * Utility check functions 188204431Sraj */ 189204431Sraj 190238742Simp/* A check which always fails, for testing purposes only */ 191238742Simpstatic inline void check_always_fail(struct check *c, struct node *dt) 192238742Simp{ 193238742Simp FAIL(c, "always_fail check"); 194238742Simp} 195238742SimpTREE_CHECK(always_fail, NULL); 196238742Simp 197204431Srajstatic void check_is_string(struct check *c, struct node *root, 198204431Sraj struct node *node) 199204431Sraj{ 200204431Sraj struct property *prop; 201204431Sraj char *propname = c->data; 202204431Sraj 203204431Sraj prop = get_property(node, propname); 204204431Sraj if (!prop) 205204431Sraj return; /* Not present, assumed ok */ 206204431Sraj 207204431Sraj if (!data_is_one_string(prop->val)) 208204431Sraj FAIL(c, "\"%s\" property in %s is not a string", 209204431Sraj propname, node->fullpath); 210204431Sraj} 211238742Simp#define WARNING_IF_NOT_STRING(nm, propname) \ 212238742Simp WARNING(nm, NULL, check_is_string, NULL, (propname)) 213238742Simp#define ERROR_IF_NOT_STRING(nm, propname) \ 214238742Simp ERROR(nm, NULL, check_is_string, NULL, (propname)) 215204431Sraj 216204431Srajstatic void check_is_cell(struct check *c, struct node *root, 217204431Sraj struct node *node) 218204431Sraj{ 219204431Sraj struct property *prop; 220204431Sraj char *propname = c->data; 221204431Sraj 222204431Sraj prop = get_property(node, propname); 223204431Sraj if (!prop) 224204431Sraj return; /* Not present, assumed ok */ 225204431Sraj 226204431Sraj if (prop->val.len != sizeof(cell_t)) 227204431Sraj FAIL(c, "\"%s\" property in %s is not a single cell", 228204431Sraj propname, node->fullpath); 229204431Sraj} 230238742Simp#define WARNING_IF_NOT_CELL(nm, propname) \ 231238742Simp WARNING(nm, NULL, check_is_cell, NULL, (propname)) 232238742Simp#define ERROR_IF_NOT_CELL(nm, propname) \ 233238742Simp ERROR(nm, NULL, check_is_cell, NULL, (propname)) 234204431Sraj 235204431Sraj/* 236204431Sraj * Structural check functions 237204431Sraj */ 238204431Sraj 239204431Srajstatic void check_duplicate_node_names(struct check *c, struct node *dt, 240204431Sraj struct node *node) 241204431Sraj{ 242204431Sraj struct node *child, *child2; 243204431Sraj 244204431Sraj for_each_child(node, child) 245204431Sraj for (child2 = child->next_sibling; 246204431Sraj child2; 247204431Sraj child2 = child2->next_sibling) 248204431Sraj if (streq(child->name, child2->name)) 249204431Sraj FAIL(c, "Duplicate node name %s", 250204431Sraj child->fullpath); 251204431Sraj} 252238742SimpNODE_ERROR(duplicate_node_names, NULL); 253204431Sraj 254204431Srajstatic void check_duplicate_property_names(struct check *c, struct node *dt, 255204431Sraj struct node *node) 256204431Sraj{ 257204431Sraj struct property *prop, *prop2; 258204431Sraj 259266130Sian for_each_property(node, prop) { 260266130Sian for (prop2 = prop->next; prop2; prop2 = prop2->next) { 261266130Sian if (prop2->deleted) 262266130Sian continue; 263204431Sraj if (streq(prop->name, prop2->name)) 264204431Sraj FAIL(c, "Duplicate property name %s in %s", 265204431Sraj prop->name, node->fullpath); 266266130Sian } 267266130Sian } 268204431Sraj} 269238742SimpNODE_ERROR(duplicate_property_names, NULL); 270204431Sraj 271204431Sraj#define LOWERCASE "abcdefghijklmnopqrstuvwxyz" 272204431Sraj#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 273204431Sraj#define DIGITS "0123456789" 274204431Sraj#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" 275204431Sraj 276204431Srajstatic void check_node_name_chars(struct check *c, struct node *dt, 277204431Sraj struct node *node) 278204431Sraj{ 279204431Sraj int n = strspn(node->name, c->data); 280204431Sraj 281204431Sraj if (n < strlen(node->name)) 282204431Sraj FAIL(c, "Bad character '%c' in node %s", 283204431Sraj node->name[n], node->fullpath); 284204431Sraj} 285238742SimpNODE_ERROR(node_name_chars, PROPNODECHARS "@"); 286204431Sraj 287204431Srajstatic void check_node_name_format(struct check *c, struct node *dt, 288204431Sraj struct node *node) 289204431Sraj{ 290204431Sraj if (strchr(get_unitname(node), '@')) 291204431Sraj FAIL(c, "Node %s has multiple '@' characters in name", 292204431Sraj node->fullpath); 293204431Sraj} 294238742SimpNODE_ERROR(node_name_format, NULL, &node_name_chars); 295204431Sraj 296204431Srajstatic void check_property_name_chars(struct check *c, struct node *dt, 297204431Sraj struct node *node, struct property *prop) 298204431Sraj{ 299204431Sraj int n = strspn(prop->name, c->data); 300204431Sraj 301204431Sraj if (n < strlen(prop->name)) 302204431Sraj FAIL(c, "Bad character '%c' in property name \"%s\", node %s", 303204431Sraj prop->name[n], prop->name, node->fullpath); 304204431Sraj} 305238742SimpPROP_ERROR(property_name_chars, PROPNODECHARS); 306204431Sraj 307238742Simp#define DESCLABEL_FMT "%s%s%s%s%s" 308238742Simp#define DESCLABEL_ARGS(node,prop,mark) \ 309238742Simp ((mark) ? "value of " : ""), \ 310238742Simp ((prop) ? "'" : ""), \ 311238742Simp ((prop) ? (prop)->name : ""), \ 312238742Simp ((prop) ? "' in " : ""), (node)->fullpath 313238742Simp 314238742Simpstatic void check_duplicate_label(struct check *c, struct node *dt, 315238742Simp const char *label, struct node *node, 316238742Simp struct property *prop, struct marker *mark) 317238742Simp{ 318238742Simp struct node *othernode = NULL; 319238742Simp struct property *otherprop = NULL; 320238742Simp struct marker *othermark = NULL; 321238742Simp 322238742Simp othernode = get_node_by_label(dt, label); 323238742Simp 324238742Simp if (!othernode) 325238742Simp otherprop = get_property_by_label(dt, label, &othernode); 326238742Simp if (!othernode) 327238742Simp othermark = get_marker_label(dt, label, &othernode, 328238742Simp &otherprop); 329238742Simp 330238742Simp if (!othernode) 331238742Simp return; 332238742Simp 333238742Simp if ((othernode != node) || (otherprop != prop) || (othermark != mark)) 334238742Simp FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT 335238742Simp " and " DESCLABEL_FMT, 336238742Simp label, DESCLABEL_ARGS(node, prop, mark), 337238742Simp DESCLABEL_ARGS(othernode, otherprop, othermark)); 338238742Simp} 339238742Simp 340238742Simpstatic void check_duplicate_label_node(struct check *c, struct node *dt, 341238742Simp struct node *node) 342238742Simp{ 343238742Simp struct label *l; 344238742Simp 345238742Simp for_each_label(node->labels, l) 346238742Simp check_duplicate_label(c, dt, l->label, node, NULL, NULL); 347238742Simp} 348238742Simpstatic void check_duplicate_label_prop(struct check *c, struct node *dt, 349238742Simp struct node *node, struct property *prop) 350238742Simp{ 351238742Simp struct marker *m = prop->val.markers; 352238742Simp struct label *l; 353238742Simp 354238742Simp for_each_label(prop->labels, l) 355238742Simp check_duplicate_label(c, dt, l->label, node, prop, NULL); 356238742Simp 357238742Simp for_each_marker_of_type(m, LABEL) 358238742Simp check_duplicate_label(c, dt, m->ref, node, prop, m); 359238742Simp} 360238742SimpERROR(duplicate_label, NULL, check_duplicate_label_node, 361238742Simp check_duplicate_label_prop, NULL); 362238742Simp 363204431Srajstatic void check_explicit_phandles(struct check *c, struct node *root, 364204433Sraj struct node *node, struct property *prop) 365204431Sraj{ 366204433Sraj struct marker *m; 367204431Sraj struct node *other; 368204431Sraj cell_t phandle; 369204431Sraj 370204433Sraj if (!streq(prop->name, "phandle") 371204433Sraj && !streq(prop->name, "linux,phandle")) 372204433Sraj return; 373204431Sraj 374204431Sraj if (prop->val.len != sizeof(cell_t)) { 375204433Sraj FAIL(c, "%s has bad length (%d) %s property", 376204433Sraj node->fullpath, prop->val.len, prop->name); 377204431Sraj return; 378204431Sraj } 379204431Sraj 380204433Sraj m = prop->val.markers; 381204433Sraj for_each_marker_of_type(m, REF_PHANDLE) { 382204433Sraj assert(m->offset == 0); 383204433Sraj if (node != get_node_by_ref(root, m->ref)) 384204433Sraj /* "Set this node's phandle equal to some 385204433Sraj * other node's phandle". That's nonsensical 386204433Sraj * by construction. */ { 387204433Sraj FAIL(c, "%s in %s is a reference to another node", 388204433Sraj prop->name, node->fullpath); 389204433Sraj return; 390204433Sraj } 391204433Sraj /* But setting this node's phandle equal to its own 392204433Sraj * phandle is allowed - that means allocate a unique 393204433Sraj * phandle for this node, even if it's not otherwise 394204433Sraj * referenced. The value will be filled in later, so 395204433Sraj * no further checking for now. */ 396204433Sraj return; 397204433Sraj } 398204433Sraj 399204431Sraj phandle = propval_cell(prop); 400204433Sraj 401204431Sraj if ((phandle == 0) || (phandle == -1)) { 402204433Sraj FAIL(c, "%s has bad value (0x%x) in %s property", 403204433Sraj node->fullpath, phandle, prop->name); 404204431Sraj return; 405204431Sraj } 406204431Sraj 407204433Sraj if (node->phandle && (node->phandle != phandle)) 408204433Sraj FAIL(c, "%s has %s property which replaces existing phandle information", 409204433Sraj node->fullpath, prop->name); 410204433Sraj 411204431Sraj other = get_node_by_phandle(root, phandle); 412204433Sraj if (other && (other != node)) { 413204431Sraj FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", 414204431Sraj node->fullpath, phandle, other->fullpath); 415204431Sraj return; 416204431Sraj } 417204431Sraj 418204431Sraj node->phandle = phandle; 419204431Sraj} 420238742SimpPROP_ERROR(explicit_phandles, NULL); 421204431Sraj 422204431Srajstatic void check_name_properties(struct check *c, struct node *root, 423204431Sraj struct node *node) 424204431Sraj{ 425204431Sraj struct property **pp, *prop = NULL; 426204431Sraj 427204431Sraj for (pp = &node->proplist; *pp; pp = &((*pp)->next)) 428204431Sraj if (streq((*pp)->name, "name")) { 429204431Sraj prop = *pp; 430204431Sraj break; 431204431Sraj } 432204431Sraj 433204431Sraj if (!prop) 434204431Sraj return; /* No name property, that's fine */ 435204431Sraj 436204431Sraj if ((prop->val.len != node->basenamelen+1) 437204431Sraj || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { 438204431Sraj FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" 439204431Sraj " of base node name)", node->fullpath, prop->val.val); 440204431Sraj } else { 441204431Sraj /* The name property is correct, and therefore redundant. 442204431Sraj * Delete it */ 443204431Sraj *pp = prop->next; 444204431Sraj free(prop->name); 445204431Sraj data_free(prop->val); 446204431Sraj free(prop); 447204431Sraj } 448204431Sraj} 449238742SimpERROR_IF_NOT_STRING(name_is_string, "name"); 450238742SimpNODE_ERROR(name_properties, NULL, &name_is_string); 451204431Sraj 452204431Sraj/* 453204431Sraj * Reference fixup functions 454204431Sraj */ 455204431Sraj 456204431Srajstatic void fixup_phandle_references(struct check *c, struct node *dt, 457204431Sraj struct node *node, struct property *prop) 458204431Sraj{ 459204431Sraj struct marker *m = prop->val.markers; 460204431Sraj struct node *refnode; 461204431Sraj cell_t phandle; 462204431Sraj 463204431Sraj for_each_marker_of_type(m, REF_PHANDLE) { 464204431Sraj assert(m->offset + sizeof(cell_t) <= prop->val.len); 465204431Sraj 466204431Sraj refnode = get_node_by_ref(dt, m->ref); 467204431Sraj if (! refnode) { 468204431Sraj FAIL(c, "Reference to non-existent node or label \"%s\"\n", 469204431Sraj m->ref); 470204431Sraj continue; 471204431Sraj } 472204431Sraj 473204431Sraj phandle = get_node_phandle(dt, refnode); 474204431Sraj *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); 475204431Sraj } 476204431Sraj} 477238742SimpERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, 478204431Sraj &duplicate_node_names, &explicit_phandles); 479204431Sraj 480204431Srajstatic void fixup_path_references(struct check *c, struct node *dt, 481204431Sraj struct node *node, struct property *prop) 482204431Sraj{ 483204431Sraj struct marker *m = prop->val.markers; 484204431Sraj struct node *refnode; 485204431Sraj char *path; 486204431Sraj 487204431Sraj for_each_marker_of_type(m, REF_PATH) { 488204431Sraj assert(m->offset <= prop->val.len); 489204431Sraj 490204431Sraj refnode = get_node_by_ref(dt, m->ref); 491204431Sraj if (!refnode) { 492204431Sraj FAIL(c, "Reference to non-existent node or label \"%s\"\n", 493204431Sraj m->ref); 494204431Sraj continue; 495204431Sraj } 496204431Sraj 497204431Sraj path = refnode->fullpath; 498204431Sraj prop->val = data_insert_at_marker(prop->val, m, path, 499204431Sraj strlen(path) + 1); 500204431Sraj } 501204431Sraj} 502238742SimpERROR(path_references, NULL, NULL, fixup_path_references, NULL, 503204431Sraj &duplicate_node_names); 504204431Sraj 505204431Sraj/* 506204431Sraj * Semantic checks 507204431Sraj */ 508238742SimpWARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); 509238742SimpWARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); 510238742SimpWARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); 511204431Sraj 512238742SimpWARNING_IF_NOT_STRING(device_type_is_string, "device_type"); 513238742SimpWARNING_IF_NOT_STRING(model_is_string, "model"); 514238742SimpWARNING_IF_NOT_STRING(status_is_string, "status"); 515204431Sraj 516204431Srajstatic void fixup_addr_size_cells(struct check *c, struct node *dt, 517204431Sraj struct node *node) 518204431Sraj{ 519204431Sraj struct property *prop; 520204431Sraj 521204431Sraj node->addr_cells = -1; 522204431Sraj node->size_cells = -1; 523204431Sraj 524204431Sraj prop = get_property(node, "#address-cells"); 525204431Sraj if (prop) 526204431Sraj node->addr_cells = propval_cell(prop); 527204431Sraj 528204431Sraj prop = get_property(node, "#size-cells"); 529204431Sraj if (prop) 530204431Sraj node->size_cells = propval_cell(prop); 531204431Sraj} 532238742SimpWARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, 533238742Simp &address_cells_is_cell, &size_cells_is_cell); 534204431Sraj 535204431Sraj#define node_addr_cells(n) \ 536204431Sraj (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) 537204431Sraj#define node_size_cells(n) \ 538204431Sraj (((n)->size_cells == -1) ? 1 : (n)->size_cells) 539204431Sraj 540204431Srajstatic void check_reg_format(struct check *c, struct node *dt, 541204431Sraj struct node *node) 542204431Sraj{ 543204431Sraj struct property *prop; 544204431Sraj int addr_cells, size_cells, entrylen; 545204431Sraj 546204431Sraj prop = get_property(node, "reg"); 547204431Sraj if (!prop) 548204431Sraj return; /* No "reg", that's fine */ 549204431Sraj 550204431Sraj if (!node->parent) { 551204431Sraj FAIL(c, "Root node has a \"reg\" property"); 552204431Sraj return; 553204431Sraj } 554204431Sraj 555204431Sraj if (prop->val.len == 0) 556204431Sraj FAIL(c, "\"reg\" property in %s is empty", node->fullpath); 557204431Sraj 558204431Sraj addr_cells = node_addr_cells(node->parent); 559204431Sraj size_cells = node_size_cells(node->parent); 560204431Sraj entrylen = (addr_cells + size_cells) * sizeof(cell_t); 561204431Sraj 562204431Sraj if ((prop->val.len % entrylen) != 0) 563204431Sraj FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " 564204431Sraj "(#address-cells == %d, #size-cells == %d)", 565204431Sraj node->fullpath, prop->val.len, addr_cells, size_cells); 566204431Sraj} 567238742SimpNODE_WARNING(reg_format, NULL, &addr_size_cells); 568204431Sraj 569204431Srajstatic void check_ranges_format(struct check *c, struct node *dt, 570204431Sraj struct node *node) 571204431Sraj{ 572204431Sraj struct property *prop; 573204431Sraj int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; 574204431Sraj 575204431Sraj prop = get_property(node, "ranges"); 576204431Sraj if (!prop) 577204431Sraj return; 578204431Sraj 579204431Sraj if (!node->parent) { 580204431Sraj FAIL(c, "Root node has a \"ranges\" property"); 581204431Sraj return; 582204431Sraj } 583204431Sraj 584204431Sraj p_addr_cells = node_addr_cells(node->parent); 585204431Sraj p_size_cells = node_size_cells(node->parent); 586204431Sraj c_addr_cells = node_addr_cells(node); 587204431Sraj c_size_cells = node_size_cells(node); 588204431Sraj entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t); 589204431Sraj 590204431Sraj if (prop->val.len == 0) { 591204431Sraj if (p_addr_cells != c_addr_cells) 592204431Sraj FAIL(c, "%s has empty \"ranges\" property but its " 593204431Sraj "#address-cells (%d) differs from %s (%d)", 594204431Sraj node->fullpath, c_addr_cells, node->parent->fullpath, 595204431Sraj p_addr_cells); 596204431Sraj if (p_size_cells != c_size_cells) 597204431Sraj FAIL(c, "%s has empty \"ranges\" property but its " 598204431Sraj "#size-cells (%d) differs from %s (%d)", 599204431Sraj node->fullpath, c_size_cells, node->parent->fullpath, 600204431Sraj p_size_cells); 601204431Sraj } else if ((prop->val.len % entrylen) != 0) { 602204431Sraj FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) " 603204431Sraj "(parent #address-cells == %d, child #address-cells == %d, " 604204431Sraj "#size-cells == %d)", node->fullpath, prop->val.len, 605204431Sraj p_addr_cells, c_addr_cells, c_size_cells); 606204431Sraj } 607204431Sraj} 608238742SimpNODE_WARNING(ranges_format, NULL, &addr_size_cells); 609204431Sraj 610204431Sraj/* 611204431Sraj * Style checks 612204431Sraj */ 613204431Srajstatic void check_avoid_default_addr_size(struct check *c, struct node *dt, 614204431Sraj struct node *node) 615204431Sraj{ 616204431Sraj struct property *reg, *ranges; 617204431Sraj 618204431Sraj if (!node->parent) 619204431Sraj return; /* Ignore root node */ 620204431Sraj 621204431Sraj reg = get_property(node, "reg"); 622204431Sraj ranges = get_property(node, "ranges"); 623204431Sraj 624204431Sraj if (!reg && !ranges) 625204431Sraj return; 626204431Sraj 627204431Sraj if ((node->parent->addr_cells == -1)) 628204431Sraj FAIL(c, "Relying on default #address-cells value for %s", 629204431Sraj node->fullpath); 630204431Sraj 631204431Sraj if ((node->parent->size_cells == -1)) 632204431Sraj FAIL(c, "Relying on default #size-cells value for %s", 633204431Sraj node->fullpath); 634204431Sraj} 635238742SimpNODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); 636204431Sraj 637204431Srajstatic void check_obsolete_chosen_interrupt_controller(struct check *c, 638204431Sraj struct node *dt) 639204431Sraj{ 640204431Sraj struct node *chosen; 641204431Sraj struct property *prop; 642204431Sraj 643204431Sraj chosen = get_node_by_path(dt, "/chosen"); 644204431Sraj if (!chosen) 645204431Sraj return; 646204431Sraj 647204431Sraj prop = get_property(chosen, "interrupt-controller"); 648204431Sraj if (prop) 649204431Sraj FAIL(c, "/chosen has obsolete \"interrupt-controller\" " 650204431Sraj "property"); 651204431Sraj} 652238742SimpTREE_WARNING(obsolete_chosen_interrupt_controller, NULL); 653204431Sraj 654204431Srajstatic struct check *check_table[] = { 655204431Sraj &duplicate_node_names, &duplicate_property_names, 656204431Sraj &node_name_chars, &node_name_format, &property_name_chars, 657204431Sraj &name_is_string, &name_properties, 658238742Simp 659238742Simp &duplicate_label, 660238742Simp 661204431Sraj &explicit_phandles, 662204431Sraj &phandle_references, &path_references, 663204431Sraj 664204431Sraj &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, 665204431Sraj &device_type_is_string, &model_is_string, &status_is_string, 666204431Sraj 667204431Sraj &addr_size_cells, ®_format, &ranges_format, 668204431Sraj 669204431Sraj &avoid_default_addr_size, 670204431Sraj &obsolete_chosen_interrupt_controller, 671238742Simp 672238742Simp &always_fail, 673204431Sraj}; 674204431Sraj 675238742Simpstatic void enable_warning_error(struct check *c, bool warn, bool error) 676238742Simp{ 677238742Simp int i; 678238742Simp 679238742Simp /* Raising level, also raise it for prereqs */ 680238742Simp if ((warn && !c->warn) || (error && !c->error)) 681238742Simp for (i = 0; i < c->num_prereqs; i++) 682238742Simp enable_warning_error(c->prereq[i], warn, error); 683238742Simp 684238742Simp c->warn = c->warn || warn; 685238742Simp c->error = c->error || error; 686238742Simp} 687238742Simp 688238742Simpstatic void disable_warning_error(struct check *c, bool warn, bool error) 689238742Simp{ 690238742Simp int i; 691238742Simp 692238742Simp /* Lowering level, also lower it for things this is the prereq 693238742Simp * for */ 694238742Simp if ((warn && c->warn) || (error && c->error)) { 695238742Simp for (i = 0; i < ARRAY_SIZE(check_table); i++) { 696238742Simp struct check *cc = check_table[i]; 697238742Simp int j; 698238742Simp 699238742Simp for (j = 0; j < cc->num_prereqs; j++) 700238742Simp if (cc->prereq[j] == c) 701238742Simp disable_warning_error(cc, warn, error); 702238742Simp } 703238742Simp } 704238742Simp 705238742Simp c->warn = c->warn && !warn; 706238742Simp c->error = c->error && !error; 707238742Simp} 708238742Simp 709238742Simpvoid parse_checks_option(bool warn, bool error, const char *optarg) 710238742Simp{ 711238742Simp int i; 712238742Simp const char *name = optarg; 713238742Simp bool enable = true; 714238742Simp 715238742Simp if ((strncmp(optarg, "no-", 3) == 0) 716238742Simp || (strncmp(optarg, "no_", 3) == 0)) { 717238742Simp name = optarg + 3; 718238742Simp enable = false; 719238742Simp } 720238742Simp 721238742Simp for (i = 0; i < ARRAY_SIZE(check_table); i++) { 722238742Simp struct check *c = check_table[i]; 723238742Simp 724238742Simp if (streq(c->name, name)) { 725238742Simp if (enable) 726238742Simp enable_warning_error(c, warn, error); 727238742Simp else 728238742Simp disable_warning_error(c, warn, error); 729238742Simp return; 730238742Simp } 731238742Simp } 732238742Simp 733238742Simp die("Unrecognized check name \"%s\"\n", name); 734238742Simp} 735238742Simp 736266130Sianvoid process_checks(bool force, struct boot_info *bi) 737204431Sraj{ 738204431Sraj struct node *dt = bi->dt; 739204431Sraj int i; 740204431Sraj int error = 0; 741204431Sraj 742204431Sraj for (i = 0; i < ARRAY_SIZE(check_table); i++) { 743204431Sraj struct check *c = check_table[i]; 744204431Sraj 745238742Simp if (c->warn || c->error) 746204431Sraj error = error || run_check(c, dt); 747204431Sraj } 748204431Sraj 749204431Sraj if (error) { 750204431Sraj if (!force) { 751204431Sraj fprintf(stderr, "ERROR: Input tree has errors, aborting " 752204431Sraj "(use -f to force output)\n"); 753204431Sraj exit(2); 754204431Sraj } else if (quiet < 3) { 755204431Sraj fprintf(stderr, "Warning: Input tree has errors, " 756204431Sraj "output forced\n"); 757204431Sraj } 758204431Sraj } 759204431Sraj} 760