From 9130ba884640328bb78aaa4840e5ddf06ccafb1c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 27 Feb 2018 17:40:38 -0600 Subject: scripts/dtc: Update to upstream version v1.4.6-9-gaadd0b65c987 This adds the following commits from upstream: aadd0b65c987 checks: centralize printing of property names in failure messages 88960e398907 checks: centralize printing of node path in check_msg f1879e1a50eb Add limited read-only support for older (V2 and V3) device tree to libfdt. 37dea76e9700 srcpos: drop special handling of tab 65893da4aee0 libfdt: overlay: Add missing license 962a45ca034d Avoid installing pylibfdt when dependencies are missing cd6ea1b2bea6 Makefile: Split INSTALL out into INSTALL_{PROGRAM,LIB,DATA,SCRIPT} 51b3a16338df Makefile.tests: Add LIBDL make(1) variable for portability sake 333d533a8f4d Attempt to auto-detect stat(1) being used if not given proper invocation e54388015af1 dtc: Bump version to v1.4.6 a1fe86f380cb fdtoverlay: Switch from using alloca to malloc c8d5472de3ff tests: Improve compatibility with other platforms c81d389a10cc checks: add chosen node checks e671852042a7 checks: add aliases node checks d0c44ebe3f42 checks: check for #{size,address}-cells without child nodes 18a3d84bb802 checks: add string list check for *-names properties 8fe94fd6f19f checks: add string list check 6c5730819604 checks: add a string check for 'label' property a384191eba09 checks: fix sound-dai phandle with arg property check b260c4f610c0 Fix ambiguous grammar for devicetree rule fe667e382bac tests: Add some basic tests for the pci_bridge checks 7975f6422260 Fix widespread incorrect use of strneq(), replace with new strprefixeq() fca296445eab Add strstarts() helper function cc392f089007 tests: Check non-matching cases for fdt_node_check_compatible() bba26a5291c8 livetree: avoid assertion of orphan phandles with overlays c8f8194d76cc implement strnlen for systems that need it c8b38f65fdec libfdt: Remove leading underscores from identifiers 3b62fdaebfe5 Remove leading underscores from identifiers 2d45d1c5c65e Replace FDT_VERSION() with stringify() 2e6fe5a107b5 Fix some errors in comments b0ae9e4b0ceb tests: Correct warning in sw_tree1.c Commit c8b38f65fdec upstream ("libfdt: Remove leading underscores from identifiers") changed the multiple inclusion define protection, so the kernel's libfdt_env.h needs the corresponding update. Signed-off-by: Rob Herring --- scripts/dtc/checks.c | 439 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 290 insertions(+), 149 deletions(-) (limited to 'scripts/dtc/checks.c') diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index e66138449886..c07ba4da9e36 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -53,26 +53,28 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ - static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ - static struct check _nm = { \ - .name = #_nm, \ - .fn = (_fn), \ - .data = (_d), \ - .warn = (_w), \ - .error = (_e), \ +#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \ + static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \ + static struct check nm_ = { \ + .name = #nm_, \ + .fn = (fn_), \ + .data = (d_), \ + .warn = (w_), \ + .error = (e_), \ .status = UNCHECKED, \ - .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ - .prereq = _nm##_prereqs, \ + .num_prereqs = ARRAY_SIZE(nm_##_prereqs), \ + .prereq = nm_##_prereqs, \ }; -#define WARNING(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) -#define ERROR(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) -#define CHECK(_nm, _fn, _d, ...) \ - CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) - -static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti, +#define WARNING(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__) +#define ERROR(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__) +#define CHECK(nm_, fn_, d_, ...) \ + CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__) + +static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti, + struct node *node, + struct property *prop, const char *fmt, ...) { va_list ap; @@ -83,19 +85,33 @@ static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti, fprintf(stderr, "%s: %s (%s): ", strcmp(dti->outname, "-") ? dti->outname : "", (c->error) ? "ERROR" : "Warning", c->name); + if (node) { + fprintf(stderr, "%s", node->fullpath); + if (prop) + fprintf(stderr, ":%s", prop->name); + fputs(": ", stderr); + } vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } va_end(ap); } -#define FAIL(c, dti, ...) \ +#define FAIL(c, dti, node, ...) \ + do { \ + TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ + (c)->status = FAILED; \ + check_msg((c), dti, node, NULL, __VA_ARGS__); \ + } while (0) + +#define FAIL_PROP(c, dti, node, prop, ...) \ do { \ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ (c)->status = FAILED; \ - check_msg((c), dti, __VA_ARGS__); \ + check_msg((c), dti, node, prop, __VA_ARGS__); \ } while (0) + static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node) { struct node *child; @@ -126,7 +142,7 @@ static bool run_check(struct check *c, struct dt_info *dti) error = error || run_check(prq, dti); if (prq->status != PASSED) { c->status = PREREQ; - check_msg(c, dti, "Failed prerequisite '%s'", + check_msg(c, dti, NULL, NULL, "Failed prerequisite '%s'", c->prereq[i]->name); } } @@ -156,7 +172,7 @@ out: static inline void check_always_fail(struct check *c, struct dt_info *dti, struct node *node) { - FAIL(c, dti, "always_fail check"); + FAIL(c, dti, node, "always_fail check"); } CHECK(always_fail, check_always_fail, NULL); @@ -171,14 +187,42 @@ static void check_is_string(struct check *c, struct dt_info *dti, return; /* Not present, assumed ok */ if (!data_is_one_string(prop->val)) - FAIL(c, dti, "\"%s\" property in %s is not a string", - propname, node->fullpath); + FAIL_PROP(c, dti, node, prop, "property is not a string"); } #define WARNING_IF_NOT_STRING(nm, propname) \ WARNING(nm, check_is_string, (propname)) #define ERROR_IF_NOT_STRING(nm, propname) \ ERROR(nm, check_is_string, (propname)) +static void check_is_string_list(struct check *c, struct dt_info *dti, + struct node *node) +{ + int rem, l; + struct property *prop; + char *propname = c->data; + char *str; + + prop = get_property(node, propname); + if (!prop) + return; /* Not present, assumed ok */ + + str = prop->val.val; + rem = prop->val.len; + while (rem > 0) { + l = strnlen(str, rem); + if (l == rem) { + FAIL_PROP(c, dti, node, prop, "property is not a string list"); + break; + } + rem -= l + 1; + str += l + 1; + } +} +#define WARNING_IF_NOT_STRING_LIST(nm, propname) \ + WARNING(nm, check_is_string_list, (propname)) +#define ERROR_IF_NOT_STRING_LIST(nm, propname) \ + ERROR(nm, check_is_string_list, (propname)) + static void check_is_cell(struct check *c, struct dt_info *dti, struct node *node) { @@ -190,8 +234,7 @@ static void check_is_cell(struct check *c, struct dt_info *dti, return; /* Not present, assumed ok */ if (prop->val.len != sizeof(cell_t)) - FAIL(c, dti, "\"%s\" property in %s is not a single cell", - propname, node->fullpath); + FAIL_PROP(c, dti, node, prop, "property is not a single cell"); } #define WARNING_IF_NOT_CELL(nm, propname) \ WARNING(nm, check_is_cell, (propname)) @@ -212,8 +255,7 @@ static void check_duplicate_node_names(struct check *c, struct dt_info *dti, child2; child2 = child2->next_sibling) if (streq(child->name, child2->name)) - FAIL(c, dti, "Duplicate node name %s", - child->fullpath); + FAIL(c, dti, node, "Duplicate node name"); } ERROR(duplicate_node_names, check_duplicate_node_names, NULL); @@ -227,8 +269,7 @@ static void check_duplicate_property_names(struct check *c, struct dt_info *dti, if (prop2->deleted) continue; if (streq(prop->name, prop2->name)) - FAIL(c, dti, "Duplicate property name %s in %s", - prop->name, node->fullpath); + FAIL_PROP(c, dti, node, prop, "Duplicate property name"); } } } @@ -246,8 +287,8 @@ static void check_node_name_chars(struct check *c, struct dt_info *dti, int n = strspn(node->name, c->data); if (n < strlen(node->name)) - FAIL(c, dti, "Bad character '%c' in node %s", - node->name[n], node->fullpath); + FAIL(c, dti, node, "Bad character '%c' in node name", + node->name[n]); } ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); @@ -257,8 +298,8 @@ static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, int n = strspn(node->name, c->data); if (n < node->basenamelen) - FAIL(c, dti, "Character '%c' not recommended in node %s", - node->name[n], node->fullpath); + FAIL(c, dti, node, "Character '%c' not recommended in node name", + node->name[n]); } CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT); @@ -266,8 +307,7 @@ static void check_node_name_format(struct check *c, struct dt_info *dti, struct node *node) { if (strchr(get_unitname(node), '@')) - FAIL(c, dti, "Node %s has multiple '@' characters in name", - node->fullpath); + FAIL(c, dti, node, "multiple '@' characters in node name"); } ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); @@ -285,12 +325,10 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, if (prop) { if (!unitname[0]) - FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name", - node->fullpath); + FAIL(c, dti, node, "node has a reg or ranges property, but no unit name"); } else { if (unitname[0]) - FAIL(c, dti, "Node %s has a unit name, but no reg property", - node->fullpath); + FAIL(c, dti, node, "node has a unit name, but no reg property"); } } WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); @@ -304,8 +342,8 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti, int n = strspn(prop->name, c->data); if (n < strlen(prop->name)) - FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s", - prop->name[n], prop->name, node->fullpath); + FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", + prop->name[n]); } } ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); @@ -336,8 +374,8 @@ static void check_property_name_chars_strict(struct check *c, n = strspn(name, c->data); } if (n < strlen(name)) - FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s", - name[n], prop->name, node->fullpath); + FAIL_PROP(c, dti, node, prop, "Character '%c' not recommended in property name", + name[n]); } } CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT); @@ -370,7 +408,7 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti, return; if ((othernode != node) || (otherprop != prop) || (othermark != mark)) - FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT + FAIL(c, dti, node, "Duplicate label '%s' on " DESCLABEL_FMT " and " DESCLABEL_FMT, label, DESCLABEL_ARGS(node, prop, mark), DESCLABEL_ARGS(othernode, otherprop, othermark)); @@ -410,8 +448,8 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, return 0; if (prop->val.len != sizeof(cell_t)) { - FAIL(c, dti, "%s has bad length (%d) %s property", - node->fullpath, prop->val.len, prop->name); + FAIL_PROP(c, dti, node, prop, "bad length (%d) %s property", + prop->val.len, prop->name); return 0; } @@ -422,8 +460,8 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, /* "Set this node's phandle equal to some * other node's phandle". That's nonsensical * by construction. */ { - FAIL(c, dti, "%s in %s is a reference to another node", - prop->name, node->fullpath); + FAIL(c, dti, node, "%s is a reference to another node", + prop->name); } /* But setting this node's phandle equal to its own * phandle is allowed - that means allocate a unique @@ -436,8 +474,8 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); if ((phandle == 0) || (phandle == -1)) { - FAIL(c, dti, "%s has bad value (0x%x) in %s property", - node->fullpath, phandle, prop->name); + FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", + phandle, prop->name); return 0; } @@ -463,16 +501,16 @@ static void check_explicit_phandles(struct check *c, struct dt_info *dti, return; if (linux_phandle && phandle && (phandle != linux_phandle)) - FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'" - " properties", node->fullpath); + FAIL(c, dti, node, "mismatching 'phandle' and 'linux,phandle'" + " properties"); if (linux_phandle && !phandle) phandle = linux_phandle; other = get_node_by_phandle(root, phandle); if (other && (other != node)) { - FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)", - node->fullpath, phandle, other->fullpath); + FAIL(c, dti, node, "duplicated phandle 0x%x (seen before at %s)", + phandle, other->fullpath); return; } @@ -496,8 +534,8 @@ static void check_name_properties(struct check *c, struct dt_info *dti, if ((prop->val.len != node->basenamelen+1) || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { - FAIL(c, dti, "\"name\" property in %s is incorrect (\"%s\" instead" - " of base node name)", node->fullpath, prop->val.val); + FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" + " of base node name)", prop->val.val); } else { /* The name property is correct, and therefore redundant. * Delete it */ @@ -531,7 +569,7 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti, refnode = get_node_by_ref(dt, m->ref); if (! refnode) { if (!(dti->dtsflags & DTSF_PLUGIN)) - FAIL(c, dti, "Reference to non-existent node or " + FAIL(c, dti, node, "Reference to non-existent node or " "label \"%s\"\n", m->ref); else /* mark the entry as unresolved */ *((fdt32_t *)(prop->val.val + m->offset)) = @@ -563,7 +601,7 @@ static void fixup_path_references(struct check *c, struct dt_info *dti, refnode = get_node_by_ref(dt, m->ref); if (!refnode) { - FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n", + FAIL(c, dti, node, "Reference to non-existent node or label \"%s\"\n", m->ref); continue; } @@ -586,6 +624,45 @@ WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); WARNING_IF_NOT_STRING(status_is_string, "status"); +WARNING_IF_NOT_STRING(label_is_string, "label"); + +WARNING_IF_NOT_STRING_LIST(compatible_is_string_list, "compatible"); + +static void check_names_is_string_list(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + for_each_property(node, prop) { + const char *s = strrchr(prop->name, '-'); + if (!s || !streq(s, "-names")) + continue; + + c->data = prop->name; + check_is_string_list(c, dti, node); + } +} +WARNING(names_is_string_list, check_names_is_string_list, NULL); + +static void check_alias_paths(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "aliases")) + return; + + for_each_property(node, prop) { + if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) { + FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)", + prop->val.val); + continue; + } + if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name)) + FAIL(c, dti, node, "aliases property name must include only lowercase and '-'"); + } +} +WARNING(alias_paths, check_alias_paths, NULL); static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, struct node *node) @@ -622,21 +699,21 @@ static void check_reg_format(struct check *c, struct dt_info *dti, return; /* No "reg", that's fine */ if (!node->parent) { - FAIL(c, dti, "Root node has a \"reg\" property"); + FAIL(c, dti, node, "Root node has a \"reg\" property"); return; } if (prop->val.len == 0) - FAIL(c, dti, "\"reg\" property in %s is empty", node->fullpath); + FAIL_PROP(c, dti, node, prop, "property is empty"); addr_cells = node_addr_cells(node->parent); size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); if (!entrylen || (prop->val.len % entrylen) != 0) - FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) " - "(#address-cells == %d, #size-cells == %d)", - node->fullpath, prop->val.len, addr_cells, size_cells); + FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " + "(#address-cells == %d, #size-cells == %d)", + prop->val.len, addr_cells, size_cells); } WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); @@ -651,7 +728,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, return; if (!node->parent) { - FAIL(c, dti, "Root node has a \"ranges\" property"); + FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property"); return; } @@ -663,20 +740,20 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, if (prop->val.len == 0) { if (p_addr_cells != c_addr_cells) - FAIL(c, dti, "%s has empty \"ranges\" property but its " - "#address-cells (%d) differs from %s (%d)", - node->fullpath, c_addr_cells, node->parent->fullpath, - p_addr_cells); + FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " + "#address-cells (%d) differs from %s (%d)", + c_addr_cells, node->parent->fullpath, + p_addr_cells); if (p_size_cells != c_size_cells) - FAIL(c, dti, "%s has empty \"ranges\" property but its " - "#size-cells (%d) differs from %s (%d)", - node->fullpath, c_size_cells, node->parent->fullpath, - p_size_cells); + FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " + "#size-cells (%d) differs from %s (%d)", + c_size_cells, node->parent->fullpath, + p_size_cells); } else if ((prop->val.len % entrylen) != 0) { - FAIL(c, dti, "\"ranges\" property in %s has invalid length (%d bytes) " - "(parent #address-cells == %d, child #address-cells == %d, " - "#size-cells == %d)", node->fullpath, prop->val.len, - p_addr_cells, c_addr_cells, c_size_cells); + FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) " + "(parent #address-cells == %d, child #address-cells == %d, " + "#size-cells == %d)", prop->val.len, + p_addr_cells, c_addr_cells, c_size_cells); } } WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); @@ -696,41 +773,33 @@ static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node * node->bus = &pci_bus; - if (!strneq(node->name, "pci", node->basenamelen) && - !strneq(node->name, "pcie", node->basenamelen)) - FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"", - node->fullpath); + if (!strprefixeq(node->name, node->basenamelen, "pci") && + !strprefixeq(node->name, node->basenamelen, "pcie")) + FAIL(c, dti, node, "node name is not \"pci\" or \"pcie\""); prop = get_property(node, "ranges"); if (!prop) - FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)", - node->fullpath); + FAIL(c, dti, node, "missing ranges for PCI bridge (or not a bridge)"); if (node_addr_cells(node) != 3) - FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge", - node->fullpath); + FAIL(c, dti, node, "incorrect #address-cells for PCI bridge"); if (node_size_cells(node) != 2) - FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge", - node->fullpath); + FAIL(c, dti, node, "incorrect #size-cells for PCI bridge"); prop = get_property(node, "bus-range"); if (!prop) { - FAIL(c, dti, "Node %s missing bus-range for PCI bridge", - node->fullpath); + FAIL(c, dti, node, "missing bus-range for PCI bridge"); return; } if (prop->val.len != (sizeof(cell_t) * 2)) { - FAIL(c, dti, "Node %s bus-range must be 2 cells", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "value must be 2 cells"); return; } cells = (cell_t *)prop->val.val; if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1])) - FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "1st cell must be less than or equal to 2nd cell"); if (fdt32_to_cpu(cells[1]) > 0xff) - FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "maximum bus number must be less than 256"); } WARNING(pci_bridge, check_pci_bridge, NULL, &device_type_is_string, &addr_size_cells); @@ -760,8 +829,8 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc max_bus = fdt32_to_cpu(cells[0]); } if ((bus_num < min_bus) || (bus_num > max_bus)) - FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)", - node->fullpath, bus_num, min_bus, max_bus); + FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", + bus_num, min_bus, max_bus); } WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge); @@ -778,25 +847,22 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no prop = get_property(node, "reg"); if (!prop) { - FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath); + FAIL(c, dti, node, "missing PCI reg property"); return; } cells = (cell_t *)prop->val.val; if (cells[1] || cells[2]) - FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "PCI reg config space address cells 2 and 3 must be 0"); reg = fdt32_to_cpu(cells[0]); dev = (reg & 0xf800) >> 11; func = (reg & 0x700) >> 8; if (reg & 0xff000000) - FAIL(c, dti, "Node %s PCI reg address is not configuration space", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "PCI reg address is not configuration space"); if (reg & 0x000000ff) - FAIL(c, dti, "Node %s PCI reg config space address register number must be 0", - node->fullpath); + FAIL_PROP(c, dti, node, prop, "PCI reg config space address register number must be 0"); if (func == 0) { snprintf(unit_addr, sizeof(unit_addr), "%x", dev); @@ -808,8 +874,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no if (streq(unitname, unit_addr)) return; - FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"", - node->fullpath, unit_addr); + FAIL(c, dti, node, "PCI unit address format error, expected \"%s\"", + unit_addr); } WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format, &pci_bridge); @@ -828,7 +894,7 @@ static bool node_is_compatible(struct node *node, const char *compat) for (str = prop->val.val, end = str + prop->val.len; str < end; str += strnlen(str, end - str) + 1) { - if (strneq(str, compat, end - str)) + if (strprefixeq(str, end - str, compat)) return true; } return false; @@ -865,7 +931,7 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no if (!cells) { if (node->parent->parent && !(node->bus == &simple_bus)) - FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath); + FAIL(c, dti, node, "missing or empty reg/ranges property"); return; } @@ -875,8 +941,8 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg); if (!streq(unitname, unit_addr)) - FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"", - node->fullpath, unit_addr); + FAIL(c, dti, node, "simple-bus unit address format error, expected \"%s\"", + unit_addr); } WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); @@ -892,14 +958,12 @@ static void check_unit_address_format(struct check *c, struct dt_info *dti, return; if (!strncmp(unitname, "0x", 2)) { - FAIL(c, dti, "Node %s unit name should not have leading \"0x\"", - node->fullpath); + FAIL(c, dti, node, "unit name should not have leading \"0x\""); /* skip over 0x for next test */ unitname += 2; } if (unitname[0] == '0' && isxdigit(unitname[1])) - FAIL(c, dti, "Node %s unit name should not have leading 0s", - node->fullpath); + FAIL(c, dti, node, "unit name should not have leading 0s"); } WARNING(unit_address_format, check_unit_address_format, NULL, &node_name_format, &pci_bridge, &simple_bus_bridge); @@ -922,16 +986,38 @@ static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, return; if (node->parent->addr_cells == -1) - FAIL(c, dti, "Relying on default #address-cells value for %s", - node->fullpath); + FAIL(c, dti, node, "Relying on default #address-cells value"); if (node->parent->size_cells == -1) - FAIL(c, dti, "Relying on default #size-cells value for %s", - node->fullpath); + FAIL(c, dti, node, "Relying on default #size-cells value"); } WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, &addr_size_cells); +static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + struct node *child; + bool has_reg = false; + + if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) + return; + + if (get_property(node, "ranges") || !node->children) + return; + + for_each_child(node, child) { + prop = get_property(child, "reg"); + if (prop) + has_reg = true; + } + + if (!has_reg) + FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property"); +} +WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); + static void check_obsolete_chosen_interrupt_controller(struct check *c, struct dt_info *dti, struct node *node) @@ -950,12 +1036,61 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, prop = get_property(chosen, "interrupt-controller"); if (prop) - FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" " - "property"); + FAIL_PROP(c, dti, node, prop, + "/chosen has obsolete \"interrupt-controller\" property"); } WARNING(obsolete_chosen_interrupt_controller, check_obsolete_chosen_interrupt_controller, NULL); +static void check_chosen_node_is_root(struct check *c, struct dt_info *dti, + struct node *node) +{ + if (!streq(node->name, "chosen")) + return; + + if (node->parent != dti->dt) + FAIL(c, dti, node, "chosen node must be at root node"); +} +WARNING(chosen_node_is_root, check_chosen_node_is_root, NULL); + +static void check_chosen_node_bootargs(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "chosen")) + return; + + prop = get_property(node, "bootargs"); + if (!prop) + return; + + c->data = prop->name; + check_is_string(c, dti, node); +} +WARNING(chosen_node_bootargs, check_chosen_node_bootargs, NULL); + +static void check_chosen_node_stdout_path(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct property *prop; + + if (!streq(node->name, "chosen")) + return; + + prop = get_property(node, "stdout-path"); + if (!prop) { + prop = get_property(node, "linux,stdout-path"); + if (!prop) + return; + FAIL_PROP(c, dti, node, prop, "Use 'stdout-path' instead"); + } + + c->data = prop->name; + check_is_string(c, dti, node); +} +WARNING(chosen_node_stdout_path, check_chosen_node_stdout_path, NULL); + struct provider { const char *prop_name; const char *cell_name; @@ -972,8 +1107,9 @@ static void check_property_phandle_args(struct check *c, int cell, cellsize = 0; if (prop->val.len % sizeof(cell_t)) { - FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s", - prop->name, prop->val.len, sizeof(cell_t), node->fullpath); + FAIL_PROP(c, dti, node, prop, + "property size (%d) is invalid, expected multiple of %zu", + prop->val.len, sizeof(cell_t)); return; } @@ -1004,14 +1140,16 @@ static void check_property_phandle_args(struct check *c, break; } if (!m) - FAIL(c, dti, "Property '%s', cell %d is not a phandle reference in %s", - prop->name, cell, node->fullpath); + FAIL_PROP(c, dti, node, prop, + "cell %d is not a phandle reference", + cell); } provider_node = get_node_by_phandle(root, phandle); if (!provider_node) { - FAIL(c, dti, "Could not get phandle node for %s:%s(cell %d)", - node->fullpath, prop->name, cell); + FAIL_PROP(c, dti, node, prop, + "Could not get phandle node for (cell %d)", + cell); break; } @@ -1021,16 +1159,17 @@ static void check_property_phandle_args(struct check *c, } else if (provider->optional) { cellsize = 0; } else { - FAIL(c, dti, "Missing property '%s' in node %s or bad phandle (referred from %s:%s[%d])", + FAIL(c, dti, node, "Missing property '%s' in node %s or bad phandle (referred from %s[%d])", provider->cell_name, provider_node->fullpath, - node->fullpath, prop->name, cell); + prop->name, cell); break; } if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { - FAIL(c, dti, "%s property size (%d) too small for cell size %d in %s", - prop->name, prop->val.len, cellsize, node->fullpath); + FAIL_PROP(c, dti, node, prop, + "property size (%d) too small for cell size %d", + prop->val.len, cellsize); } } } @@ -1066,7 +1205,7 @@ WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells"); WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells"); WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells"); WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells"); -WARNING_PROPERTY_PHANDLE_CELLS(sound_dais, "sound-dais", "#sound-dai-cells"); +WARNING_PROPERTY_PHANDLE_CELLS(sound_dai, "sound-dai", "#sound-dai-cells"); WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells"); static bool prop_is_gpio(struct property *prop) @@ -1132,8 +1271,8 @@ static void check_deprecated_gpio_property(struct check *c, if (!streq(str, "gpio")) continue; - FAIL(c, dti, "'[*-]gpio' is deprecated, use '[*-]gpios' instead for %s:%s", - node->fullpath, prop->name); + FAIL_PROP(c, dti, node, prop, + "'[*-]gpio' is deprecated, use '[*-]gpios' instead"); } } @@ -1167,9 +1306,8 @@ static void check_interrupts_property(struct check *c, return; if (irq_prop->val.len % sizeof(cell_t)) - FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s", - irq_prop->name, irq_prop->val.len, sizeof(cell_t), - node->fullpath); + FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", + irq_prop->val.len, sizeof(cell_t)); while (parent && !prop) { if (parent != node && node_is_interrupt_provider(parent)) { @@ -1187,14 +1325,12 @@ static void check_interrupts_property(struct check *c, irq_node = get_node_by_phandle(root, phandle); if (!irq_node) { - FAIL(c, dti, "Bad interrupt-parent phandle for %s", - node->fullpath); + FAIL_PROP(c, dti, parent, prop, "Bad phandle"); return; } if (!node_is_interrupt_provider(irq_node)) - FAIL(c, dti, - "Missing interrupt-controller or interrupt-map property in %s", - irq_node->fullpath); + FAIL(c, dti, irq_node, + "Missing interrupt-controller or interrupt-map property"); break; } @@ -1203,23 +1339,21 @@ static void check_interrupts_property(struct check *c, } if (!irq_node) { - FAIL(c, dti, "Missing interrupt-parent for %s", node->fullpath); + FAIL(c, dti, node, "Missing interrupt-parent"); return; } prop = get_property(irq_node, "#interrupt-cells"); if (!prop) { - FAIL(c, dti, "Missing #interrupt-cells in interrupt-parent %s", - irq_node->fullpath); + FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent"); return; } irq_cells = propval_cell(prop); if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { - FAIL(c, dti, - "interrupts size is (%d), expected multiple of %d in %s", - irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)), - node->fullpath); + FAIL_PROP(c, dti, node, prop, + "size is (%d), expected multiple of %d", + irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); } } WARNING(interrupts_property, check_interrupts_property, &phandle_references); @@ -1236,6 +1370,9 @@ static struct check *check_table[] = { &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, &device_type_is_string, &model_is_string, &status_is_string, + &label_is_string, + + &compatible_is_string_list, &names_is_string_list, &property_name_chars_strict, &node_name_chars_strict, @@ -1253,7 +1390,9 @@ static struct check *check_table[] = { &simple_bus_reg, &avoid_default_addr_size, + &avoid_unnecessary_addr_size, &obsolete_chosen_interrupt_controller, + &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, &clocks_property, &cooling_device_property, @@ -1269,13 +1408,15 @@ static struct check *check_table[] = { &power_domains_property, &pwms_property, &resets_property, - &sound_dais_property, + &sound_dai_property, &thermal_sensors_property, &deprecated_gpio_property, &gpios_property, &interrupts_property, + &alias_paths, + &always_fail, }; -- cgit