Re: [RFC PATCH 2/2] checks: interrupt-map: Dump entries on error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



On Wed, May 13, 2020 at 11:35 AM Andre Przywara <andre.przywara@xxxxxxx> wrote:
>
> 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, &reg_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);

Printing like this doesn't work well when you have parallel calls to
dtc. You have to print everything to a buffer and then write the
buffer to stderr in one call.

> +}
> +
> +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
>



[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux