checks.c revision 318102
1/* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21#include "dtc.h" 22 23#ifdef TRACE_CHECKS 24#define TRACE(c, ...) \ 25 do { \ 26 fprintf(stderr, "=== %s: ", (c)->name); \ 27 fprintf(stderr, __VA_ARGS__); \ 28 fprintf(stderr, "\n"); \ 29 } while (0) 30#else 31#define TRACE(c, fmt, ...) do { } while (0) 32#endif 33 34enum checkstatus { 35 UNCHECKED = 0, 36 PREREQ, 37 PASSED, 38 FAILED, 39}; 40 41struct check; 42 43typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node); 44 45struct check { 46 const char *name; 47 check_fn fn; 48 void *data; 49 bool warn, error; 50 enum checkstatus status; 51 bool inprogress; 52 int num_prereqs; 53 struct check **prereq; 54}; 55 56#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ 57 static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ 58 static struct check _nm = { \ 59 .name = #_nm, \ 60 .fn = (_fn), \ 61 .data = (_d), \ 62 .warn = (_w), \ 63 .error = (_e), \ 64 .status = UNCHECKED, \ 65 .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ 66 .prereq = _nm##_prereqs, \ 67 }; 68#define WARNING(_nm, _fn, _d, ...) \ 69 CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) 70#define ERROR(_nm, _fn, _d, ...) \ 71 CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) 72#define CHECK(_nm, _fn, _d, ...) \ 73 CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) 74 75#ifdef __GNUC__ 76static inline void check_msg(struct check *c, struct dt_info *dti, 77 const char *fmt, ...) __attribute__((format (printf, 3, 4))); 78#endif 79static inline void check_msg(struct check *c, struct dt_info *dti, 80 const char *fmt, ...) 81{ 82 va_list ap; 83 va_start(ap, fmt); 84 85 if ((c->warn && (quiet < 1)) 86 || (c->error && (quiet < 2))) { 87 fprintf(stderr, "%s: %s (%s): ", 88 strcmp(dti->outname, "-") ? dti->outname : "<stdout>", 89 (c->error) ? "ERROR" : "Warning", c->name); 90 vfprintf(stderr, fmt, ap); 91 fprintf(stderr, "\n"); 92 } 93 va_end(ap); 94} 95 96#define FAIL(c, dti, ...) \ 97 do { \ 98 TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ 99 (c)->status = FAILED; \ 100 check_msg((c), dti, __VA_ARGS__); \ 101 } while (0) 102 103static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node) 104{ 105 struct node *child; 106 107 TRACE(c, "%s", node->fullpath); 108 if (c->fn) 109 c->fn(c, dti, node); 110 111 for_each_child(node, child) 112 check_nodes_props(c, dti, child); 113} 114 115static bool run_check(struct check *c, struct dt_info *dti) 116{ 117 struct node *dt = dti->dt; 118 bool error = false; 119 int i; 120 121 assert(!c->inprogress); 122 123 if (c->status != UNCHECKED) 124 goto out; 125 126 c->inprogress = true; 127 128 for (i = 0; i < c->num_prereqs; i++) { 129 struct check *prq = c->prereq[i]; 130 error = error || run_check(prq, dti); 131 if (prq->status != PASSED) { 132 c->status = PREREQ; 133 check_msg(c, dti, "Failed prerequisite '%s'", 134 c->prereq[i]->name); 135 } 136 } 137 138 if (c->status != UNCHECKED) 139 goto out; 140 141 check_nodes_props(c, dti, dt); 142 143 if (c->status == UNCHECKED) 144 c->status = PASSED; 145 146 TRACE(c, "\tCompleted, status %d", c->status); 147 148out: 149 c->inprogress = false; 150 if ((c->status != PASSED) && (c->error)) 151 error = true; 152 return error; 153} 154 155/* 156 * Utility check functions 157 */ 158 159/* A check which always fails, for testing purposes only */ 160static inline void check_always_fail(struct check *c, struct dt_info *dti, 161 struct node *node) 162{ 163 FAIL(c, dti, "always_fail check"); 164} 165CHECK(always_fail, check_always_fail, NULL); 166 167static void check_is_string(struct check *c, struct dt_info *dti, 168 struct node *node) 169{ 170 struct property *prop; 171 char *propname = c->data; 172 173 prop = get_property(node, propname); 174 if (!prop) 175 return; /* Not present, assumed ok */ 176 177 if (!data_is_one_string(prop->val)) 178 FAIL(c, dti, "\"%s\" property in %s is not a string", 179 propname, node->fullpath); 180} 181#define WARNING_IF_NOT_STRING(nm, propname) \ 182 WARNING(nm, check_is_string, (propname)) 183#define ERROR_IF_NOT_STRING(nm, propname) \ 184 ERROR(nm, check_is_string, (propname)) 185 186static void check_is_cell(struct check *c, struct dt_info *dti, 187 struct node *node) 188{ 189 struct property *prop; 190 char *propname = c->data; 191 192 prop = get_property(node, propname); 193 if (!prop) 194 return; /* Not present, assumed ok */ 195 196 if (prop->val.len != sizeof(cell_t)) 197 FAIL(c, dti, "\"%s\" property in %s is not a single cell", 198 propname, node->fullpath); 199} 200#define WARNING_IF_NOT_CELL(nm, propname) \ 201 WARNING(nm, check_is_cell, (propname)) 202#define ERROR_IF_NOT_CELL(nm, propname) \ 203 ERROR(nm, check_is_cell, (propname)) 204 205/* 206 * Structural check functions 207 */ 208 209static void check_duplicate_node_names(struct check *c, struct dt_info *dti, 210 struct node *node) 211{ 212 struct node *child, *child2; 213 214 for_each_child(node, child) 215 for (child2 = child->next_sibling; 216 child2; 217 child2 = child2->next_sibling) 218 if (streq(child->name, child2->name)) 219 FAIL(c, dti, "Duplicate node name %s", 220 child->fullpath); 221} 222ERROR(duplicate_node_names, check_duplicate_node_names, NULL); 223 224static void check_duplicate_property_names(struct check *c, struct dt_info *dti, 225 struct node *node) 226{ 227 struct property *prop, *prop2; 228 229 for_each_property(node, prop) { 230 for (prop2 = prop->next; prop2; prop2 = prop2->next) { 231 if (prop2->deleted) 232 continue; 233 if (streq(prop->name, prop2->name)) 234 FAIL(c, dti, "Duplicate property name %s in %s", 235 prop->name, node->fullpath); 236 } 237 } 238} 239ERROR(duplicate_property_names, check_duplicate_property_names, NULL); 240 241#define LOWERCASE "abcdefghijklmnopqrstuvwxyz" 242#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 243#define DIGITS "0123456789" 244#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" 245#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" 246 247static void check_node_name_chars(struct check *c, struct dt_info *dti, 248 struct node *node) 249{ 250 int n = strspn(node->name, c->data); 251 252 if (n < strlen(node->name)) 253 FAIL(c, dti, "Bad character '%c' in node %s", 254 node->name[n], node->fullpath); 255} 256ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); 257 258static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, 259 struct node *node) 260{ 261 int n = strspn(node->name, c->data); 262 263 if (n < node->basenamelen) 264 FAIL(c, dti, "Character '%c' not recommended in node %s", 265 node->name[n], node->fullpath); 266} 267CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT); 268 269static void check_node_name_format(struct check *c, struct dt_info *dti, 270 struct node *node) 271{ 272 if (strchr(get_unitname(node), '@')) 273 FAIL(c, dti, "Node %s has multiple '@' characters in name", 274 node->fullpath); 275} 276ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); 277 278static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, 279 struct node *node) 280{ 281 const char *unitname = get_unitname(node); 282 struct property *prop = get_property(node, "reg"); 283 284 if (!prop) { 285 prop = get_property(node, "ranges"); 286 if (prop && !prop->val.len) 287 prop = NULL; 288 } 289 290 if (prop) { 291 if (!unitname[0]) 292 FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name", 293 node->fullpath); 294 } else { 295 if (unitname[0]) 296 FAIL(c, dti, "Node %s has a unit name, but no reg property", 297 node->fullpath); 298 } 299} 300WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); 301 302static void check_property_name_chars(struct check *c, struct dt_info *dti, 303 struct node *node) 304{ 305 struct property *prop; 306 307 for_each_property(node, prop) { 308 int n = strspn(prop->name, c->data); 309 310 if (n < strlen(prop->name)) 311 FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s", 312 prop->name[n], prop->name, node->fullpath); 313 } 314} 315ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); 316 317static void check_property_name_chars_strict(struct check *c, 318 struct dt_info *dti, 319 struct node *node) 320{ 321 struct property *prop; 322 323 for_each_property(node, prop) { 324 const char *name = prop->name; 325 int n = strspn(name, c->data); 326 327 if (n == strlen(prop->name)) 328 continue; 329 330 /* Certain names are whitelisted */ 331 if (streq(name, "device_type")) 332 continue; 333 334 /* 335 * # is only allowed at the beginning of property names not counting 336 * the vendor prefix. 337 */ 338 if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) { 339 name += n + 1; 340 n = strspn(name, c->data); 341 } 342 if (n < strlen(name)) 343 FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s", 344 name[n], prop->name, node->fullpath); 345 } 346} 347CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT); 348 349#define DESCLABEL_FMT "%s%s%s%s%s" 350#define DESCLABEL_ARGS(node,prop,mark) \ 351 ((mark) ? "value of " : ""), \ 352 ((prop) ? "'" : ""), \ 353 ((prop) ? (prop)->name : ""), \ 354 ((prop) ? "' in " : ""), (node)->fullpath 355 356static void check_duplicate_label(struct check *c, struct dt_info *dti, 357 const char *label, struct node *node, 358 struct property *prop, struct marker *mark) 359{ 360 struct node *dt = dti->dt; 361 struct node *othernode = NULL; 362 struct property *otherprop = NULL; 363 struct marker *othermark = NULL; 364 365 othernode = get_node_by_label(dt, label); 366 367 if (!othernode) 368 otherprop = get_property_by_label(dt, label, &othernode); 369 if (!othernode) 370 othermark = get_marker_label(dt, label, &othernode, 371 &otherprop); 372 373 if (!othernode) 374 return; 375 376 if ((othernode != node) || (otherprop != prop) || (othermark != mark)) 377 FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT 378 " and " DESCLABEL_FMT, 379 label, DESCLABEL_ARGS(node, prop, mark), 380 DESCLABEL_ARGS(othernode, otherprop, othermark)); 381} 382 383static void check_duplicate_label_node(struct check *c, struct dt_info *dti, 384 struct node *node) 385{ 386 struct label *l; 387 struct property *prop; 388 389 for_each_label(node->labels, l) 390 check_duplicate_label(c, dti, l->label, node, NULL, NULL); 391 392 for_each_property(node, prop) { 393 struct marker *m = prop->val.markers; 394 395 for_each_label(prop->labels, l) 396 check_duplicate_label(c, dti, l->label, node, prop, NULL); 397 398 for_each_marker_of_type(m, LABEL) 399 check_duplicate_label(c, dti, m->ref, node, prop, m); 400 } 401} 402ERROR(duplicate_label, check_duplicate_label_node, NULL); 403 404static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, 405 struct node *node, const char *propname) 406{ 407 struct node *root = dti->dt; 408 struct property *prop; 409 struct marker *m; 410 cell_t phandle; 411 412 prop = get_property(node, propname); 413 if (!prop) 414 return 0; 415 416 if (prop->val.len != sizeof(cell_t)) { 417 FAIL(c, dti, "%s has bad length (%d) %s property", 418 node->fullpath, prop->val.len, prop->name); 419 return 0; 420 } 421 422 m = prop->val.markers; 423 for_each_marker_of_type(m, REF_PHANDLE) { 424 assert(m->offset == 0); 425 if (node != get_node_by_ref(root, m->ref)) 426 /* "Set this node's phandle equal to some 427 * other node's phandle". That's nonsensical 428 * by construction. */ { 429 FAIL(c, dti, "%s in %s is a reference to another node", 430 prop->name, node->fullpath); 431 } 432 /* But setting this node's phandle equal to its own 433 * phandle is allowed - that means allocate a unique 434 * phandle for this node, even if it's not otherwise 435 * referenced. The value will be filled in later, so 436 * we treat it as having no phandle data for now. */ 437 return 0; 438 } 439 440 phandle = propval_cell(prop); 441 442 if ((phandle == 0) || (phandle == -1)) { 443 FAIL(c, dti, "%s has bad value (0x%x) in %s property", 444 node->fullpath, phandle, prop->name); 445 return 0; 446 } 447 448 return phandle; 449} 450 451static void check_explicit_phandles(struct check *c, struct dt_info *dti, 452 struct node *node) 453{ 454 struct node *root = dti->dt; 455 struct node *other; 456 cell_t phandle, linux_phandle; 457 458 /* Nothing should have assigned phandles yet */ 459 assert(!node->phandle); 460 461 phandle = check_phandle_prop(c, dti, node, "phandle"); 462 463 linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle"); 464 465 if (!phandle && !linux_phandle) 466 /* No valid phandles; nothing further to check */ 467 return; 468 469 if (linux_phandle && phandle && (phandle != linux_phandle)) 470 FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'" 471 " properties", node->fullpath); 472 473 if (linux_phandle && !phandle) 474 phandle = linux_phandle; 475 476 other = get_node_by_phandle(root, phandle); 477 if (other && (other != node)) { 478 FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)", 479 node->fullpath, phandle, other->fullpath); 480 return; 481 } 482 483 node->phandle = phandle; 484} 485ERROR(explicit_phandles, check_explicit_phandles, NULL); 486 487static void check_name_properties(struct check *c, struct dt_info *dti, 488 struct node *node) 489{ 490 struct property **pp, *prop = NULL; 491 492 for (pp = &node->proplist; *pp; pp = &((*pp)->next)) 493 if (streq((*pp)->name, "name")) { 494 prop = *pp; 495 break; 496 } 497 498 if (!prop) 499 return; /* No name property, that's fine */ 500 501 if ((prop->val.len != node->basenamelen+1) 502 || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { 503 FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead" 504 " of base node name)", node->fullpath, prop->val.val); 505 } else { 506 /* The name property is correct, and therefore redundant. 507 * Delete it */ 508 *pp = prop->next; 509 free(prop->name); 510 data_free(prop->val); 511 free(prop); 512 } 513} 514ERROR_IF_NOT_STRING(name_is_string, "name"); 515ERROR(name_properties, check_name_properties, NULL, &name_is_string); 516 517/* 518 * Reference fixup functions 519 */ 520 521static void fixup_phandle_references(struct check *c, struct dt_info *dti, 522 struct node *node) 523{ 524 struct node *dt = dti->dt; 525 struct property *prop; 526 527 for_each_property(node, prop) { 528 struct marker *m = prop->val.markers; 529 struct node *refnode; 530 cell_t phandle; 531 532 for_each_marker_of_type(m, REF_PHANDLE) { 533 assert(m->offset + sizeof(cell_t) <= prop->val.len); 534 535 refnode = get_node_by_ref(dt, m->ref); 536 if (! refnode) { 537 if (!(dti->dtsflags & DTSF_PLUGIN)) 538 FAIL(c, dti, "Reference to non-existent node or " 539 "label \"%s\"\n", m->ref); 540 else /* mark the entry as unresolved */ 541 *((cell_t *)(prop->val.val + m->offset)) = 542 cpu_to_fdt32(0xffffffff); 543 continue; 544 } 545 546 phandle = get_node_phandle(dt, refnode); 547 *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); 548 } 549 } 550} 551ERROR(phandle_references, fixup_phandle_references, NULL, 552 &duplicate_node_names, &explicit_phandles); 553 554static void fixup_path_references(struct check *c, struct dt_info *dti, 555 struct node *node) 556{ 557 struct node *dt = dti->dt; 558 struct property *prop; 559 560 for_each_property(node, prop) { 561 struct marker *m = prop->val.markers; 562 struct node *refnode; 563 char *path; 564 565 for_each_marker_of_type(m, REF_PATH) { 566 assert(m->offset <= prop->val.len); 567 568 refnode = get_node_by_ref(dt, m->ref); 569 if (!refnode) { 570 FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n", 571 m->ref); 572 continue; 573 } 574 575 path = refnode->fullpath; 576 prop->val = data_insert_at_marker(prop->val, m, path, 577 strlen(path) + 1); 578 } 579 } 580} 581ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); 582 583/* 584 * Semantic checks 585 */ 586WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); 587WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); 588WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); 589 590WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); 591WARNING_IF_NOT_STRING(model_is_string, "model"); 592WARNING_IF_NOT_STRING(status_is_string, "status"); 593 594static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, 595 struct node *node) 596{ 597 struct property *prop; 598 599 node->addr_cells = -1; 600 node->size_cells = -1; 601 602 prop = get_property(node, "#address-cells"); 603 if (prop) 604 node->addr_cells = propval_cell(prop); 605 606 prop = get_property(node, "#size-cells"); 607 if (prop) 608 node->size_cells = propval_cell(prop); 609} 610WARNING(addr_size_cells, fixup_addr_size_cells, NULL, 611 &address_cells_is_cell, &size_cells_is_cell); 612 613#define node_addr_cells(n) \ 614 (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) 615#define node_size_cells(n) \ 616 (((n)->size_cells == -1) ? 1 : (n)->size_cells) 617 618static void check_reg_format(struct check *c, struct dt_info *dti, 619 struct node *node) 620{ 621 struct property *prop; 622 int addr_cells, size_cells, entrylen; 623 624 prop = get_property(node, "reg"); 625 if (!prop) 626 return; /* No "reg", that's fine */ 627 628 if (!node->parent) { 629 FAIL(c, dti, "Root node has a \"reg\" property"); 630 return; 631 } 632 633 if (prop->val.len == 0) 634 FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath); 635 636 addr_cells = node_addr_cells(node->parent); 637 size_cells = node_size_cells(node->parent); 638 entrylen = (addr_cells + size_cells) * sizeof(cell_t); 639 640 if (!entrylen || (prop->val.len % entrylen) != 0) 641 FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) " 642 "(#address-cells == %d, #size-cells == %d)", 643 node->fullpath, prop->val.len, addr_cells, size_cells); 644} 645WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); 646 647static void check_ranges_format(struct check *c, struct dt_info *dti, 648 struct node *node) 649{ 650 struct property *prop; 651 int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; 652 653 prop = get_property(node, "ranges"); 654 if (!prop) 655 return; 656 657 if (!node->parent) { 658 FAIL(c, dti, "Root node has a \"ranges\" property"); 659 return; 660 } 661 662 p_addr_cells = node_addr_cells(node->parent); 663 p_size_cells = node_size_cells(node->parent); 664 c_addr_cells = node_addr_cells(node); 665 c_size_cells = node_size_cells(node); 666 entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t); 667 668 if (prop->val.len == 0) { 669 if (p_addr_cells != c_addr_cells) 670 FAIL(c, dti, "%s has empty \"ranges\" property but its " 671 "#address-cells (%d) differs from %s (%d)", 672 node->fullpath, c_addr_cells, node->parent->fullpath, 673 p_addr_cells); 674 if (p_size_cells != c_size_cells) 675 FAIL(c, dti, "%s has empty \"ranges\" property but its " 676 "#size-cells (%d) differs from %s (%d)", 677 node->fullpath, c_size_cells, node->parent->fullpath, 678 p_size_cells); 679 } else if ((prop->val.len % entrylen) != 0) { 680 FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) " 681 "(parent #address-cells == %d, child #address-cells == %d, " 682 "#size-cells == %d)", node->fullpath, prop->val.len, 683 p_addr_cells, c_addr_cells, c_size_cells); 684 } 685} 686WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); 687 688/* 689 * Style checks 690 */ 691static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, 692 struct node *node) 693{ 694 struct property *reg, *ranges; 695 696 if (!node->parent) 697 return; /* Ignore root node */ 698 699 reg = get_property(node, "reg"); 700 ranges = get_property(node, "ranges"); 701 702 if (!reg && !ranges) 703 return; 704 705 if (node->parent->addr_cells == -1) 706 FAIL(c, dti, "Relying on default #address-cells value for %s", 707 node->fullpath); 708 709 if (node->parent->size_cells == -1) 710 FAIL(c, dti, "Relying on default #size-cells value for %s", 711 node->fullpath); 712} 713WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, 714 &addr_size_cells); 715 716static void check_obsolete_chosen_interrupt_controller(struct check *c, 717 struct dt_info *dti, 718 struct node *node) 719{ 720 struct node *dt = dti->dt; 721 struct node *chosen; 722 struct property *prop; 723 724 if (node != dt) 725 return; 726 727 728 chosen = get_node_by_path(dt, "/chosen"); 729 if (!chosen) 730 return; 731 732 prop = get_property(chosen, "interrupt-controller"); 733 if (prop) 734 FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" " 735 "property"); 736} 737WARNING(obsolete_chosen_interrupt_controller, 738 check_obsolete_chosen_interrupt_controller, NULL); 739 740static struct check *check_table[] = { 741 &duplicate_node_names, &duplicate_property_names, 742 &node_name_chars, &node_name_format, &property_name_chars, 743 &name_is_string, &name_properties, 744 745 &duplicate_label, 746 747 &explicit_phandles, 748 &phandle_references, &path_references, 749 750 &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, 751 &device_type_is_string, &model_is_string, &status_is_string, 752 753 &property_name_chars_strict, 754 &node_name_chars_strict, 755 756 &addr_size_cells, ®_format, &ranges_format, 757 758 &unit_address_vs_reg, 759 760 &avoid_default_addr_size, 761 &obsolete_chosen_interrupt_controller, 762 763 &always_fail, 764}; 765 766static void enable_warning_error(struct check *c, bool warn, bool error) 767{ 768 int i; 769 770 /* Raising level, also raise it for prereqs */ 771 if ((warn && !c->warn) || (error && !c->error)) 772 for (i = 0; i < c->num_prereqs; i++) 773 enable_warning_error(c->prereq[i], warn, error); 774 775 c->warn = c->warn || warn; 776 c->error = c->error || error; 777} 778 779static void disable_warning_error(struct check *c, bool warn, bool error) 780{ 781 int i; 782 783 /* Lowering level, also lower it for things this is the prereq 784 * for */ 785 if ((warn && c->warn) || (error && c->error)) { 786 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 787 struct check *cc = check_table[i]; 788 int j; 789 790 for (j = 0; j < cc->num_prereqs; j++) 791 if (cc->prereq[j] == c) 792 disable_warning_error(cc, warn, error); 793 } 794 } 795 796 c->warn = c->warn && !warn; 797 c->error = c->error && !error; 798} 799 800void parse_checks_option(bool warn, bool error, const char *arg) 801{ 802 int i; 803 const char *name = arg; 804 bool enable = true; 805 806 if ((strncmp(arg, "no-", 3) == 0) 807 || (strncmp(arg, "no_", 3) == 0)) { 808 name = arg + 3; 809 enable = false; 810 } 811 812 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 813 struct check *c = check_table[i]; 814 815 if (streq(c->name, name)) { 816 if (enable) 817 enable_warning_error(c, warn, error); 818 else 819 disable_warning_error(c, warn, error); 820 return; 821 } 822 } 823 824 die("Unrecognized check name \"%s\"\n", name); 825} 826 827void process_checks(bool force, struct dt_info *dti) 828{ 829 int i; 830 int error = 0; 831 832 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 833 struct check *c = check_table[i]; 834 835 if (c->warn || c->error) 836 error = error || run_check(c, dti); 837 } 838 839 if (error) { 840 if (!force) { 841 fprintf(stderr, "ERROR: Input tree has errors, aborting " 842 "(use -f to force output)\n"); 843 exit(2); 844 } else if (quiet < 3) { 845 fprintf(stderr, "Warning: Input tree has errors, " 846 "output forced\n"); 847 } 848 } 849} 850