| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007. |
|---|
| 3 | | - * |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or |
|---|
| 6 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 7 | | - * published by the Free Software Foundation; either version 2 of the |
|---|
| 8 | | - * License, or (at your option) any later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | | - * General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program; if not, write to the Free Software |
|---|
| 17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
|---|
| 18 | | - * USA |
|---|
| 19 | 4 | */ |
|---|
| 20 | 5 | |
|---|
| 21 | 6 | #include "dtc.h" |
|---|
| 7 | +#include "srcpos.h" |
|---|
| 22 | 8 | |
|---|
| 23 | 9 | #ifdef TRACE_CHECKS |
|---|
| 24 | 10 | #define TRACE(c, ...) \ |
|---|
| .. | .. |
|---|
| 78 | 64 | const char *fmt, ...) |
|---|
| 79 | 65 | { |
|---|
| 80 | 66 | va_list ap; |
|---|
| 81 | | - va_start(ap, fmt); |
|---|
| 67 | + char *str = NULL; |
|---|
| 68 | + struct srcpos *pos = NULL; |
|---|
| 69 | + char *file_str; |
|---|
| 82 | 70 | |
|---|
| 83 | | - if ((c->warn && (quiet < 1)) |
|---|
| 84 | | - || (c->error && (quiet < 2))) { |
|---|
| 85 | | - fprintf(stderr, "%s: %s (%s): ", |
|---|
| 86 | | - strcmp(dti->outname, "-") ? dti->outname : "<stdout>", |
|---|
| 87 | | - (c->error) ? "ERROR" : "Warning", c->name); |
|---|
| 88 | | - if (node) { |
|---|
| 89 | | - fprintf(stderr, "%s", node->fullpath); |
|---|
| 90 | | - if (prop) |
|---|
| 91 | | - fprintf(stderr, ":%s", prop->name); |
|---|
| 92 | | - fputs(": ", stderr); |
|---|
| 93 | | - } |
|---|
| 94 | | - vfprintf(stderr, fmt, ap); |
|---|
| 95 | | - fprintf(stderr, "\n"); |
|---|
| 71 | + if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2))) |
|---|
| 72 | + return; |
|---|
| 73 | + |
|---|
| 74 | + if (prop && prop->srcpos) |
|---|
| 75 | + pos = prop->srcpos; |
|---|
| 76 | + else if (node && node->srcpos) |
|---|
| 77 | + pos = node->srcpos; |
|---|
| 78 | + |
|---|
| 79 | + if (pos) { |
|---|
| 80 | + file_str = srcpos_string(pos); |
|---|
| 81 | + xasprintf(&str, "%s", file_str); |
|---|
| 82 | + free(file_str); |
|---|
| 83 | + } else if (streq(dti->outname, "-")) { |
|---|
| 84 | + xasprintf(&str, "<stdout>"); |
|---|
| 85 | + } else { |
|---|
| 86 | + xasprintf(&str, "%s", dti->outname); |
|---|
| 96 | 87 | } |
|---|
| 88 | + |
|---|
| 89 | + xasprintf_append(&str, ": %s (%s): ", |
|---|
| 90 | + (c->error) ? "ERROR" : "Warning", c->name); |
|---|
| 91 | + |
|---|
| 92 | + if (node) { |
|---|
| 93 | + if (prop) |
|---|
| 94 | + xasprintf_append(&str, "%s:%s: ", node->fullpath, prop->name); |
|---|
| 95 | + else |
|---|
| 96 | + xasprintf_append(&str, "%s: ", node->fullpath); |
|---|
| 97 | + } |
|---|
| 98 | + |
|---|
| 99 | + va_start(ap, fmt); |
|---|
| 100 | + xavsprintf_append(&str, fmt, ap); |
|---|
| 97 | 101 | va_end(ap); |
|---|
| 102 | + |
|---|
| 103 | + xasprintf_append(&str, "\n"); |
|---|
| 104 | + |
|---|
| 105 | + if (!prop && pos) { |
|---|
| 106 | + pos = node->srcpos; |
|---|
| 107 | + while (pos->next) { |
|---|
| 108 | + pos = pos->next; |
|---|
| 109 | + |
|---|
| 110 | + file_str = srcpos_string(pos); |
|---|
| 111 | + xasprintf_append(&str, " also defined at %s\n", file_str); |
|---|
| 112 | + free(file_str); |
|---|
| 113 | + } |
|---|
| 114 | + } |
|---|
| 115 | + |
|---|
| 116 | + fputs(str, stderr); |
|---|
| 98 | 117 | } |
|---|
| 99 | 118 | |
|---|
| 100 | 119 | #define FAIL(c, dti, node, ...) \ |
|---|
| .. | .. |
|---|
| 333 | 352 | FAIL(c, dti, node, "node has a reg or ranges property, but no unit name"); |
|---|
| 334 | 353 | } else { |
|---|
| 335 | 354 | if (unitname[0]) |
|---|
| 336 | | - FAIL(c, dti, node, "node has a unit name, but no reg property"); |
|---|
| 355 | + FAIL(c, dti, node, "node has a unit name, but no reg or ranges property"); |
|---|
| 337 | 356 | } |
|---|
| 338 | 357 | } |
|---|
| 339 | 358 | WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); |
|---|
| .. | .. |
|---|
| 648 | 667 | static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti, |
|---|
| 649 | 668 | struct node *node) |
|---|
| 650 | 669 | { |
|---|
| 670 | + if (generate_symbols && node->labels) |
|---|
| 671 | + return; |
|---|
| 651 | 672 | if (node->omit_if_unused && !node->is_referenced) |
|---|
| 652 | 673 | delete_node(node); |
|---|
| 653 | 674 | |
|---|
| .. | .. |
|---|
| 710 | 731 | return; |
|---|
| 711 | 732 | |
|---|
| 712 | 733 | for_each_property(node, prop) { |
|---|
| 734 | + if (streq(prop->name, "phandle") |
|---|
| 735 | + || streq(prop->name, "linux,phandle")) { |
|---|
| 736 | + continue; |
|---|
| 737 | + } |
|---|
| 738 | + |
|---|
| 713 | 739 | if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) { |
|---|
| 714 | 740 | FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)", |
|---|
| 715 | 741 | prop->val.val); |
|---|
| .. | .. |
|---|
| 779 | 805 | { |
|---|
| 780 | 806 | struct property *prop; |
|---|
| 781 | 807 | int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; |
|---|
| 808 | + const char *ranges = c->data; |
|---|
| 782 | 809 | |
|---|
| 783 | | - prop = get_property(node, "ranges"); |
|---|
| 810 | + prop = get_property(node, ranges); |
|---|
| 784 | 811 | if (!prop) |
|---|
| 785 | 812 | return; |
|---|
| 786 | 813 | |
|---|
| 787 | 814 | if (!node->parent) { |
|---|
| 788 | | - FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property"); |
|---|
| 815 | + FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property", |
|---|
| 816 | + ranges); |
|---|
| 789 | 817 | return; |
|---|
| 790 | 818 | } |
|---|
| 791 | 819 | |
|---|
| .. | .. |
|---|
| 797 | 825 | |
|---|
| 798 | 826 | if (prop->val.len == 0) { |
|---|
| 799 | 827 | if (p_addr_cells != c_addr_cells) |
|---|
| 800 | | - FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " |
|---|
| 828 | + FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its " |
|---|
| 801 | 829 | "#address-cells (%d) differs from %s (%d)", |
|---|
| 802 | | - c_addr_cells, node->parent->fullpath, |
|---|
| 830 | + ranges, c_addr_cells, node->parent->fullpath, |
|---|
| 803 | 831 | p_addr_cells); |
|---|
| 804 | 832 | if (p_size_cells != c_size_cells) |
|---|
| 805 | | - FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " |
|---|
| 833 | + FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its " |
|---|
| 806 | 834 | "#size-cells (%d) differs from %s (%d)", |
|---|
| 807 | | - c_size_cells, node->parent->fullpath, |
|---|
| 835 | + ranges, c_size_cells, node->parent->fullpath, |
|---|
| 808 | 836 | p_size_cells); |
|---|
| 809 | 837 | } else if ((prop->val.len % entrylen) != 0) { |
|---|
| 810 | | - FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) " |
|---|
| 838 | + FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " |
|---|
| 811 | 839 | "(parent #address-cells == %d, child #address-cells == %d, " |
|---|
| 812 | | - "#size-cells == %d)", prop->val.len, |
|---|
| 840 | + "#size-cells == %d)", ranges, prop->val.len, |
|---|
| 813 | 841 | p_addr_cells, c_addr_cells, c_size_cells); |
|---|
| 814 | 842 | } |
|---|
| 815 | 843 | } |
|---|
| 816 | | -WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); |
|---|
| 844 | +WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells); |
|---|
| 845 | +WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells); |
|---|
| 817 | 846 | |
|---|
| 818 | 847 | static const struct bus_type pci_bus = { |
|---|
| 819 | 848 | .name = "PCI", |
|---|
| .. | .. |
|---|
| 902 | 931 | return; |
|---|
| 903 | 932 | |
|---|
| 904 | 933 | prop = get_property(node, "reg"); |
|---|
| 905 | | - if (!prop) { |
|---|
| 906 | | - FAIL(c, dti, node, "missing PCI reg property"); |
|---|
| 934 | + if (!prop) |
|---|
| 907 | 935 | return; |
|---|
| 908 | | - } |
|---|
| 909 | 936 | |
|---|
| 910 | 937 | cells = (cell_t *)prop->val.val; |
|---|
| 911 | 938 | if (cells[1] || cells[2]) |
|---|
| .. | .. |
|---|
| 950 | 977 | |
|---|
| 951 | 978 | for (str = prop->val.val, end = str + prop->val.len; str < end; |
|---|
| 952 | 979 | str += strnlen(str, end - str) + 1) { |
|---|
| 953 | | - if (strprefixeq(str, end - str, compat)) |
|---|
| 980 | + if (streq(str, compat)) |
|---|
| 954 | 981 | return true; |
|---|
| 955 | 982 | } |
|---|
| 956 | 983 | return false; |
|---|
| .. | .. |
|---|
| 961 | 988 | if (node_is_compatible(node, "simple-bus")) |
|---|
| 962 | 989 | node->bus = &simple_bus; |
|---|
| 963 | 990 | } |
|---|
| 964 | | -WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells); |
|---|
| 991 | +WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, |
|---|
| 992 | + &addr_size_cells, &compatible_is_string_list); |
|---|
| 965 | 993 | |
|---|
| 966 | 994 | static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node) |
|---|
| 967 | 995 | { |
|---|
| .. | .. |
|---|
| 1001 | 1029 | unit_addr); |
|---|
| 1002 | 1030 | } |
|---|
| 1003 | 1031 | WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); |
|---|
| 1032 | + |
|---|
| 1033 | +static const struct bus_type i2c_bus = { |
|---|
| 1034 | + .name = "i2c-bus", |
|---|
| 1035 | +}; |
|---|
| 1036 | + |
|---|
| 1037 | +static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) |
|---|
| 1038 | +{ |
|---|
| 1039 | + if (strprefixeq(node->name, node->basenamelen, "i2c-bus") || |
|---|
| 1040 | + strprefixeq(node->name, node->basenamelen, "i2c-arb")) { |
|---|
| 1041 | + node->bus = &i2c_bus; |
|---|
| 1042 | + } else if (strprefixeq(node->name, node->basenamelen, "i2c")) { |
|---|
| 1043 | + struct node *child; |
|---|
| 1044 | + for_each_child(node, child) { |
|---|
| 1045 | + if (strprefixeq(child->name, node->basenamelen, "i2c-bus")) |
|---|
| 1046 | + return; |
|---|
| 1047 | + } |
|---|
| 1048 | + node->bus = &i2c_bus; |
|---|
| 1049 | + } else |
|---|
| 1050 | + return; |
|---|
| 1051 | + |
|---|
| 1052 | + if (!node->children) |
|---|
| 1053 | + return; |
|---|
| 1054 | + |
|---|
| 1055 | + if (node_addr_cells(node) != 1) |
|---|
| 1056 | + FAIL(c, dti, node, "incorrect #address-cells for I2C bus"); |
|---|
| 1057 | + if (node_size_cells(node) != 0) |
|---|
| 1058 | + FAIL(c, dti, node, "incorrect #size-cells for I2C bus"); |
|---|
| 1059 | + |
|---|
| 1060 | +} |
|---|
| 1061 | +WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells); |
|---|
| 1062 | + |
|---|
| 1063 | +#define I2C_OWN_SLAVE_ADDRESS (1U << 30) |
|---|
| 1064 | +#define I2C_TEN_BIT_ADDRESS (1U << 31) |
|---|
| 1065 | + |
|---|
| 1066 | +static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node) |
|---|
| 1067 | +{ |
|---|
| 1068 | + struct property *prop; |
|---|
| 1069 | + const char *unitname = get_unitname(node); |
|---|
| 1070 | + char unit_addr[17]; |
|---|
| 1071 | + uint32_t reg = 0; |
|---|
| 1072 | + int len; |
|---|
| 1073 | + cell_t *cells = NULL; |
|---|
| 1074 | + |
|---|
| 1075 | + if (!node->parent || (node->parent->bus != &i2c_bus)) |
|---|
| 1076 | + return; |
|---|
| 1077 | + |
|---|
| 1078 | + prop = get_property(node, "reg"); |
|---|
| 1079 | + if (prop) |
|---|
| 1080 | + cells = (cell_t *)prop->val.val; |
|---|
| 1081 | + |
|---|
| 1082 | + if (!cells) { |
|---|
| 1083 | + FAIL(c, dti, node, "missing or empty reg property"); |
|---|
| 1084 | + return; |
|---|
| 1085 | + } |
|---|
| 1086 | + |
|---|
| 1087 | + reg = fdt32_to_cpu(*cells); |
|---|
| 1088 | + /* Ignore I2C_OWN_SLAVE_ADDRESS */ |
|---|
| 1089 | + reg &= ~I2C_OWN_SLAVE_ADDRESS; |
|---|
| 1090 | + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); |
|---|
| 1091 | + if (!streq(unitname, unit_addr)) |
|---|
| 1092 | + FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"", |
|---|
| 1093 | + unit_addr); |
|---|
| 1094 | + |
|---|
| 1095 | + for (len = prop->val.len; len > 0; len -= 4) { |
|---|
| 1096 | + reg = fdt32_to_cpu(*(cells++)); |
|---|
| 1097 | + /* Ignore I2C_OWN_SLAVE_ADDRESS */ |
|---|
| 1098 | + reg &= ~I2C_OWN_SLAVE_ADDRESS; |
|---|
| 1099 | + |
|---|
| 1100 | + if ((reg & I2C_TEN_BIT_ADDRESS) && ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff)) |
|---|
| 1101 | + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", |
|---|
| 1102 | + reg); |
|---|
| 1103 | + else if (reg > 0x7f) |
|---|
| 1104 | + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property", |
|---|
| 1105 | + reg); |
|---|
| 1106 | + } |
|---|
| 1107 | +} |
|---|
| 1108 | +WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge); |
|---|
| 1109 | + |
|---|
| 1110 | +static const struct bus_type spi_bus = { |
|---|
| 1111 | + .name = "spi-bus", |
|---|
| 1112 | +}; |
|---|
| 1113 | + |
|---|
| 1114 | +static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) |
|---|
| 1115 | +{ |
|---|
| 1116 | + int spi_addr_cells = 1; |
|---|
| 1117 | + |
|---|
| 1118 | + if (strprefixeq(node->name, node->basenamelen, "spi")) { |
|---|
| 1119 | + node->bus = &spi_bus; |
|---|
| 1120 | + } else { |
|---|
| 1121 | + /* Try to detect SPI buses which don't have proper node name */ |
|---|
| 1122 | + struct node *child; |
|---|
| 1123 | + |
|---|
| 1124 | + if (node_addr_cells(node) != 1 || node_size_cells(node) != 0) |
|---|
| 1125 | + return; |
|---|
| 1126 | + |
|---|
| 1127 | + for_each_child(node, child) { |
|---|
| 1128 | + struct property *prop; |
|---|
| 1129 | + for_each_property(child, prop) { |
|---|
| 1130 | + if (strprefixeq(prop->name, 4, "spi-")) { |
|---|
| 1131 | + node->bus = &spi_bus; |
|---|
| 1132 | + break; |
|---|
| 1133 | + } |
|---|
| 1134 | + } |
|---|
| 1135 | + if (node->bus == &spi_bus) |
|---|
| 1136 | + break; |
|---|
| 1137 | + } |
|---|
| 1138 | + |
|---|
| 1139 | + if (node->bus == &spi_bus && get_property(node, "reg")) |
|---|
| 1140 | + FAIL(c, dti, node, "node name for SPI buses should be 'spi'"); |
|---|
| 1141 | + } |
|---|
| 1142 | + if (node->bus != &spi_bus || !node->children) |
|---|
| 1143 | + return; |
|---|
| 1144 | + |
|---|
| 1145 | + if (get_property(node, "spi-slave")) |
|---|
| 1146 | + spi_addr_cells = 0; |
|---|
| 1147 | + if (node_addr_cells(node) != spi_addr_cells) |
|---|
| 1148 | + FAIL(c, dti, node, "incorrect #address-cells for SPI bus"); |
|---|
| 1149 | + if (node_size_cells(node) != 0) |
|---|
| 1150 | + FAIL(c, dti, node, "incorrect #size-cells for SPI bus"); |
|---|
| 1151 | + |
|---|
| 1152 | +} |
|---|
| 1153 | +WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells); |
|---|
| 1154 | + |
|---|
| 1155 | +static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node) |
|---|
| 1156 | +{ |
|---|
| 1157 | + struct property *prop; |
|---|
| 1158 | + const char *unitname = get_unitname(node); |
|---|
| 1159 | + char unit_addr[9]; |
|---|
| 1160 | + uint32_t reg = 0; |
|---|
| 1161 | + cell_t *cells = NULL; |
|---|
| 1162 | + |
|---|
| 1163 | + if (!node->parent || (node->parent->bus != &spi_bus)) |
|---|
| 1164 | + return; |
|---|
| 1165 | + |
|---|
| 1166 | + if (get_property(node->parent, "spi-slave")) |
|---|
| 1167 | + return; |
|---|
| 1168 | + |
|---|
| 1169 | + prop = get_property(node, "reg"); |
|---|
| 1170 | + if (prop) |
|---|
| 1171 | + cells = (cell_t *)prop->val.val; |
|---|
| 1172 | + |
|---|
| 1173 | + if (!cells) { |
|---|
| 1174 | + FAIL(c, dti, node, "missing or empty reg property"); |
|---|
| 1175 | + return; |
|---|
| 1176 | + } |
|---|
| 1177 | + |
|---|
| 1178 | + reg = fdt32_to_cpu(*cells); |
|---|
| 1179 | + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); |
|---|
| 1180 | + if (!streq(unitname, unit_addr)) |
|---|
| 1181 | + FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"", |
|---|
| 1182 | + unit_addr); |
|---|
| 1183 | +} |
|---|
| 1184 | +WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge); |
|---|
| 1004 | 1185 | |
|---|
| 1005 | 1186 | static void check_unit_address_format(struct check *c, struct dt_info *dti, |
|---|
| 1006 | 1187 | struct node *node) |
|---|
| .. | .. |
|---|
| 1074 | 1255 | } |
|---|
| 1075 | 1256 | WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); |
|---|
| 1076 | 1257 | |
|---|
| 1077 | | -static void check_unique_unit_address(struct check *c, struct dt_info *dti, |
|---|
| 1078 | | - struct node *node) |
|---|
| 1258 | +static bool node_is_disabled(struct node *node) |
|---|
| 1259 | +{ |
|---|
| 1260 | + struct property *prop; |
|---|
| 1261 | + |
|---|
| 1262 | + prop = get_property(node, "status"); |
|---|
| 1263 | + if (prop) { |
|---|
| 1264 | + char *str = prop->val.val; |
|---|
| 1265 | + if (streq("disabled", str)) |
|---|
| 1266 | + return true; |
|---|
| 1267 | + } |
|---|
| 1268 | + |
|---|
| 1269 | + return false; |
|---|
| 1270 | +} |
|---|
| 1271 | + |
|---|
| 1272 | +static void check_unique_unit_address_common(struct check *c, |
|---|
| 1273 | + struct dt_info *dti, |
|---|
| 1274 | + struct node *node, |
|---|
| 1275 | + bool disable_check) |
|---|
| 1079 | 1276 | { |
|---|
| 1080 | 1277 | struct node *childa; |
|---|
| 1081 | 1278 | |
|---|
| .. | .. |
|---|
| 1092 | 1289 | if (!strlen(addr_a)) |
|---|
| 1093 | 1290 | continue; |
|---|
| 1094 | 1291 | |
|---|
| 1292 | + if (disable_check && node_is_disabled(childa)) |
|---|
| 1293 | + continue; |
|---|
| 1294 | + |
|---|
| 1095 | 1295 | for_each_child(node, childb) { |
|---|
| 1096 | 1296 | const char *addr_b = get_unitname(childb); |
|---|
| 1097 | 1297 | if (childa == childb) |
|---|
| 1098 | 1298 | break; |
|---|
| 1299 | + |
|---|
| 1300 | + if (disable_check && node_is_disabled(childb)) |
|---|
| 1301 | + continue; |
|---|
| 1099 | 1302 | |
|---|
| 1100 | 1303 | if (streq(addr_a, addr_b)) |
|---|
| 1101 | 1304 | FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath); |
|---|
| 1102 | 1305 | } |
|---|
| 1103 | 1306 | } |
|---|
| 1104 | 1307 | } |
|---|
| 1308 | + |
|---|
| 1309 | +static void check_unique_unit_address(struct check *c, struct dt_info *dti, |
|---|
| 1310 | + struct node *node) |
|---|
| 1311 | +{ |
|---|
| 1312 | + check_unique_unit_address_common(c, dti, node, false); |
|---|
| 1313 | +} |
|---|
| 1105 | 1314 | WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size); |
|---|
| 1315 | + |
|---|
| 1316 | +static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti, |
|---|
| 1317 | + struct node *node) |
|---|
| 1318 | +{ |
|---|
| 1319 | + check_unique_unit_address_common(c, dti, node, true); |
|---|
| 1320 | +} |
|---|
| 1321 | +CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled, |
|---|
| 1322 | + NULL, false, false, &avoid_default_addr_size); |
|---|
| 1106 | 1323 | |
|---|
| 1107 | 1324 | static void check_obsolete_chosen_interrupt_controller(struct check *c, |
|---|
| 1108 | 1325 | struct dt_info *dti, |
|---|
| .. | .. |
|---|
| 1378 | 1595 | |
|---|
| 1379 | 1596 | return false; |
|---|
| 1380 | 1597 | } |
|---|
| 1598 | + |
|---|
| 1599 | +static void check_interrupt_provider(struct check *c, |
|---|
| 1600 | + struct dt_info *dti, |
|---|
| 1601 | + struct node *node) |
|---|
| 1602 | +{ |
|---|
| 1603 | + struct property *prop; |
|---|
| 1604 | + |
|---|
| 1605 | + if (!node_is_interrupt_provider(node)) |
|---|
| 1606 | + return; |
|---|
| 1607 | + |
|---|
| 1608 | + prop = get_property(node, "#interrupt-cells"); |
|---|
| 1609 | + if (!prop) |
|---|
| 1610 | + FAIL(c, dti, node, |
|---|
| 1611 | + "Missing #interrupt-cells in interrupt provider"); |
|---|
| 1612 | + |
|---|
| 1613 | + prop = get_property(node, "#address-cells"); |
|---|
| 1614 | + if (!prop) |
|---|
| 1615 | + FAIL(c, dti, node, |
|---|
| 1616 | + "Missing #address-cells in interrupt provider"); |
|---|
| 1617 | +} |
|---|
| 1618 | +WARNING(interrupt_provider, check_interrupt_provider, NULL); |
|---|
| 1619 | + |
|---|
| 1381 | 1620 | static void check_interrupts_property(struct check *c, |
|---|
| 1382 | 1621 | struct dt_info *dti, |
|---|
| 1383 | 1622 | struct node *node) |
|---|
| .. | .. |
|---|
| 1404 | 1643 | prop = get_property(parent, "interrupt-parent"); |
|---|
| 1405 | 1644 | if (prop) { |
|---|
| 1406 | 1645 | phandle = propval_cell(prop); |
|---|
| 1407 | | - /* Give up if this is an overlay with external references */ |
|---|
| 1408 | | - if ((phandle == 0 || phandle == -1) && |
|---|
| 1409 | | - (dti->dtsflags & DTSF_PLUGIN)) |
|---|
| 1646 | + if ((phandle == 0) || (phandle == -1)) { |
|---|
| 1647 | + /* Give up if this is an overlay with |
|---|
| 1648 | + * external references */ |
|---|
| 1649 | + if (dti->dtsflags & DTSF_PLUGIN) |
|---|
| 1410 | 1650 | return; |
|---|
| 1651 | + FAIL_PROP(c, dti, parent, prop, "Invalid phandle"); |
|---|
| 1652 | + continue; |
|---|
| 1653 | + } |
|---|
| 1411 | 1654 | |
|---|
| 1412 | 1655 | irq_node = get_node_by_phandle(root, phandle); |
|---|
| 1413 | 1656 | if (!irq_node) { |
|---|
| .. | .. |
|---|
| 1431 | 1674 | |
|---|
| 1432 | 1675 | prop = get_property(irq_node, "#interrupt-cells"); |
|---|
| 1433 | 1676 | if (!prop) { |
|---|
| 1434 | | - FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent"); |
|---|
| 1677 | + /* We warn about that already in another test. */ |
|---|
| 1435 | 1678 | return; |
|---|
| 1436 | 1679 | } |
|---|
| 1437 | 1680 | |
|---|
| .. | .. |
|---|
| 1576 | 1819 | return; |
|---|
| 1577 | 1820 | |
|---|
| 1578 | 1821 | if (!strprefixeq(node->name, node->basenamelen, "endpoint")) |
|---|
| 1579 | | - FAIL(c, dti, node, "graph endpont node name should be 'endpoint'"); |
|---|
| 1822 | + FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'"); |
|---|
| 1580 | 1823 | |
|---|
| 1581 | 1824 | check_graph_reg(c, dti, node); |
|---|
| 1582 | 1825 | |
|---|
| .. | .. |
|---|
| 1611 | 1854 | &property_name_chars_strict, |
|---|
| 1612 | 1855 | &node_name_chars_strict, |
|---|
| 1613 | 1856 | |
|---|
| 1614 | | - &addr_size_cells, ®_format, &ranges_format, |
|---|
| 1857 | + &addr_size_cells, ®_format, &ranges_format, &dma_ranges_format, |
|---|
| 1615 | 1858 | |
|---|
| 1616 | 1859 | &unit_address_vs_reg, |
|---|
| 1617 | 1860 | &unit_address_format, |
|---|
| .. | .. |
|---|
| 1623 | 1866 | &simple_bus_bridge, |
|---|
| 1624 | 1867 | &simple_bus_reg, |
|---|
| 1625 | 1868 | |
|---|
| 1869 | + &i2c_bus_bridge, |
|---|
| 1870 | + &i2c_bus_reg, |
|---|
| 1871 | + |
|---|
| 1872 | + &spi_bus_bridge, |
|---|
| 1873 | + &spi_bus_reg, |
|---|
| 1874 | + |
|---|
| 1626 | 1875 | &avoid_default_addr_size, |
|---|
| 1627 | 1876 | &avoid_unnecessary_addr_size, |
|---|
| 1628 | 1877 | &unique_unit_address, |
|---|
| 1878 | + &unique_unit_address_if_enabled, |
|---|
| 1629 | 1879 | &obsolete_chosen_interrupt_controller, |
|---|
| 1630 | 1880 | &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, |
|---|
| 1631 | 1881 | |
|---|
| .. | .. |
|---|
| 1649 | 1899 | &deprecated_gpio_property, |
|---|
| 1650 | 1900 | &gpios_property, |
|---|
| 1651 | 1901 | &interrupts_property, |
|---|
| 1902 | + &interrupt_provider, |
|---|
| 1652 | 1903 | |
|---|
| 1653 | 1904 | &alias_paths, |
|---|
| 1654 | 1905 | |
|---|