mirror of https://gitlab.com/qemu-project/dtc.git
checks: add graph binding checks
Add checks for DT graph bindings. These checks check node names, unit-addresses and link connections on ports, port, and endpoint nodes. The graph nodes are matched by finding nodes named 'endpoint' or with a 'remote-endpoint' property. We can't match on 'ports' or 'port' nodes because those names are used for non-graph nodes. While the graph nodes aren't really buses, using the bus pointer to tag matched nodes is convenient. Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
2347c96edc
commit
df536831d0
148
checks.c
148
checks.c
|
@ -1393,6 +1393,152 @@ static void check_interrupts_property(struct check *c,
|
||||||
}
|
}
|
||||||
WARNING(interrupts_property, check_interrupts_property, &phandle_references);
|
WARNING(interrupts_property, check_interrupts_property, &phandle_references);
|
||||||
|
|
||||||
|
static const struct bus_type graph_port_bus = {
|
||||||
|
.name = "graph-port",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bus_type graph_ports_bus = {
|
||||||
|
.name = "graph-ports",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void check_graph_nodes(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
for_each_child(node, child) {
|
||||||
|
if (!(strprefixeq(child->name, child->basenamelen, "endpoint") ||
|
||||||
|
get_property(child, "remote-endpoint")))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
node->bus = &graph_port_bus;
|
||||||
|
|
||||||
|
/* The parent of 'port' nodes can be either 'ports' or a device */
|
||||||
|
if (!node->parent->bus &&
|
||||||
|
(streq(node->parent->name, "ports") || get_property(node, "reg")))
|
||||||
|
node->parent->bus = &graph_ports_bus;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
WARNING(graph_nodes, check_graph_nodes, NULL);
|
||||||
|
|
||||||
|
static void check_graph_child_address(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
struct node *child;
|
||||||
|
|
||||||
|
if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_child(node, child) {
|
||||||
|
struct property *prop = get_property(child, "reg");
|
||||||
|
|
||||||
|
/* No error if we have any non-zero unit address */
|
||||||
|
if (prop && propval_cell(prop) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt == 1 && node->addr_cells != -1)
|
||||||
|
FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
|
||||||
|
node->children->name);
|
||||||
|
}
|
||||||
|
WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes);
|
||||||
|
|
||||||
|
static void check_graph_reg(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
char unit_addr[9];
|
||||||
|
const char *unitname = get_unitname(node);
|
||||||
|
struct property *prop;
|
||||||
|
|
||||||
|
prop = get_property(node, "reg");
|
||||||
|
if (!prop || !unitname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(prop->val.val && prop->val.len == sizeof(cell_t))) {
|
||||||
|
FAIL(c, dti, node, "graph node malformed 'reg' property");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(unit_addr, sizeof(unit_addr), "%x", propval_cell(prop));
|
||||||
|
if (!streq(unitname, unit_addr))
|
||||||
|
FAIL(c, dti, node, "graph node unit address error, expected \"%s\"",
|
||||||
|
unit_addr);
|
||||||
|
|
||||||
|
if (node->parent->addr_cells != 1)
|
||||||
|
FAIL_PROP(c, dti, node, get_property(node, "#address-cells"),
|
||||||
|
"graph node '#address-cells' is %d, must be 1",
|
||||||
|
node->parent->addr_cells);
|
||||||
|
if (node->parent->size_cells != 0)
|
||||||
|
FAIL_PROP(c, dti, node, get_property(node, "#size-cells"),
|
||||||
|
"graph node '#size-cells' is %d, must be 0",
|
||||||
|
node->parent->size_cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_graph_port(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
if (node->bus != &graph_port_bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strprefixeq(node->name, node->basenamelen, "port"))
|
||||||
|
FAIL(c, dti, node, "graph port node name should be 'port'");
|
||||||
|
|
||||||
|
check_graph_reg(c, dti, node);
|
||||||
|
}
|
||||||
|
WARNING(graph_port, check_graph_port, NULL, &graph_nodes);
|
||||||
|
|
||||||
|
static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *endpoint)
|
||||||
|
{
|
||||||
|
int phandle;
|
||||||
|
struct node *node;
|
||||||
|
struct property *prop;
|
||||||
|
|
||||||
|
prop = get_property(endpoint, "remote-endpoint");
|
||||||
|
if (!prop)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
phandle = propval_cell(prop);
|
||||||
|
/* Give up if this is an overlay with external references */
|
||||||
|
if (phandle == 0 || phandle == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = get_node_by_phandle(dti->dt, phandle);
|
||||||
|
if (!node)
|
||||||
|
FAIL_PROP(c, dti, endpoint, prop, "graph phandle is not valid");
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_graph_endpoint(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
struct node *remote_node;
|
||||||
|
|
||||||
|
if (!node->parent || node->parent->bus != &graph_port_bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
|
||||||
|
FAIL(c, dti, node, "graph endpont node name should be 'endpoint'");
|
||||||
|
|
||||||
|
check_graph_reg(c, dti, node);
|
||||||
|
|
||||||
|
remote_node = get_remote_endpoint(c, dti, node);
|
||||||
|
if (!remote_node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (get_remote_endpoint(c, dti, remote_node) != node)
|
||||||
|
FAIL(c, dti, node, "graph connection to node '%s' is not bidirectional",
|
||||||
|
remote_node->fullpath);
|
||||||
|
}
|
||||||
|
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
|
||||||
|
|
||||||
static struct check *check_table[] = {
|
static struct check *check_table[] = {
|
||||||
&duplicate_node_names, &duplicate_property_names,
|
&duplicate_node_names, &duplicate_property_names,
|
||||||
&node_name_chars, &node_name_format, &property_name_chars,
|
&node_name_chars, &node_name_format, &property_name_chars,
|
||||||
|
@ -1453,6 +1599,8 @@ static struct check *check_table[] = {
|
||||||
|
|
||||||
&alias_paths,
|
&alias_paths,
|
||||||
|
|
||||||
|
&graph_nodes, &graph_child_address, &graph_port, &graph_endpoint,
|
||||||
|
|
||||||
&always_fail,
|
&always_fail,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
bad_endpoint: port-a@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
endpoint@d0 {
|
||||||
|
reg = <0>;
|
||||||
|
remote-endpoint = <0xdeadbeef>;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -599,6 +599,9 @@ dtc_tests () {
|
||||||
check_tests unit-addr-unique.dts unique_unit_address
|
check_tests unit-addr-unique.dts unique_unit_address
|
||||||
check_tests bad-phandle-cells.dts interrupts_extended_property
|
check_tests bad-phandle-cells.dts interrupts_extended_property
|
||||||
check_tests bad-gpio.dts gpios_property
|
check_tests bad-gpio.dts gpios_property
|
||||||
|
check_tests bad-graph.dts graph_child_address
|
||||||
|
check_tests bad-graph.dts graph_port
|
||||||
|
check_tests bad-graph.dts graph_endpoint
|
||||||
run_sh_test dtc-checkfails.sh deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb bad-gpio.dts
|
run_sh_test dtc-checkfails.sh deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb bad-gpio.dts
|
||||||
check_tests bad-interrupt-cells.dts interrupts_property
|
check_tests bad-interrupt-cells.dts interrupts_property
|
||||||
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_chars -- -I dtb -O dtb bad_node_char.dtb
|
||||||
|
|
Loading…
Reference in New Issue