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 75e23ffda2STom 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 */ 537e23ffda2STom 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); 543e23ffda2STom 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 684*d7857e40STom Rini static const struct bus_type pci_bus = { 685*d7857e40STom Rini .name = "PCI", 686*d7857e40STom Rini }; 687*d7857e40STom Rini 688*d7857e40STom Rini static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node) 689*d7857e40STom Rini { 690*d7857e40STom Rini struct property *prop; 691*d7857e40STom Rini cell_t *cells; 692*d7857e40STom Rini 693*d7857e40STom Rini prop = get_property(node, "device_type"); 694*d7857e40STom Rini if (!prop || !streq(prop->val.val, "pci")) 695*d7857e40STom Rini return; 696*d7857e40STom Rini 697*d7857e40STom Rini node->bus = &pci_bus; 698*d7857e40STom Rini 699*d7857e40STom Rini if (!strneq(node->name, "pci", node->basenamelen) && 700*d7857e40STom Rini !strneq(node->name, "pcie", node->basenamelen)) 701*d7857e40STom Rini FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"", 702*d7857e40STom Rini node->fullpath); 703*d7857e40STom Rini 704*d7857e40STom Rini prop = get_property(node, "ranges"); 705*d7857e40STom Rini if (!prop) 706*d7857e40STom Rini FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)", 707*d7857e40STom Rini node->fullpath); 708*d7857e40STom Rini 709*d7857e40STom Rini if (node_addr_cells(node) != 3) 710*d7857e40STom Rini FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge", 711*d7857e40STom Rini node->fullpath); 712*d7857e40STom Rini if (node_size_cells(node) != 2) 713*d7857e40STom Rini FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge", 714*d7857e40STom Rini node->fullpath); 715*d7857e40STom Rini 716*d7857e40STom Rini prop = get_property(node, "bus-range"); 717*d7857e40STom Rini if (!prop) { 718*d7857e40STom Rini FAIL(c, dti, "Node %s missing bus-range for PCI bridge", 719*d7857e40STom Rini node->fullpath); 720*d7857e40STom Rini return; 721*d7857e40STom Rini } 722*d7857e40STom Rini if (prop->val.len != (sizeof(cell_t) * 2)) { 723*d7857e40STom Rini FAIL(c, dti, "Node %s bus-range must be 2 cells", 724*d7857e40STom Rini node->fullpath); 725*d7857e40STom Rini return; 726*d7857e40STom Rini } 727*d7857e40STom Rini cells = (cell_t *)prop->val.val; 728*d7857e40STom Rini if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1])) 729*d7857e40STom Rini FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell", 730*d7857e40STom Rini node->fullpath); 731*d7857e40STom Rini if (fdt32_to_cpu(cells[1]) > 0xff) 732*d7857e40STom Rini FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256", 733*d7857e40STom Rini node->fullpath); 734*d7857e40STom Rini } 735*d7857e40STom Rini WARNING(pci_bridge, check_pci_bridge, NULL, 736*d7857e40STom Rini &device_type_is_string, &addr_size_cells); 737*d7857e40STom Rini 738*d7857e40STom Rini static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node) 739*d7857e40STom Rini { 740*d7857e40STom Rini struct property *prop; 741*d7857e40STom Rini unsigned int bus_num, min_bus, max_bus; 742*d7857e40STom Rini cell_t *cells; 743*d7857e40STom Rini 744*d7857e40STom Rini if (!node->parent || (node->parent->bus != &pci_bus)) 745*d7857e40STom Rini return; 746*d7857e40STom Rini 747*d7857e40STom Rini prop = get_property(node, "reg"); 748*d7857e40STom Rini if (!prop) 749*d7857e40STom Rini return; 750*d7857e40STom Rini 751*d7857e40STom Rini cells = (cell_t *)prop->val.val; 752*d7857e40STom Rini bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16; 753*d7857e40STom Rini 754*d7857e40STom Rini prop = get_property(node->parent, "bus-range"); 755*d7857e40STom Rini if (!prop) { 756*d7857e40STom Rini min_bus = max_bus = 0; 757*d7857e40STom Rini } else { 758*d7857e40STom Rini cells = (cell_t *)prop->val.val; 759*d7857e40STom Rini min_bus = fdt32_to_cpu(cells[0]); 760*d7857e40STom Rini max_bus = fdt32_to_cpu(cells[0]); 761*d7857e40STom Rini } 762*d7857e40STom Rini if ((bus_num < min_bus) || (bus_num > max_bus)) 763*d7857e40STom Rini FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)", 764*d7857e40STom Rini node->fullpath, bus_num, min_bus, max_bus); 765*d7857e40STom Rini } 766*d7857e40STom Rini WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge); 767*d7857e40STom Rini 768*d7857e40STom Rini static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node) 769*d7857e40STom Rini { 770*d7857e40STom Rini struct property *prop; 771*d7857e40STom Rini const char *unitname = get_unitname(node); 772*d7857e40STom Rini char unit_addr[5]; 773*d7857e40STom Rini unsigned int dev, func, reg; 774*d7857e40STom Rini cell_t *cells; 775*d7857e40STom Rini 776*d7857e40STom Rini if (!node->parent || (node->parent->bus != &pci_bus)) 777*d7857e40STom Rini return; 778*d7857e40STom Rini 779*d7857e40STom Rini prop = get_property(node, "reg"); 780*d7857e40STom Rini if (!prop) { 781*d7857e40STom Rini FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath); 782*d7857e40STom Rini return; 783*d7857e40STom Rini } 784*d7857e40STom Rini 785*d7857e40STom Rini cells = (cell_t *)prop->val.val; 786*d7857e40STom Rini if (cells[1] || cells[2]) 787*d7857e40STom Rini FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0", 788*d7857e40STom Rini node->fullpath); 789*d7857e40STom Rini 790*d7857e40STom Rini reg = fdt32_to_cpu(cells[0]); 791*d7857e40STom Rini dev = (reg & 0xf800) >> 11; 792*d7857e40STom Rini func = (reg & 0x700) >> 8; 793*d7857e40STom Rini 794*d7857e40STom Rini if (reg & 0xff000000) 795*d7857e40STom Rini FAIL(c, dti, "Node %s PCI reg address is not configuration space", 796*d7857e40STom Rini node->fullpath); 797*d7857e40STom Rini if (reg & 0x000000ff) 798*d7857e40STom Rini FAIL(c, dti, "Node %s PCI reg config space address register number must be 0", 799*d7857e40STom Rini node->fullpath); 800*d7857e40STom Rini 801*d7857e40STom Rini if (func == 0) { 802*d7857e40STom Rini snprintf(unit_addr, sizeof(unit_addr), "%x", dev); 803*d7857e40STom Rini if (streq(unitname, unit_addr)) 804*d7857e40STom Rini return; 805*d7857e40STom Rini } 806*d7857e40STom Rini 807*d7857e40STom Rini snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func); 808*d7857e40STom Rini if (streq(unitname, unit_addr)) 809*d7857e40STom Rini return; 810*d7857e40STom Rini 811*d7857e40STom Rini FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"", 812*d7857e40STom Rini node->fullpath, unit_addr); 813*d7857e40STom Rini } 814*d7857e40STom Rini WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format, &pci_bridge); 815*d7857e40STom Rini 816*d7857e40STom Rini static const struct bus_type simple_bus = { 817*d7857e40STom Rini .name = "simple-bus", 818*d7857e40STom Rini }; 819*d7857e40STom Rini 820*d7857e40STom Rini static bool node_is_compatible(struct node *node, const char *compat) 821*d7857e40STom Rini { 822*d7857e40STom Rini struct property *prop; 823*d7857e40STom Rini const char *str, *end; 824*d7857e40STom Rini 825*d7857e40STom Rini prop = get_property(node, "compatible"); 826*d7857e40STom Rini if (!prop) 827*d7857e40STom Rini return false; 828*d7857e40STom Rini 829*d7857e40STom Rini for (str = prop->val.val, end = str + prop->val.len; str < end; 830*d7857e40STom Rini str += strnlen(str, end - str) + 1) { 831*d7857e40STom Rini if (strneq(str, compat, end - str)) 832*d7857e40STom Rini return true; 833*d7857e40STom Rini } 834*d7857e40STom Rini return false; 835*d7857e40STom Rini } 836*d7857e40STom Rini 837*d7857e40STom Rini static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) 838*d7857e40STom Rini { 839*d7857e40STom Rini if (node_is_compatible(node, "simple-bus")) 840*d7857e40STom Rini node->bus = &simple_bus; 841*d7857e40STom Rini } 842*d7857e40STom Rini WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells); 843*d7857e40STom Rini 844*d7857e40STom Rini static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node) 845*d7857e40STom Rini { 846*d7857e40STom Rini struct property *prop; 847*d7857e40STom Rini const char *unitname = get_unitname(node); 848*d7857e40STom Rini char unit_addr[17]; 849*d7857e40STom Rini unsigned int size; 850*d7857e40STom Rini uint64_t reg = 0; 851*d7857e40STom Rini cell_t *cells = NULL; 852*d7857e40STom Rini 853*d7857e40STom Rini if (!node->parent || (node->parent->bus != &simple_bus)) 854*d7857e40STom Rini return; 855*d7857e40STom Rini 856*d7857e40STom Rini prop = get_property(node, "reg"); 857*d7857e40STom Rini if (prop) 858*d7857e40STom Rini cells = (cell_t *)prop->val.val; 859*d7857e40STom Rini else { 860*d7857e40STom Rini prop = get_property(node, "ranges"); 861*d7857e40STom Rini if (prop && prop->val.len) 862*d7857e40STom Rini /* skip of child address */ 863*d7857e40STom Rini cells = ((cell_t *)prop->val.val) + node_addr_cells(node); 864*d7857e40STom Rini } 865*d7857e40STom Rini 866*d7857e40STom Rini if (!cells) { 867*d7857e40STom Rini if (node->parent->parent && !(node->bus == &simple_bus)) 868*d7857e40STom Rini FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath); 869*d7857e40STom Rini return; 870*d7857e40STom Rini } 871*d7857e40STom Rini 872*d7857e40STom Rini size = node_addr_cells(node->parent); 873*d7857e40STom Rini while (size--) 874*d7857e40STom Rini reg = (reg << 32) | fdt32_to_cpu(*(cells++)); 875*d7857e40STom Rini 876*d7857e40STom Rini snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg); 877*d7857e40STom Rini if (!streq(unitname, unit_addr)) 878*d7857e40STom Rini FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"", 879*d7857e40STom Rini node->fullpath, unit_addr); 880*d7857e40STom Rini } 881*d7857e40STom Rini WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); 882*d7857e40STom Rini 883*d7857e40STom Rini static void check_unit_address_format(struct check *c, struct dt_info *dti, 884*d7857e40STom Rini struct node *node) 885*d7857e40STom Rini { 886*d7857e40STom Rini const char *unitname = get_unitname(node); 887*d7857e40STom Rini 888*d7857e40STom Rini if (node->parent && node->parent->bus) 889*d7857e40STom Rini return; 890*d7857e40STom Rini 891*d7857e40STom Rini if (!unitname[0]) 892*d7857e40STom Rini return; 893*d7857e40STom Rini 894*d7857e40STom Rini if (!strncmp(unitname, "0x", 2)) { 895*d7857e40STom Rini FAIL(c, dti, "Node %s unit name should not have leading \"0x\"", 896*d7857e40STom Rini node->fullpath); 897*d7857e40STom Rini /* skip over 0x for next test */ 898*d7857e40STom Rini unitname += 2; 899*d7857e40STom Rini } 900*d7857e40STom Rini if (unitname[0] == '0' && isxdigit(unitname[1])) 901*d7857e40STom Rini FAIL(c, dti, "Node %s unit name should not have leading 0s", 902*d7857e40STom Rini node->fullpath); 903*d7857e40STom Rini } 904*d7857e40STom Rini WARNING(unit_address_format, check_unit_address_format, NULL, 905*d7857e40STom Rini &node_name_format, &pci_bridge, &simple_bus_bridge); 906*d7857e40STom Rini 907d18719a4STom Rini /* 908d18719a4STom Rini * Style checks 909d18719a4STom Rini */ 910d18719a4STom Rini static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, 911d18719a4STom Rini struct node *node) 912d18719a4STom Rini { 913d18719a4STom Rini struct property *reg, *ranges; 914d18719a4STom Rini 915d18719a4STom Rini if (!node->parent) 916d18719a4STom Rini return; /* Ignore root node */ 917d18719a4STom Rini 918d18719a4STom Rini reg = get_property(node, "reg"); 919d18719a4STom Rini ranges = get_property(node, "ranges"); 920d18719a4STom Rini 921d18719a4STom Rini if (!reg && !ranges) 922d18719a4STom Rini return; 923d18719a4STom Rini 924d18719a4STom Rini if (node->parent->addr_cells == -1) 925d18719a4STom Rini FAIL(c, dti, "Relying on default #address-cells value for %s", 926d18719a4STom Rini node->fullpath); 927d18719a4STom Rini 928d18719a4STom Rini if (node->parent->size_cells == -1) 929d18719a4STom Rini FAIL(c, dti, "Relying on default #size-cells value for %s", 930d18719a4STom Rini node->fullpath); 931d18719a4STom Rini } 932d18719a4STom Rini WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, 933d18719a4STom Rini &addr_size_cells); 934d18719a4STom Rini 935d18719a4STom Rini static void check_obsolete_chosen_interrupt_controller(struct check *c, 936d18719a4STom Rini struct dt_info *dti, 937d18719a4STom Rini struct node *node) 938d18719a4STom Rini { 939d18719a4STom Rini struct node *dt = dti->dt; 940d18719a4STom Rini struct node *chosen; 941d18719a4STom Rini struct property *prop; 942d18719a4STom Rini 943d18719a4STom Rini if (node != dt) 944d18719a4STom Rini return; 945d18719a4STom Rini 946d18719a4STom Rini 947d18719a4STom Rini chosen = get_node_by_path(dt, "/chosen"); 948d18719a4STom Rini if (!chosen) 949d18719a4STom Rini return; 950d18719a4STom Rini 951d18719a4STom Rini prop = get_property(chosen, "interrupt-controller"); 952d18719a4STom Rini if (prop) 953d18719a4STom Rini FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" " 954d18719a4STom Rini "property"); 955d18719a4STom Rini } 956d18719a4STom Rini WARNING(obsolete_chosen_interrupt_controller, 957d18719a4STom Rini check_obsolete_chosen_interrupt_controller, NULL); 958d18719a4STom Rini 959d18719a4STom Rini static struct check *check_table[] = { 960d18719a4STom Rini &duplicate_node_names, &duplicate_property_names, 961d18719a4STom Rini &node_name_chars, &node_name_format, &property_name_chars, 962d18719a4STom Rini &name_is_string, &name_properties, 963d18719a4STom Rini 964d18719a4STom Rini &duplicate_label, 965d18719a4STom Rini 966d18719a4STom Rini &explicit_phandles, 967d18719a4STom Rini &phandle_references, &path_references, 968d18719a4STom Rini 969d18719a4STom Rini &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, 970d18719a4STom Rini &device_type_is_string, &model_is_string, &status_is_string, 971d18719a4STom Rini 972d18719a4STom Rini &property_name_chars_strict, 973d18719a4STom Rini &node_name_chars_strict, 974d18719a4STom Rini 975d18719a4STom Rini &addr_size_cells, ®_format, &ranges_format, 976d18719a4STom Rini 977d18719a4STom Rini &unit_address_vs_reg, 978*d7857e40STom Rini &unit_address_format, 979*d7857e40STom Rini 980*d7857e40STom Rini &pci_bridge, 981*d7857e40STom Rini &pci_device_reg, 982*d7857e40STom Rini &pci_device_bus_num, 983*d7857e40STom Rini 984*d7857e40STom Rini &simple_bus_bridge, 985*d7857e40STom Rini &simple_bus_reg, 986d18719a4STom Rini 987d18719a4STom Rini &avoid_default_addr_size, 988d18719a4STom Rini &obsolete_chosen_interrupt_controller, 989d18719a4STom Rini 990d18719a4STom Rini &always_fail, 991d18719a4STom Rini }; 992d18719a4STom Rini 993d18719a4STom Rini static void enable_warning_error(struct check *c, bool warn, bool error) 994d18719a4STom Rini { 995d18719a4STom Rini int i; 996d18719a4STom Rini 997d18719a4STom Rini /* Raising level, also raise it for prereqs */ 998d18719a4STom Rini if ((warn && !c->warn) || (error && !c->error)) 999d18719a4STom Rini for (i = 0; i < c->num_prereqs; i++) 1000d18719a4STom Rini enable_warning_error(c->prereq[i], warn, error); 1001d18719a4STom Rini 1002d18719a4STom Rini c->warn = c->warn || warn; 1003d18719a4STom Rini c->error = c->error || error; 1004d18719a4STom Rini } 1005d18719a4STom Rini 1006d18719a4STom Rini static void disable_warning_error(struct check *c, bool warn, bool error) 1007d18719a4STom Rini { 1008d18719a4STom Rini int i; 1009d18719a4STom Rini 1010d18719a4STom Rini /* Lowering level, also lower it for things this is the prereq 1011d18719a4STom Rini * for */ 1012d18719a4STom Rini if ((warn && c->warn) || (error && c->error)) { 1013d18719a4STom Rini for (i = 0; i < ARRAY_SIZE(check_table); i++) { 1014d18719a4STom Rini struct check *cc = check_table[i]; 1015d18719a4STom Rini int j; 1016d18719a4STom Rini 1017d18719a4STom Rini for (j = 0; j < cc->num_prereqs; j++) 1018d18719a4STom Rini if (cc->prereq[j] == c) 1019d18719a4STom Rini disable_warning_error(cc, warn, error); 1020d18719a4STom Rini } 1021d18719a4STom Rini } 1022d18719a4STom Rini 1023d18719a4STom Rini c->warn = c->warn && !warn; 1024d18719a4STom Rini c->error = c->error && !error; 1025d18719a4STom Rini } 1026d18719a4STom Rini 1027d18719a4STom Rini void parse_checks_option(bool warn, bool error, const char *arg) 1028d18719a4STom Rini { 1029d18719a4STom Rini int i; 1030d18719a4STom Rini const char *name = arg; 1031d18719a4STom Rini bool enable = true; 1032d18719a4STom Rini 1033d18719a4STom Rini if ((strncmp(arg, "no-", 3) == 0) 1034d18719a4STom Rini || (strncmp(arg, "no_", 3) == 0)) { 1035d18719a4STom Rini name = arg + 3; 1036d18719a4STom Rini enable = false; 1037d18719a4STom Rini } 1038d18719a4STom Rini 1039d18719a4STom Rini for (i = 0; i < ARRAY_SIZE(check_table); i++) { 1040d18719a4STom Rini struct check *c = check_table[i]; 1041d18719a4STom Rini 1042d18719a4STom Rini if (streq(c->name, name)) { 1043d18719a4STom Rini if (enable) 1044d18719a4STom Rini enable_warning_error(c, warn, error); 1045d18719a4STom Rini else 1046d18719a4STom Rini disable_warning_error(c, warn, error); 1047d18719a4STom Rini return; 1048d18719a4STom Rini } 1049d18719a4STom Rini } 1050d18719a4STom Rini 1051d18719a4STom Rini die("Unrecognized check name \"%s\"\n", name); 1052d18719a4STom Rini } 1053d18719a4STom Rini 1054d18719a4STom Rini void process_checks(bool force, struct dt_info *dti) 1055d18719a4STom Rini { 1056d18719a4STom Rini int i; 1057d18719a4STom Rini int error = 0; 1058d18719a4STom Rini 1059d18719a4STom Rini for (i = 0; i < ARRAY_SIZE(check_table); i++) { 1060d18719a4STom Rini struct check *c = check_table[i]; 1061d18719a4STom Rini 1062d18719a4STom Rini if (c->warn || c->error) 1063d18719a4STom Rini error = error || run_check(c, dti); 1064d18719a4STom Rini } 1065d18719a4STom Rini 1066d18719a4STom Rini if (error) { 1067d18719a4STom Rini if (!force) { 1068d18719a4STom Rini fprintf(stderr, "ERROR: Input tree has errors, aborting " 1069d18719a4STom Rini "(use -f to force output)\n"); 1070d18719a4STom Rini exit(2); 1071d18719a4STom Rini } else if (quiet < 3) { 1072d18719a4STom Rini fprintf(stderr, "Warning: Input tree has errors, " 1073d18719a4STom Rini "output forced\n"); 1074d18719a4STom Rini } 1075d18719a4STom Rini } 1076d18719a4STom Rini } 1077