linux/scripts/dtc/checks.c
<<
>>
Prefs
   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
  75static inline void  PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti,
  76                                           const char *fmt, ...)
  77{
  78        va_list ap;
  79        va_start(ap, fmt);
  80
  81        if ((c->warn && (quiet < 1))
  82            || (c->error && (quiet < 2))) {
  83                fprintf(stderr, "%s: %s (%s): ",
  84                        strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
  85                        (c->error) ? "ERROR" : "Warning", c->name);
  86                vfprintf(stderr, fmt, ap);
  87                fprintf(stderr, "\n");
  88        }
  89        va_end(ap);
  90}
  91
  92#define FAIL(c, dti, ...)                                               \
  93        do {                                                            \
  94                TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__);  \
  95                (c)->status = FAILED;                                   \
  96                check_msg((c), dti, __VA_ARGS__);                       \
  97        } while (0)
  98
  99static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
 100{
 101        struct node *child;
 102
 103        TRACE(c, "%s", node->fullpath);
 104        if (c->fn)
 105                c->fn(c, dti, node);
 106
 107        for_each_child(node, child)
 108                check_nodes_props(c, dti, child);
 109}
 110
 111static bool run_check(struct check *c, struct dt_info *dti)
 112{
 113        struct node *dt = dti->dt;
 114        bool error = false;
 115        int i;
 116
 117        assert(!c->inprogress);
 118
 119        if (c->status != UNCHECKED)
 120                goto out;
 121
 122        c->inprogress = true;
 123
 124        for (i = 0; i < c->num_prereqs; i++) {
 125                struct check *prq = c->prereq[i];
 126                error = error || run_check(prq, dti);
 127                if (prq->status != PASSED) {
 128                        c->status = PREREQ;
 129                        check_msg(c, dti, "Failed prerequisite '%s'",
 130                                  c->prereq[i]->name);
 131                }
 132        }
 133
 134        if (c->status != UNCHECKED)
 135                goto out;
 136
 137        check_nodes_props(c, dti, dt);
 138
 139        if (c->status == UNCHECKED)
 140                c->status = PASSED;
 141
 142        TRACE(c, "\tCompleted, status %d", c->status);
 143
 144out:
 145        c->inprogress = false;
 146        if ((c->status != PASSED) && (c->error))
 147                error = true;
 148        return error;
 149}
 150
 151/*
 152 * Utility check functions
 153 */
 154
 155/* A check which always fails, for testing purposes only */
 156static inline void check_always_fail(struct check *c, struct dt_info *dti,
 157                                     struct node *node)
 158{
 159        FAIL(c, dti, "always_fail check");
 160}
 161CHECK(always_fail, check_always_fail, NULL);
 162
 163static void check_is_string(struct check *c, struct dt_info *dti,
 164                            struct node *node)
 165{
 166        struct property *prop;
 167        char *propname = c->data;
 168
 169        prop = get_property(node, propname);
 170        if (!prop)
 171                return; /* Not present, assumed ok */
 172
 173        if (!data_is_one_string(prop->val))
 174                FAIL(c, dti, "\"%s\" property in %s is not a string",
 175                     propname, node->fullpath);
 176}
 177#define WARNING_IF_NOT_STRING(nm, propname) \
 178        WARNING(nm, check_is_string, (propname))
 179#define ERROR_IF_NOT_STRING(nm, propname) \
 180        ERROR(nm, check_is_string, (propname))
 181
 182static void check_is_cell(struct check *c, struct dt_info *dti,
 183                          struct node *node)
 184{
 185        struct property *prop;
 186        char *propname = c->data;
 187
 188        prop = get_property(node, propname);
 189        if (!prop)
 190                return; /* Not present, assumed ok */
 191
 192        if (prop->val.len != sizeof(cell_t))
 193                FAIL(c, dti, "\"%s\" property in %s is not a single cell",
 194                     propname, node->fullpath);
 195}
 196#define WARNING_IF_NOT_CELL(nm, propname) \
 197        WARNING(nm, check_is_cell, (propname))
 198#define ERROR_IF_NOT_CELL(nm, propname) \
 199        ERROR(nm, check_is_cell, (propname))
 200
 201/*
 202 * Structural check functions
 203 */
 204
 205static void check_duplicate_node_names(struct check *c, struct dt_info *dti,
 206                                       struct node *node)
 207{
 208        struct node *child, *child2;
 209
 210        for_each_child(node, child)
 211                for (child2 = child->next_sibling;
 212                     child2;
 213                     child2 = child2->next_sibling)
 214                        if (streq(child->name, child2->name))
 215                                FAIL(c, dti, "Duplicate node name %s",
 216                                     child->fullpath);
 217}
 218ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
 219
 220static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
 221                                           struct node *node)
 222{
 223        struct property *prop, *prop2;
 224
 225        for_each_property(node, prop) {
 226                for (prop2 = prop->next; prop2; prop2 = prop2->next) {
 227                        if (prop2->deleted)
 228                                continue;
 229                        if (streq(prop->name, prop2->name))
 230                                FAIL(c, dti, "Duplicate property name %s in %s",
 231                                     prop->name, node->fullpath);
 232                }
 233        }
 234}
 235ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
 236
 237#define LOWERCASE       "abcdefghijklmnopqrstuvwxyz"
 238#define UPPERCASE       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 239#define DIGITS          "0123456789"
 240#define PROPNODECHARS   LOWERCASE UPPERCASE DIGITS ",._+*#?-"
 241#define PROPNODECHARSSTRICT     LOWERCASE UPPERCASE DIGITS ",-"
 242
 243static void check_node_name_chars(struct check *c, struct dt_info *dti,
 244                                  struct node *node)
 245{
 246        int n = strspn(node->name, c->data);
 247
 248        if (n < strlen(node->name))
 249                FAIL(c, dti, "Bad character '%c' in node %s",
 250                     node->name[n], node->fullpath);
 251}
 252ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
 253
 254static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
 255                                         struct node *node)
 256{
 257        int n = strspn(node->name, c->data);
 258
 259        if (n < node->basenamelen)
 260                FAIL(c, dti, "Character '%c' not recommended in node %s",
 261                     node->name[n], node->fullpath);
 262}
 263CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
 264
 265static void check_node_name_format(struct check *c, struct dt_info *dti,
 266                                   struct node *node)
 267{
 268        if (strchr(get_unitname(node), '@'))
 269                FAIL(c, dti, "Node %s has multiple '@' characters in name",
 270                     node->fullpath);
 271}
 272ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
 273
 274static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
 275                                      struct node *node)
 276{
 277        const char *unitname = get_unitname(node);
 278        struct property *prop = get_property(node, "reg");
 279
 280        if (!prop) {
 281                prop = get_property(node, "ranges");
 282                if (prop && !prop->val.len)
 283                        prop = NULL;
 284        }
 285
 286        if (prop) {
 287                if (!unitname[0])
 288                        FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name",
 289                            node->fullpath);
 290        } else {
 291                if (unitname[0])
 292                        FAIL(c, dti, "Node %s has a unit name, but no reg property",
 293                            node->fullpath);
 294        }
 295}
 296WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
 297
 298static void check_property_name_chars(struct check *c, struct dt_info *dti,
 299                                      struct node *node)
 300{
 301        struct property *prop;
 302
 303        for_each_property(node, prop) {
 304                int n = strspn(prop->name, c->data);
 305
 306                if (n < strlen(prop->name))
 307                        FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s",
 308                             prop->name[n], prop->name, node->fullpath);
 309        }
 310}
 311ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
 312
 313static void check_property_name_chars_strict(struct check *c,
 314                                             struct dt_info *dti,
 315                                             struct node *node)
 316{
 317        struct property *prop;
 318
 319        for_each_property(node, prop) {
 320                const char *name = prop->name;
 321                int n = strspn(name, c->data);
 322
 323                if (n == strlen(prop->name))
 324                        continue;
 325
 326                /* Certain names are whitelisted */
 327                if (streq(name, "device_type"))
 328                        continue;
 329
 330                /*
 331                 * # is only allowed at the beginning of property names not counting
 332                 * the vendor prefix.
 333                 */
 334                if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) {
 335                        name += n + 1;
 336                        n = strspn(name, c->data);
 337                }
 338                if (n < strlen(name))
 339                        FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s",
 340                             name[n], prop->name, node->fullpath);
 341        }
 342}
 343CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
 344
 345#define DESCLABEL_FMT   "%s%s%s%s%s"
 346#define DESCLABEL_ARGS(node,prop,mark)          \
 347        ((mark) ? "value of " : ""),            \
 348        ((prop) ? "'" : ""), \
 349        ((prop) ? (prop)->name : ""), \
 350        ((prop) ? "' in " : ""), (node)->fullpath
 351
 352static void check_duplicate_label(struct check *c, struct dt_info *dti,
 353                                  const char *label, struct node *node,
 354                                  struct property *prop, struct marker *mark)
 355{
 356        struct node *dt = dti->dt;
 357        struct node *othernode = NULL;
 358        struct property *otherprop = NULL;
 359        struct marker *othermark = NULL;
 360
 361        othernode = get_node_by_label(dt, label);
 362
 363        if (!othernode)
 364                otherprop = get_property_by_label(dt, label, &othernode);
 365        if (!othernode)
 366                othermark = get_marker_label(dt, label, &othernode,
 367                                               &otherprop);
 368
 369        if (!othernode)
 370                return;
 371
 372        if ((othernode != node) || (otherprop != prop) || (othermark != mark))
 373                FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT
 374                     " and " DESCLABEL_FMT,
 375                     label, DESCLABEL_ARGS(node, prop, mark),
 376                     DESCLABEL_ARGS(othernode, otherprop, othermark));
 377}
 378
 379static void check_duplicate_label_node(struct check *c, struct dt_info *dti,
 380                                       struct node *node)
 381{
 382        struct label *l;
 383        struct property *prop;
 384
 385        for_each_label(node->labels, l)
 386                check_duplicate_label(c, dti, l->label, node, NULL, NULL);
 387
 388        for_each_property(node, prop) {
 389                struct marker *m = prop->val.markers;
 390
 391                for_each_label(prop->labels, l)
 392                        check_duplicate_label(c, dti, l->label, node, prop, NULL);
 393
 394                for_each_marker_of_type(m, LABEL)
 395                        check_duplicate_label(c, dti, m->ref, node, prop, m);
 396        }
 397}
 398ERROR(duplicate_label, check_duplicate_label_node, NULL);
 399
 400static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
 401                                 struct node *node, const char *propname)
 402{
 403        struct node *root = dti->dt;
 404        struct property *prop;
 405        struct marker *m;
 406        cell_t phandle;
 407
 408        prop = get_property(node, propname);
 409        if (!prop)
 410                return 0;
 411
 412        if (prop->val.len != sizeof(cell_t)) {
 413                FAIL(c, dti, "%s has bad length (%d) %s property",
 414                     node->fullpath, prop->val.len, prop->name);
 415                return 0;
 416        }
 417
 418        m = prop->val.markers;
 419        for_each_marker_of_type(m, REF_PHANDLE) {
 420                assert(m->offset == 0);
 421                if (node != get_node_by_ref(root, m->ref))
 422                        /* "Set this node's phandle equal to some
 423                         * other node's phandle".  That's nonsensical
 424                         * by construction. */ {
 425                        FAIL(c, dti, "%s in %s is a reference to another node",
 426                             prop->name, node->fullpath);
 427                }
 428                /* But setting this node's phandle equal to its own
 429                 * phandle is allowed - that means allocate a unique
 430                 * phandle for this node, even if it's not otherwise
 431                 * referenced.  The value will be filled in later, so
 432                 * we treat it as having no phandle data for now. */
 433                return 0;
 434        }
 435
 436        phandle = propval_cell(prop);
 437
 438        if ((phandle == 0) || (phandle == -1)) {
 439                FAIL(c, dti, "%s has bad value (0x%x) in %s property",
 440                     node->fullpath, phandle, prop->name);
 441                return 0;
 442        }
 443
 444        return phandle;
 445}
 446
 447static void check_explicit_phandles(struct check *c, struct dt_info *dti,
 448                                    struct node *node)
 449{
 450        struct node *root = dti->dt;
 451        struct node *other;
 452        cell_t phandle, linux_phandle;
 453
 454        /* Nothing should have assigned phandles yet */
 455        assert(!node->phandle);
 456
 457        phandle = check_phandle_prop(c, dti, node, "phandle");
 458
 459        linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle");
 460
 461        if (!phandle && !linux_phandle)
 462                /* No valid phandles; nothing further to check */
 463                return;
 464
 465        if (linux_phandle && phandle && (phandle != linux_phandle))
 466                FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'"
 467                     " properties", node->fullpath);
 468
 469        if (linux_phandle && !phandle)
 470                phandle = linux_phandle;
 471
 472        other = get_node_by_phandle(root, phandle);
 473        if (other && (other != node)) {
 474                FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)",
 475                     node->fullpath, phandle, other->fullpath);
 476                return;
 477        }
 478
 479        node->phandle = phandle;
 480}
 481ERROR(explicit_phandles, check_explicit_phandles, NULL);
 482
 483static void check_name_properties(struct check *c, struct dt_info *dti,
 484                                  struct node *node)
 485{
 486        struct property **pp, *prop = NULL;
 487
 488        for (pp = &node->proplist; *pp; pp = &((*pp)->next))
 489                if (streq((*pp)->name, "name")) {
 490                        prop = *pp;
 491                        break;
 492                }
 493
 494        if (!prop)
 495                return; /* No name property, that's fine */
 496
 497        if ((prop->val.len != node->basenamelen+1)
 498            || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
 499                FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead"
 500                     " of base node name)", node->fullpath, prop->val.val);
 501        } else {
 502                /* The name property is correct, and therefore redundant.
 503                 * Delete it */
 504                *pp = prop->next;
 505                free(prop->name);
 506                data_free(prop->val);
 507                free(prop);
 508        }
 509}
 510ERROR_IF_NOT_STRING(name_is_string, "name");
 511ERROR(name_properties, check_name_properties, NULL, &name_is_string);
 512
 513/*
 514 * Reference fixup functions
 515 */
 516
 517static void fixup_phandle_references(struct check *c, struct dt_info *dti,
 518                                     struct node *node)
 519{
 520        struct node *dt = dti->dt;
 521        struct property *prop;
 522
 523        for_each_property(node, prop) {
 524                struct marker *m = prop->val.markers;
 525                struct node *refnode;
 526                cell_t phandle;
 527
 528                for_each_marker_of_type(m, REF_PHANDLE) {
 529                        assert(m->offset + sizeof(cell_t) <= prop->val.len);
 530
 531                        refnode = get_node_by_ref(dt, m->ref);
 532                        if (! refnode) {
 533                                if (!(dti->dtsflags & DTSF_PLUGIN))
 534                                        FAIL(c, dti, "Reference to non-existent node or "
 535                                                        "label \"%s\"\n", m->ref);
 536                                else /* mark the entry as unresolved */
 537                                        *((fdt32_t *)(prop->val.val + m->offset)) =
 538                                                cpu_to_fdt32(0xffffffff);
 539                                continue;
 540                        }
 541
 542                        phandle = get_node_phandle(dt, refnode);
 543                        *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
 544                }
 545        }
 546}
 547ERROR(phandle_references, fixup_phandle_references, NULL,
 548      &duplicate_node_names, &explicit_phandles);
 549
 550static void fixup_path_references(struct check *c, struct dt_info *dti,
 551                                  struct node *node)
 552{
 553        struct node *dt = dti->dt;
 554        struct property *prop;
 555
 556        for_each_property(node, prop) {
 557                struct marker *m = prop->val.markers;
 558                struct node *refnode;
 559                char *path;
 560
 561                for_each_marker_of_type(m, REF_PATH) {
 562                        assert(m->offset <= prop->val.len);
 563
 564                        refnode = get_node_by_ref(dt, m->ref);
 565                        if (!refnode) {
 566                                FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n",
 567                                     m->ref);
 568                                continue;
 569                        }
 570
 571                        path = refnode->fullpath;
 572                        prop->val = data_insert_at_marker(prop->val, m, path,
 573                                                          strlen(path) + 1);
 574                }
 575        }
 576}
 577ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
 578
 579/*
 580 * Semantic checks
 581 */
 582WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
 583WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
 584WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
 585
 586WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
 587WARNING_IF_NOT_STRING(model_is_string, "model");
 588WARNING_IF_NOT_STRING(status_is_string, "status");
 589
 590static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
 591                                  struct node *node)
 592{
 593        struct property *prop;
 594
 595        node->addr_cells = -1;
 596        node->size_cells = -1;
 597
 598        prop = get_property(node, "#address-cells");
 599        if (prop)
 600                node->addr_cells = propval_cell(prop);
 601
 602        prop = get_property(node, "#size-cells");
 603        if (prop)
 604                node->size_cells = propval_cell(prop);
 605}
 606WARNING(addr_size_cells, fixup_addr_size_cells, NULL,
 607        &address_cells_is_cell, &size_cells_is_cell);
 608
 609#define node_addr_cells(n) \
 610        (((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
 611#define node_size_cells(n) \
 612        (((n)->size_cells == -1) ? 1 : (n)->size_cells)
 613
 614static void check_reg_format(struct check *c, struct dt_info *dti,
 615                             struct node *node)
 616{
 617        struct property *prop;
 618        int addr_cells, size_cells, entrylen;
 619
 620        prop = get_property(node, "reg");
 621        if (!prop)
 622                return; /* No "reg", that's fine */
 623
 624        if (!node->parent) {
 625                FAIL(c, dti, "Root node has a \"reg\" property");
 626                return;
 627        }
 628
 629        if (prop->val.len == 0)
 630                FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath);
 631
 632        addr_cells = node_addr_cells(node->parent);
 633        size_cells = node_size_cells(node->parent);
 634        entrylen = (addr_cells + size_cells) * sizeof(cell_t);
 635
 636        if (!entrylen || (prop->val.len % entrylen) != 0)
 637                FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) "
 638                     "(#address-cells == %d, #size-cells == %d)",
 639                     node->fullpath, prop->val.len, addr_cells, size_cells);
 640}
 641WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
 642
 643static void check_ranges_format(struct check *c, struct dt_info *dti,
 644                                struct node *node)
 645{
 646        struct property *prop;
 647        int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
 648
 649        prop = get_property(node, "ranges");
 650        if (!prop)
 651                return;
 652
 653        if (!node->parent) {
 654                FAIL(c, dti, "Root node has a \"ranges\" property");
 655                return;
 656        }
 657
 658        p_addr_cells = node_addr_cells(node->parent);
 659        p_size_cells = node_size_cells(node->parent);
 660        c_addr_cells = node_addr_cells(node);
 661        c_size_cells = node_size_cells(node);
 662        entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
 663
 664        if (prop->val.len == 0) {
 665                if (p_addr_cells != c_addr_cells)
 666                        FAIL(c, dti, "%s has empty \"ranges\" property but its "
 667                             "#address-cells (%d) differs from %s (%d)",
 668                             node->fullpath, c_addr_cells, node->parent->fullpath,
 669                             p_addr_cells);
 670                if (p_size_cells != c_size_cells)
 671                        FAIL(c, dti, "%s has empty \"ranges\" property but its "
 672                             "#size-cells (%d) differs from %s (%d)",
 673                             node->fullpath, c_size_cells, node->parent->fullpath,
 674                             p_size_cells);
 675        } else if ((prop->val.len % entrylen) != 0) {
 676                FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) "
 677                     "(parent #address-cells == %d, child #address-cells == %d, "
 678                     "#size-cells == %d)", node->fullpath, prop->val.len,
 679                     p_addr_cells, c_addr_cells, c_size_cells);
 680        }
 681}
 682WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
 683
 684static const struct bus_type pci_bus = {
 685        .name = "PCI",
 686};
 687
 688static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node)
 689{
 690        struct property *prop;
 691        cell_t *cells;
 692
 693        prop = get_property(node, "device_type");
 694        if (!prop || !streq(prop->val.val, "pci"))
 695                return;
 696
 697        node->bus = &pci_bus;
 698
 699        if (!strneq(node->name, "pci", node->basenamelen) &&
 700            !strneq(node->name, "pcie", node->basenamelen))
 701                FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"",
 702                             node->fullpath);
 703
 704        prop = get_property(node, "ranges");
 705        if (!prop)
 706                FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
 707                             node->fullpath);
 708
 709        if (node_addr_cells(node) != 3)
 710                FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
 711                             node->fullpath);
 712        if (node_size_cells(node) != 2)
 713                FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
 714                             node->fullpath);
 715
 716        prop = get_property(node, "bus-range");
 717        if (!prop) {
 718                FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
 719                             node->fullpath);
 720                return;
 721        }
 722        if (prop->val.len != (sizeof(cell_t) * 2)) {
 723                FAIL(c, dti, "Node %s bus-range must be 2 cells",
 724                             node->fullpath);
 725                return;
 726        }
 727        cells = (cell_t *)prop->val.val;
 728        if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1]))
 729                FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell",
 730                             node->fullpath);
 731        if (fdt32_to_cpu(cells[1]) > 0xff)
 732                FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
 733                             node->fullpath);
 734}
 735WARNING(pci_bridge, check_pci_bridge, NULL,
 736        &device_type_is_string, &addr_size_cells);
 737
 738static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
 739{
 740        struct property *prop;
 741        unsigned int bus_num, min_bus, max_bus;
 742        cell_t *cells;
 743
 744        if (!node->parent || (node->parent->bus != &pci_bus))
 745                return;
 746
 747        prop = get_property(node, "reg");
 748        if (!prop)
 749                return;
 750
 751        cells = (cell_t *)prop->val.val;
 752        bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
 753
 754        prop = get_property(node->parent, "bus-range");
 755        if (!prop) {
 756                min_bus = max_bus = 0;
 757        } else {
 758                cells = (cell_t *)prop->val.val;
 759                min_bus = fdt32_to_cpu(cells[0]);
 760                max_bus = fdt32_to_cpu(cells[0]);
 761        }
 762        if ((bus_num < min_bus) || (bus_num > max_bus))
 763                FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)",
 764                     node->fullpath, bus_num, min_bus, max_bus);
 765}
 766WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, &reg_format, &pci_bridge);
 767
 768static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
 769{
 770        struct property *prop;
 771        const char *unitname = get_unitname(node);
 772        char unit_addr[5];
 773        unsigned int dev, func, reg;
 774        cell_t *cells;
 775
 776        if (!node->parent || (node->parent->bus != &pci_bus))
 777                return;
 778
 779        prop = get_property(node, "reg");
 780        if (!prop) {
 781                FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
 782                return;
 783        }
 784
 785        cells = (cell_t *)prop->val.val;
 786        if (cells[1] || cells[2])
 787                FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0",
 788                             node->fullpath);
 789
 790        reg = fdt32_to_cpu(cells[0]);
 791        dev = (reg & 0xf800) >> 11;
 792        func = (reg & 0x700) >> 8;
 793
 794        if (reg & 0xff000000)
 795                FAIL(c, dti, "Node %s PCI reg address is not configuration space",
 796                             node->fullpath);
 797        if (reg & 0x000000ff)
 798                FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
 799                             node->fullpath);
 800
 801        if (func == 0) {
 802                snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
 803                if (streq(unitname, unit_addr))
 804                        return;
 805        }
 806
 807        snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
 808        if (streq(unitname, unit_addr))
 809                return;
 810
 811        FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
 812             node->fullpath, unit_addr);
 813}
 814WARNING(pci_device_reg, check_pci_device_reg, NULL, &reg_format, &pci_bridge);
 815
 816static const struct bus_type simple_bus = {
 817        .name = "simple-bus",
 818};
 819
 820static bool node_is_compatible(struct node *node, const char *compat)
 821{
 822        struct property *prop;
 823        const char *str, *end;
 824
 825        prop = get_property(node, "compatible");
 826        if (!prop)
 827                return false;
 828
 829        for (str = prop->val.val, end = str + prop->val.len; str < end;
 830             str += strnlen(str, end - str) + 1) {
 831                if (strneq(str, compat, end - str))
 832                        return true;
 833        }
 834        return false;
 835}
 836
 837static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
 838{
 839        if (node_is_compatible(node, "simple-bus"))
 840                node->bus = &simple_bus;
 841}
 842WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
 843
 844static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
 845{
 846        struct property *prop;
 847        const char *unitname = get_unitname(node);
 848        char unit_addr[17];
 849        unsigned int size;
 850        uint64_t reg = 0;
 851        cell_t *cells = NULL;
 852
 853        if (!node->parent || (node->parent->bus != &simple_bus))
 854                return;
 855
 856        prop = get_property(node, "reg");
 857        if (prop)
 858                cells = (cell_t *)prop->val.val;
 859        else {
 860                prop = get_property(node, "ranges");
 861                if (prop && prop->val.len)
 862                        /* skip of child address */
 863                        cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
 864        }
 865
 866        if (!cells) {
 867                if (node->parent->parent && !(node->bus == &simple_bus))
 868                        FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
 869                return;
 870        }
 871
 872        size = node_addr_cells(node->parent);
 873        while (size--)
 874                reg = (reg << 32) | fdt32_to_cpu(*(cells++));
 875
 876        snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg);
 877        if (!streq(unitname, unit_addr))
 878                FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
 879                     node->fullpath, unit_addr);
 880}
 881WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
 882
 883static void check_unit_address_format(struct check *c, struct dt_info *dti,
 884                                      struct node *node)
 885{
 886        const char *unitname = get_unitname(node);
 887
 888        if (node->parent && node->parent->bus)
 889                return;
 890
 891        if (!unitname[0])
 892                return;
 893
 894        if (!strncmp(unitname, "0x", 2)) {
 895                FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
 896                    node->fullpath);
 897                /* skip over 0x for next test */
 898                unitname += 2;
 899        }
 900        if (unitname[0] == '0' && isxdigit(unitname[1]))
 901                FAIL(c, dti, "Node %s unit name should not have leading 0s",
 902                    node->fullpath);
 903}
 904WARNING(unit_address_format, check_unit_address_format, NULL,
 905        &node_name_format, &pci_bridge, &simple_bus_bridge);
 906
 907/*
 908 * Style checks
 909 */
 910static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
 911                                          struct node *node)
 912{
 913        struct property *reg, *ranges;
 914
 915        if (!node->parent)
 916                return; /* Ignore root node */
 917
 918        reg = get_property(node, "reg");
 919        ranges = get_property(node, "ranges");
 920
 921        if (!reg && !ranges)
 922                return;
 923
 924        if (node->parent->addr_cells == -1)
 925                FAIL(c, dti, "Relying on default #address-cells value for %s",
 926                     node->fullpath);
 927
 928        if (node->parent->size_cells == -1)
 929                FAIL(c, dti, "Relying on default #size-cells value for %s",
 930                     node->fullpath);
 931}
 932WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
 933        &addr_size_cells);
 934
 935static void check_obsolete_chosen_interrupt_controller(struct check *c,
 936                                                       struct dt_info *dti,
 937                                                       struct node *node)
 938{
 939        struct node *dt = dti->dt;
 940        struct node *chosen;
 941        struct property *prop;
 942
 943        if (node != dt)
 944                return;
 945
 946
 947        chosen = get_node_by_path(dt, "/chosen");
 948        if (!chosen)
 949                return;
 950
 951        prop = get_property(chosen, "interrupt-controller");
 952        if (prop)
 953                FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" "
 954                     "property");
 955}
 956WARNING(obsolete_chosen_interrupt_controller,
 957        check_obsolete_chosen_interrupt_controller, NULL);
 958
 959struct provider {
 960        const char *prop_name;
 961        const char *cell_name;
 962        bool optional;
 963};
 964
 965static void check_property_phandle_args(struct check *c,
 966                                          struct dt_info *dti,
 967                                          struct node *node,
 968                                          struct property *prop,
 969                                          const struct provider *provider)
 970{
 971        struct node *root = dti->dt;
 972        int cell, cellsize = 0;
 973
 974        if (prop->val.len % sizeof(cell_t)) {
 975                FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
 976                     prop->name, prop->val.len, sizeof(cell_t), node->fullpath);
 977                return;
 978        }
 979
 980        for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
 981                struct node *provider_node;
 982                struct property *cellprop;
 983                int phandle;
 984
 985                phandle = propval_cell_n(prop, cell);
 986                /*
 987                 * Some bindings use a cell value 0 or -1 to skip over optional
 988                 * entries when each index position has a specific definition.
 989                 */
 990                if (phandle == 0 || phandle == -1) {
 991                        /* Give up if this is an overlay with external references */
 992                        if (dti->dtsflags & DTSF_PLUGIN)
 993                                break;
 994
 995                        cellsize = 0;
 996                        continue;
 997                }
 998
 999                /* If we have markers, verify the current cell is a phandle */
1000                if (prop->val.markers) {
1001                        struct marker *m = prop->val.markers;
1002                        for_each_marker_of_type(m, REF_PHANDLE) {
1003                                if (m->offset == (cell * sizeof(cell_t)))
1004                                        break;
1005                        }
1006                        if (!m)
1007                                FAIL(c, dti, "Property '%s', cell %d is not a phandle reference in %s",
1008                                     prop->name, cell, node->fullpath);
1009                }
1010
1011                provider_node = get_node_by_phandle(root, phandle);
1012                if (!provider_node) {
1013                        FAIL(c, dti, "Could not get phandle node for %s:%s(cell %d)",
1014                             node->fullpath, prop->name, cell);
1015                        break;
1016                }
1017
1018                cellprop = get_property(provider_node, provider->cell_name);
1019                if (cellprop) {
1020                        cellsize = propval_cell(cellprop);
1021                } else if (provider->optional) {
1022                        cellsize = 0;
1023                } else {
1024                        FAIL(c, dti, "Missing property '%s' in node %s or bad phandle (referred from %s:%s[%d])",
1025                             provider->cell_name,
1026                             provider_node->fullpath,
1027                             node->fullpath, prop->name, cell);
1028                        break;
1029                }
1030
1031                if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
1032                        FAIL(c, dti, "%s property size (%d) too small for cell size %d in %s",
1033                             prop->name, prop->val.len, cellsize, node->fullpath);
1034                }
1035        }
1036}
1037
1038static void check_provider_cells_property(struct check *c,
1039                                          struct dt_info *dti,
1040                                          struct node *node)
1041{
1042        struct provider *provider = c->data;
1043        struct property *prop;
1044
1045        prop = get_property(node, provider->prop_name);
1046        if (!prop)
1047                return;
1048
1049        check_property_phandle_args(c, dti, node, prop, provider);
1050}
1051#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
1052        static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
1053        WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
1054
1055WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
1056WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
1057WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells");
1058WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells");
1059WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells");
1060WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells");
1061WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells");
1062WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells");
1063WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true);
1064WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells");
1065WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells");
1066WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells");
1067WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells");
1068WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells");
1069WARNING_PROPERTY_PHANDLE_CELLS(sound_dais, "sound-dais", "#sound-dai-cells");
1070WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells");
1071
1072static bool prop_is_gpio(struct property *prop)
1073{
1074        char *str;
1075
1076        /*
1077         * *-gpios and *-gpio can appear in property names,
1078         * so skip over any false matches (only one known ATM)
1079         */
1080        if (strstr(prop->name, "nr-gpio"))
1081                return false;
1082
1083        str = strrchr(prop->name, '-');
1084        if (str)
1085                str++;
1086        else
1087                str = prop->name;
1088        if (!(streq(str, "gpios") || streq(str, "gpio")))
1089                return false;
1090
1091        return true;
1092}
1093
1094static void check_gpios_property(struct check *c,
1095                                          struct dt_info *dti,
1096                                          struct node *node)
1097{
1098        struct property *prop;
1099
1100        /* Skip GPIO hog nodes which have 'gpios' property */
1101        if (get_property(node, "gpio-hog"))
1102                return;
1103
1104        for_each_property(node, prop) {
1105                struct provider provider;
1106
1107                if (!prop_is_gpio(prop))
1108                        continue;
1109
1110                provider.prop_name = prop->name;
1111                provider.cell_name = "#gpio-cells";
1112                provider.optional = false;
1113                check_property_phandle_args(c, dti, node, prop, &provider);
1114        }
1115
1116}
1117WARNING(gpios_property, check_gpios_property, NULL, &phandle_references);
1118
1119static void check_deprecated_gpio_property(struct check *c,
1120                                           struct dt_info *dti,
1121                                           struct node *node)
1122{
1123        struct property *prop;
1124
1125        for_each_property(node, prop) {
1126                char *str;
1127
1128                if (!prop_is_gpio(prop))
1129                        continue;
1130
1131                str = strstr(prop->name, "gpio");
1132                if (!streq(str, "gpio"))
1133                        continue;
1134
1135                FAIL(c, dti, "'[*-]gpio' is deprecated, use '[*-]gpios' instead for %s:%s",
1136                     node->fullpath, prop->name);
1137        }
1138
1139}
1140CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL);
1141
1142static bool node_is_interrupt_provider(struct node *node)
1143{
1144        struct property *prop;
1145
1146        prop = get_property(node, "interrupt-controller");
1147        if (prop)
1148                return true;
1149
1150        prop = get_property(node, "interrupt-map");
1151        if (prop)
1152                return true;
1153
1154        return false;
1155}
1156static void check_interrupts_property(struct check *c,
1157                                      struct dt_info *dti,
1158                                      struct node *node)
1159{
1160        struct node *root = dti->dt;
1161        struct node *irq_node = NULL, *parent = node;
1162        struct property *irq_prop, *prop = NULL;
1163        int irq_cells, phandle;
1164
1165        irq_prop = get_property(node, "interrupts");
1166        if (!irq_prop)
1167                return;
1168
1169        if (irq_prop->val.len % sizeof(cell_t))
1170                FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
1171                     irq_prop->name, irq_prop->val.len, sizeof(cell_t),
1172                     node->fullpath);
1173
1174        while (parent && !prop) {
1175                if (parent != node && node_is_interrupt_provider(parent)) {
1176                        irq_node = parent;
1177                        break;
1178                }
1179
1180                prop = get_property(parent, "interrupt-parent");
1181                if (prop) {
1182                        phandle = propval_cell(prop);
1183                        /* Give up if this is an overlay with external references */
1184                        if ((phandle == 0 || phandle == -1) &&
1185                            (dti->dtsflags & DTSF_PLUGIN))
1186                                        return;
1187
1188                        irq_node = get_node_by_phandle(root, phandle);
1189                        if (!irq_node) {
1190                                FAIL(c, dti, "Bad interrupt-parent phandle for %s",
1191                                     node->fullpath);
1192                                return;
1193                        }
1194                        if (!node_is_interrupt_provider(irq_node))
1195                                FAIL(c, dti,
1196                                     "Missing interrupt-controller or interrupt-map property in %s",
1197                                     irq_node->fullpath);
1198
1199                        break;
1200                }
1201
1202                parent = parent->parent;
1203        }
1204
1205        if (!irq_node) {
1206                FAIL(c, dti, "Missing interrupt-parent for %s", node->fullpath);
1207                return;
1208        }
1209
1210        prop = get_property(irq_node, "#interrupt-cells");
1211        if (!prop) {
1212                FAIL(c, dti, "Missing #interrupt-cells in interrupt-parent %s",
1213                     irq_node->fullpath);
1214                return;
1215        }
1216
1217        irq_cells = propval_cell(prop);
1218        if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
1219                FAIL(c, dti,
1220                     "interrupts size is (%d), expected multiple of %d in %s",
1221                     irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)),
1222                     node->fullpath);
1223        }
1224}
1225WARNING(interrupts_property, check_interrupts_property, &phandle_references);
1226
1227static struct check *check_table[] = {
1228        &duplicate_node_names, &duplicate_property_names,
1229        &node_name_chars, &node_name_format, &property_name_chars,
1230        &name_is_string, &name_properties,
1231
1232        &duplicate_label,
1233
1234        &explicit_phandles,
1235        &phandle_references, &path_references,
1236
1237        &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
1238        &device_type_is_string, &model_is_string, &status_is_string,
1239
1240        &property_name_chars_strict,
1241        &node_name_chars_strict,
1242
1243        &addr_size_cells, &reg_format, &ranges_format,
1244
1245        &unit_address_vs_reg,
1246        &unit_address_format,
1247
1248        &pci_bridge,
1249        &pci_device_reg,
1250        &pci_device_bus_num,
1251
1252        &simple_bus_bridge,
1253        &simple_bus_reg,
1254
1255        &avoid_default_addr_size,
1256        &obsolete_chosen_interrupt_controller,
1257
1258        &clocks_property,
1259        &cooling_device_property,
1260        &dmas_property,
1261        &hwlocks_property,
1262        &interrupts_extended_property,
1263        &io_channels_property,
1264        &iommus_property,
1265        &mboxes_property,
1266        &msi_parent_property,
1267        &mux_controls_property,
1268        &phys_property,
1269        &power_domains_property,
1270        &pwms_property,
1271        &resets_property,
1272        &sound_dais_property,
1273        &thermal_sensors_property,
1274
1275        &deprecated_gpio_property,
1276        &gpios_property,
1277        &interrupts_property,
1278
1279        &always_fail,
1280};
1281
1282static void enable_warning_error(struct check *c, bool warn, bool error)
1283{
1284        int i;
1285
1286        /* Raising level, also raise it for prereqs */
1287        if ((warn && !c->warn) || (error && !c->error))
1288                for (i = 0; i < c->num_prereqs; i++)
1289                        enable_warning_error(c->prereq[i], warn, error);
1290
1291        c->warn = c->warn || warn;
1292        c->error = c->error || error;
1293}
1294
1295static void disable_warning_error(struct check *c, bool warn, bool error)
1296{
1297        int i;
1298
1299        /* Lowering level, also lower it for things this is the prereq
1300         * for */
1301        if ((warn && c->warn) || (error && c->error)) {
1302                for (i = 0; i < ARRAY_SIZE(check_table); i++) {
1303                        struct check *cc = check_table[i];
1304                        int j;
1305
1306                        for (j = 0; j < cc->num_prereqs; j++)
1307                                if (cc->prereq[j] == c)
1308                                        disable_warning_error(cc, warn, error);
1309                }
1310        }
1311
1312        c->warn = c->warn && !warn;
1313        c->error = c->error && !error;
1314}
1315
1316void parse_checks_option(bool warn, bool error, const char *arg)
1317{
1318        int i;
1319        const char *name = arg;
1320        bool enable = true;
1321
1322        if ((strncmp(arg, "no-", 3) == 0)
1323            || (strncmp(arg, "no_", 3) == 0)) {
1324                name = arg + 3;
1325                enable = false;
1326        }
1327
1328        for (i = 0; i < ARRAY_SIZE(check_table); i++) {
1329                struct check *c = check_table[i];
1330
1331                if (streq(c->name, name)) {
1332                        if (enable)
1333                                enable_warning_error(c, warn, error);
1334                        else
1335                                disable_warning_error(c, warn, error);
1336                        return;
1337                }
1338        }
1339
1340        die("Unrecognized check name \"%s\"\n", name);
1341}
1342
1343void process_checks(bool force, struct dt_info *dti)
1344{
1345        int i;
1346        int error = 0;
1347
1348        for (i = 0; i < ARRAY_SIZE(check_table); i++) {
1349                struct check *c = check_table[i];
1350
1351                if (c->warn || c->error)
1352                        error = error || run_check(c, dti);
1353        }
1354
1355        if (error) {
1356                if (!force) {
1357                        fprintf(stderr, "ERROR: Input tree has errors, aborting "
1358                                "(use -f to force output)\n");
1359                        exit(2);
1360                } else if (quiet < 3) {
1361                        fprintf(stderr, "Warning: Input tree has errors, "
1362                                "output forced\n");
1363                }
1364        }
1365}
1366