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, ®_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