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