While the interrupt-map property is now validated, the current error messages will probably leave people scratching their head on what the actual problem is. To help with the diagnosis, dump the map property formatted in a way that corresponds to the actual interpretation from an IRQ consumer's point of view. While this can't pinpoint the actual problem, it's much easier to see what went wrong, especially when comparing it to the .dts source. As this will generate one line per mapped interrupt, it can be potentially long on those larger maps. A report would look like this: Warning (interrupt_map): /soc/pci@1c00000:interrupt-map: invalid phandle for interrupt-map entry < <0x0 0x0 0x0>, <0x1>, <&gic@17a00000>, <0x0>, <0x87 0x4 0x0> >, < <0x0 0x0 0x2>, <0x1>, <&invalid>, > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> --- checks.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/checks.c b/checks.c index 12518db..5a63c20 100644 --- a/checks.c +++ b/checks.c @@ -924,6 +924,80 @@ 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, &pci_bridge); +static void dump_cell_group(struct property *prop, int index, int cells, + int nr_cells) +{ + int limit, i; + + if (index + cells > nr_cells) + limit = nr_cells - index; + else + limit = cells; + + fputs("<", stderr); + for (i = 0; i < limit; i++) { + cell_t v = propval_cell_n(prop, index + i); + fprintf(stderr, "%s0x%x", i == 0 ? "" : " ", v); + } + if (limit < cells) + fputs(", MISSING", stderr); + fputs(">", stderr); +} + +static void dump_interrupt_map(struct node *root, struct node *nexus, + struct property *map, int irq_cells) +{ + int cells = map->val.len / 4; + struct property *prop; + int value; + int i; + + for (i = 0; i < cells;) { + struct node *intc = NULL; + + fprintf(stderr, "%s\t< ", i == 0 ? "" : ",\n"); + dump_cell_group(map, i, node_addr_cells(nexus), cells); + fputs(", ", stderr); + dump_cell_group(map, i + node_addr_cells(nexus), irq_cells, cells); + fputs(", <&", stderr); + i += node_addr_cells(nexus) + irq_cells; + if (i >= cells) + break; + value = propval_cell_n(map, i); + if (value != 0) + intc = get_node_by_phandle(root, value); + fprintf(stderr, "%s>, ", + intc && intc->name ? intc->name : "invalid"); + if (!intc) { + fprintf(stderr, ">\n"); + return; + } + /* + * Linux treats non-existing #address-cells in the interrupt + * parent as 0 (and not 2, as the spec says). + * Deal with that, since many DTs rely on that. + */ + prop = get_property(intc, "#address-cells"); + if (prop) + value = propval_cell(prop); + else + value = 0; + dump_cell_group(map, i + 1, value, cells); + fputs(", ", stderr); + i += 1 + value; + + prop = get_property(intc, "#interrupt-cells"); + if (prop) { + value = propval_cell(prop); + dump_cell_group(map, i, value, cells); + } else + fputs("<?>", stderr); + fputs(" >", stderr); + i += value; + } + fputs("\n", stderr); +} + static void check_interrupt_map(struct check *c, struct dt_info *dti, struct node *node) { @@ -956,6 +1030,7 @@ static void check_interrupt_map(struct check *c, struct dt_info *dti, if (phandle_idx + 1 >= cells) { FAIL_PROP(c, dti, node, map, "insufficient cells for interrupt-map entry"); + dump_interrupt_map(dti->dt, node, map, irq_cells); return; } intc_phandle = propval_cell_n(map, phandle_idx); @@ -965,6 +1040,7 @@ static void check_interrupt_map(struct check *c, struct dt_info *dti, if (!intc) { FAIL_PROP(c, dti, node, map, "invalid phandle for interrupt-map entry"); + dump_interrupt_map(dti->dt, node, map, irq_cells); return; } @@ -972,6 +1048,7 @@ static void check_interrupt_map(struct check *c, struct dt_info *dti, if (!prop) { FAIL_PROP(c,dti, node, map, "interrupt-map phandle does not point to interrupt controller"); + dump_interrupt_map(dti->dt, node, map, irq_cells); return; } @@ -994,6 +1071,7 @@ static void check_interrupt_map(struct check *c, struct dt_info *dti, if (!prop) { FAIL_PROP(c,dti, node, map, "interrupt-controller misses #interrupt-cells property"); + dump_interrupt_map(dti->dt, node, map, irq_cells); return; } intc_irq_cells = propval_cell(prop); @@ -1001,6 +1079,7 @@ static void check_interrupt_map(struct check *c, struct dt_info *dti, if (phandle_idx + intc_addr_cells + intc_irq_cells >= cells) { FAIL_PROP(c, dti, node, map, "insufficient cells for interrupt-map entry"); + dump_interrupt_map(dti->dt, node, map, irq_cells); return; } i = phandle_idx + 1 + intc_addr_cells + intc_irq_cells; -- 2.14.1