Browse Source

checks: Add an interrupt-map check

Add a check for parsing 'interrupt-map' properties. The check primarily
tests parsing 'interrupt-map' properties which depends on and the parent
interrupt controller (or another map) node.

Note that this does not require '#address-cells' in the interrupt-map
parent, but treats missing '#address-cells' as 0 which is how the Linux
kernel parses it. There's numerous cases that expect this behavior.

Cc: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Message-Id: <20211015213527.2237774-1-robh@kernel.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
main
Rob Herring 3 years ago committed by David Gibson
parent
commit
0a3a9d3449
  1. 85
      checks.c
  2. 20
      tests/bad-interrupt-map-mask.dts
  3. 17
      tests/bad-interrupt-map-parent.dts
  4. 19
      tests/bad-interrupt-map.dts
  5. 3
      tests/run_tests.sh

85
checks.c

@ -1590,6 +1590,90 @@ static void check_interrupt_provider(struct check *c,
} }
WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell);


static void check_interrupt_map(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct node *root = dti->dt;
struct property *prop, *irq_map_prop;
size_t cellsize, cell, map_cells;

irq_map_prop = get_property(node, "interrupt-map");
if (!irq_map_prop)
return;

if (node->addr_cells < 0) {
FAIL(c, dti, node,
"Missing '#address-cells' in interrupt-map provider");
return;
}
cellsize = node_addr_cells(node);
cellsize += propval_cell(get_property(node, "#interrupt-cells"));

prop = get_property(node, "interrupt-map-mask");
if (prop && (prop->val.len != (cellsize * sizeof(cell_t))))
FAIL_PROP(c, dti, node, prop,
"property size (%d) is invalid, expected %zu",
prop->val.len, cellsize * sizeof(cell_t));

if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) {
FAIL_PROP(c, dti, node, irq_map_prop,
"property size (%d) is invalid, expected multiple of %zu",
irq_map_prop->val.len, sizeof(cell_t));
return;
}

map_cells = irq_map_prop->val.len / sizeof(cell_t);
for (cell = 0; cell < map_cells; ) {
struct node *provider_node;
struct property *cellprop;
int phandle;
size_t parent_cellsize;

if ((cell + cellsize) >= map_cells) {
FAIL_PROP(c, dti, node, irq_map_prop,
"property size (%d) too small, expected > %zu",
irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t));
break;
}
cell += cellsize;

phandle = propval_cell_n(irq_map_prop, cell);
if (!phandle_is_valid(phandle)) {
/* Give up if this is an overlay with external references */
if (!(dti->dtsflags & DTSF_PLUGIN))
FAIL_PROP(c, dti, node, irq_map_prop,
"Cell %zu is not a phandle(%d)",
cell, phandle);
break;
}

provider_node = get_node_by_phandle(root, phandle);
if (!provider_node) {
FAIL_PROP(c, dti, node, irq_map_prop,
"Could not get phandle(%d) node for (cell %zu)",
phandle, cell);
break;
}

cellprop = get_property(provider_node, "#interrupt-cells");
if (cellprop) {
parent_cellsize = propval_cell(cellprop);
} else {
FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])",
provider_node->fullpath, cell);
break;
}

cellprop = get_property(provider_node, "#address-cells");
if (cellprop)
parent_cellsize += propval_cell(cellprop);

cell += 1 + parent_cellsize;
}
}
WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider);

static void check_interrupts_property(struct check *c, static void check_interrupts_property(struct check *c,
struct dt_info *dti, struct dt_info *dti,
struct node *node) struct node *node)
@ -1888,6 +1972,7 @@ static struct check *check_table[] = {
&gpios_property, &gpios_property,
&interrupts_property, &interrupts_property,
&interrupt_provider, &interrupt_provider,
&interrupt_map,


&alias_paths, &alias_paths,



20
tests/bad-interrupt-map-mask.dts

@ -0,0 +1,20 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
interrupt-controller;
};

node {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;
interrupt-map-mask = <0 0>;

child {
interrupts = <1>;
};
};
};

17
tests/bad-interrupt-map-parent.dts

@ -0,0 +1,17 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
};

node {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;

child {
interrupts = <1>;
};
};
};

19
tests/bad-interrupt-map.dts

@ -0,0 +1,19 @@
/dts-v1/;

/ {
interrupt-parent = <&intc>;
intc: interrupt-controller {
#interrupt-cells = <3>;
interrupt-controller;
};

node {
/* Missing #address-cells = <0>; */
#interrupt-cells = <1>;
interrupt-map = <1 &intc 1 2 3>;

child {
interrupts = <1>;
};
};
};

3
tests/run_tests.sh

@ -717,6 +717,9 @@ dtc_tests () {
run_sh_test "$SRCDIR/dtc-checkfails.sh" -n deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/good-gpio.dts" run_sh_test "$SRCDIR/dtc-checkfails.sh" -n deprecated_gpio_property -- -Wdeprecated_gpio_property -I dts -O dtb "$SRCDIR/good-gpio.dts"
check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property check_tests "$SRCDIR/bad-interrupt-cells.dts" interrupts_property
check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider check_tests "$SRCDIR/bad-interrupt-controller.dts" interrupt_provider
check_tests "$SRCDIR/bad-interrupt-map.dts" interrupt_map
check_tests "$SRCDIR/bad-interrupt-map-parent.dts" interrupt_map
check_tests "$SRCDIR/bad-interrupt-map-mask.dts" interrupt_map
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_chars -- -I dtb -O dtb bad_node_char.dtb
run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb run_sh_test "$SRCDIR/dtc-checkfails.sh" node_name_format -- -I dtb -O dtb bad_node_format.dtb
run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb run_sh_test "$SRCDIR/dtc-checkfails.sh" property_name_chars -- -I dtb -O dtb bad_prop_char.dtb

Loading…
Cancel
Save