* [PATCH v4 1/3] checks: Add bus checks for PCI buses
[not found] ` <20170320144418.5021-1-robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2017-03-20 14:44 ` Rob Herring
[not found] ` <20170320144418.5021-2-robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-03-20 14:44 ` [PATCH v4 2/3] checks: Add bus checks for simple-bus buses Rob Herring
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Rob Herring @ 2017-03-20 14:44 UTC (permalink / raw)
To: David Gibson
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Add PCI bridge and device node checks. We identify PCI bridges with
'device_type = "pci"' as only PCI bridges should set that property. For
bridges, check that node name is pci or pcie, ranges and bus-range are
present, and #address-cells and #size-cells are correct.
For devices, check the reg property fields are correct for the first
element (the config address). Check that the unit address is formatted
corectly based on the reg property. Device unit addresses are in the
form DD or DD,F where DD is the device 0-0x1f and F is the function 0-7.
Also, check that the bus number is within the expected range defined by
bridge's bus-ranges.
Reviewed-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
Signed-off-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
v4:
- replace one last strcmp with streq
- Add pci_bridge dependency on pci_device_bus_num
v3:
- Use bus_type ptr for matching bus types
- Add a name string to bus_type
- Add a bus-range check
- Improve the PCI device reg value checking
- Use streq/strneq
- fix FAIL call changes from current master
v2:
- Remove bus_type functions. Combine test for bus_type and bridge check
into single check.
- Add a check that PCI bridge node name is pci or pcie.
checks.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
dtc.h | 5 +++
2 files changed, 141 insertions(+)
diff --git a/checks.c b/checks.c
index 38f548e582c8..427a5787b004 100644
--- a/checks.c
+++ b/checks.c
@@ -681,6 +681,138 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
}
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
+static const struct bus_type pci_bus = {
+ .name = "PCI",
+};
+
+static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ cell_t *cells;
+
+ prop = get_property(node, "device_type");
+ if (!prop || !streq(prop->val.val, "pci"))
+ return;
+
+ 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);
+
+ prop = get_property(node, "ranges");
+ if (!prop)
+ FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
+ node->fullpath);
+
+ if (node_addr_cells(node) != 3)
+ FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
+ node->fullpath);
+ if (node_size_cells(node) != 2)
+ FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
+ node->fullpath);
+
+ prop = get_property(node, "bus-range");
+ if (!prop) {
+ FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
+ node->fullpath);
+ return;
+ }
+ if (prop->val.len != (sizeof(cell_t) * 2)) {
+ FAIL(c, dti, "Node %s bus-range must be 2 cells",
+ node->fullpath);
+ 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);
+ if (fdt32_to_cpu(cells[1]) > 0xff)
+ FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
+ node->fullpath);
+}
+WARNING(pci_bridge, check_pci_bridge, NULL,
+ &device_type_is_string, &addr_size_cells);
+
+static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ unsigned int bus_num, min_bus, max_bus;
+ cell_t *cells;
+
+ if (!node->parent || (node->parent->bus != &pci_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (!prop)
+ return;
+
+ cells = (cell_t *)prop->val.val;
+ bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
+
+ prop = get_property(node->parent, "bus-range");
+ if (!prop) {
+ min_bus = max_bus = 0;
+ } else {
+ cells = (cell_t *)prop->val.val;
+ min_bus = fdt32_to_cpu(cells[0]);
+ 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);
+}
+WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge);
+
+static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[5];
+ unsigned int dev, func, reg;
+ cell_t *cells;
+
+ if (!node->parent || (node->parent->bus != &pci_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (!prop) {
+ FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
+ 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);
+
+ 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);
+ if (reg & 0x000000ff)
+ FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
+ node->fullpath);
+
+ if (func == 0) {
+ snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
+ if (streq(unitname, unit_addr))
+ return;
+ }
+
+ snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
+ if (streq(unitname, unit_addr))
+ return;
+
+ FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
+ node->fullpath, unit_addr);
+}
+WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format);
+
/*
* Style checks
*/
@@ -753,6 +885,10 @@ static struct check *check_table[] = {
&unit_address_vs_reg,
+ &pci_bridge,
+ &pci_device_reg,
+ &pci_device_bus_num,
+
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
diff --git a/dtc.h b/dtc.h
index 403b79deab88..fc24e17510fd 100644
--- a/dtc.h
+++ b/dtc.h
@@ -135,6 +135,10 @@ struct label {
struct label *next;
};
+struct bus_type {
+ const char *name;
+};
+
struct property {
bool deleted;
char *name;
@@ -161,6 +165,7 @@ struct node {
int addr_cells, size_cells;
struct label *labels;
+ const struct bus_type *bus;
};
#define for_each_label_withdel(l0, l) \
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/3] checks: Add bus checks for simple-bus buses
[not found] ` <20170320144418.5021-1-robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-03-20 14:44 ` [PATCH v4 1/3] checks: Add bus checks for PCI buses Rob Herring
@ 2017-03-20 14:44 ` Rob Herring
2017-03-20 14:44 ` [PATCH v4 3/3] checks: Warn on node name unit-addresses with '0x' or leading 0s Rob Herring
2017-03-21 3:50 ` [PATCH v4 0/3] dtc bus and unit address checks David Gibson
3 siblings, 0 replies; 6+ messages in thread
From: Rob Herring @ 2017-03-20 14:44 UTC (permalink / raw)
To: David Gibson
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Add checks to identify simple-bus bus types and checks for child
devices. Simple-bus type is generally identified by "simple-bus"
compatible string. We also treat the root as a simple-bus, but only for
child nodes with reg property.
Signed-off-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
v4:
- Avoid strlen overrunning property buffer in node_is_compatible
- Drop assuming root node is a simple-bus
v3:
- new patch
checks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/checks.c b/checks.c
index 427a5787b004..33036b8dbbc2 100644
--- a/checks.c
+++ b/checks.c
@@ -813,6 +813,73 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no
}
WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format);
+static const struct bus_type simple_bus = {
+ .name = "simple-bus",
+};
+
+static bool node_is_compatible(struct node *node, const char *compat)
+{
+ struct property *prop;
+ const char *str, *end;
+
+ prop = get_property(node, "compatible");
+ if (!prop)
+ return false;
+
+ for (str = prop->val.val, end = str + prop->val.len; str < end;
+ str += strnlen(str, end - str) + 1) {
+ if (strneq(str, compat, end - str))
+ return true;
+ }
+ return false;
+}
+
+static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
+{
+ if (node_is_compatible(node, "simple-bus"))
+ node->bus = &simple_bus;
+}
+WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
+
+static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
+{
+ struct property *prop;
+ const char *unitname = get_unitname(node);
+ char unit_addr[17];
+ unsigned int size;
+ uint64_t reg = 0;
+ cell_t *cells = NULL;
+
+ if (!node->parent || (node->parent->bus != &simple_bus))
+ return;
+
+ prop = get_property(node, "reg");
+ if (prop)
+ cells = (cell_t *)prop->val.val;
+ else {
+ prop = get_property(node, "ranges");
+ if (prop && prop->val.len)
+ /* skip of child address */
+ cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
+ }
+
+ if (!cells) {
+ if (node->parent->parent && !(node->bus == &simple_bus))
+ FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
+ return;
+ }
+
+ size = node_addr_cells(node->parent);
+ while (size--)
+ reg = (reg << 32) | fdt32_to_cpu(*(cells++));
+
+ snprintf(unit_addr, sizeof(unit_addr), "%lx", reg);
+ if (!streq(unitname, unit_addr))
+ FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
+ node->fullpath, unit_addr);
+}
+WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge);
+
/*
* Style checks
*/
@@ -889,6 +956,9 @@ static struct check *check_table[] = {
&pci_device_reg,
&pci_device_bus_num,
+ &simple_bus_bridge,
+ &simple_bus_reg,
+
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
--
2.10.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/3] checks: Warn on node name unit-addresses with '0x' or leading 0s
[not found] ` <20170320144418.5021-1-robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-03-20 14:44 ` [PATCH v4 1/3] checks: Add bus checks for PCI buses Rob Herring
2017-03-20 14:44 ` [PATCH v4 2/3] checks: Add bus checks for simple-bus buses Rob Herring
@ 2017-03-20 14:44 ` Rob Herring
2017-03-21 3:50 ` [PATCH v4 0/3] dtc bus and unit address checks David Gibson
3 siblings, 0 replies; 6+ messages in thread
From: Rob Herring @ 2017-03-20 14:44 UTC (permalink / raw)
To: David Gibson
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Node name unit-addresses should generally never begin with 0x or leading
0s. Add warnings to check for these cases, but only for nodes without a
known bus type as there should be better bus specific checks of the
unit address in those cases. Any unit addresses that don't follow the
general rule will need to add a new bus type. There aren't any known
ones ATM.
Reviewed-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
Signed-off-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
v4:
- Rebase to 1.4.4
v3:
- Only run check if bus type is not set (moving to the end of the series
as a result). The bus bridge checks also must be a dependency.
v2:
- Split into separate check from unit_address_vs_reg
checks.c | 25 +++++++++++++++++++++++++
tests/run_tests.sh | 2 ++
tests/unit-addr-leading-0s.dts | 12 ++++++++++++
tests/unit-addr-leading-0x.dts | 12 ++++++++++++
4 files changed, 51 insertions(+)
create mode 100644 tests/unit-addr-leading-0s.dts
create mode 100644 tests/unit-addr-leading-0x.dts
diff --git a/checks.c b/checks.c
index 33036b8dbbc2..7f9232158dd9 100644
--- a/checks.c
+++ b/checks.c
@@ -880,6 +880,30 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge);
+static void check_unit_address_format(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ const char *unitname = get_unitname(node);
+
+ if (node->parent && node->parent->bus)
+ return;
+
+ if (!unitname[0])
+ return;
+
+ if (!strncmp(unitname, "0x", 2)) {
+ FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
+ node->fullpath);
+ /* 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);
+}
+WARNING(unit_address_format, check_unit_address_format, NULL,
+ &node_name_format, &pci_bridge, &simple_bus_bridge);
+
/*
* Style checks
*/
@@ -951,6 +975,7 @@ static struct check *check_table[] = {
&addr_size_cells, ®_format, &ranges_format,
&unit_address_vs_reg,
+ &unit_address_format,
&pci_bridge,
&pci_device_reg,
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index ed489dbdd269..0f5c3db79b80 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -540,6 +540,8 @@ dtc_tests () {
check_tests obsolete-chosen-interrupt-controller.dts obsolete_chosen_interrupt_controller
check_tests reg-without-unit-addr.dts unit_address_vs_reg
check_tests unit-addr-without-reg.dts unit_address_vs_reg
+ check_tests unit-addr-leading-0x.dts unit_address_format
+ check_tests unit-addr-leading-0s.dts unit_address_format
run_sh_test dtc-checkfails.sh node_name_chars -- -I dtb -O dtb bad_node_char.dtb
run_sh_test dtc-checkfails.sh node_name_format -- -I dtb -O dtb bad_node_format.dtb
run_sh_test dtc-checkfails.sh prop_name_chars -- -I dtb -O dtb bad_prop_char.dtb
diff --git a/tests/unit-addr-leading-0s.dts b/tests/unit-addr-leading-0s.dts
new file mode 100644
index 000000000000..cc017e9431a2
--- /dev/null
+++ b/tests/unit-addr-leading-0s.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ bus {
+ node@001 {
+ reg = <1 0>;
+ };
+ };
+};
diff --git a/tests/unit-addr-leading-0x.dts b/tests/unit-addr-leading-0x.dts
new file mode 100644
index 000000000000..74f19678c98c
--- /dev/null
+++ b/tests/unit-addr-leading-0x.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ bus {
+ node@0x1 {
+ reg = <1 0>;
+ };
+ };
+};
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 6+ messages in thread