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