[PATCH v9 22/37] drivers: misc: irq-uclass: Update irq_get_by_index

Moritz Fischer moritzf at google.com
Wed Oct 16 22:10:22 CEST 2024


On Tue, Oct 15, 2024 at 11:16 PM Patrick Rudolph
<patrick.rudolph at 9elements.com> wrote:
>
> Support reading the "interrupts" property from the devicetree in case
> the "interrupts-extended" property isn't found. As the "interrupts"
> property is commonly used, this allows to parse all existing FDT and
> makes irq_get_by_index() more useful.
>
> The "interrupts" property doesn't contain a phandle as "interrupts-extended"
> does, so implement a new method to locate the interrupt-parent called
> irq_get_interrupt_parent().
>
> TEST: Read the interrupts from the GIC node for ACPI MADT generation.
>
> Signed-off-by: Patrick Rudolph <patrick.rudolph at 9elements.com>
Reviewed-by: Moritz Fischer <moritzf at google.com>
> ---
> Changelog v9:
> - Read interrupt-cells from interrupt parent
> ---
>  arch/sandbox/dts/test.dts |  3 ++
>  drivers/misc/irq-uclass.c | 66 ++++++++++++++++++++++++++++++++++++++-
>  include/irq.h             | 14 +++++++++
>  test/dm/irq.c             | 15 +++++++++
>  4 files changed, 97 insertions(+), 1 deletion(-)
>
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 8412506c17..9599a8db9c 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -522,6 +522,9 @@
>         };
>
>         f-test {
> +               #interrupt-cells = <2>;
> +               interrupt-parent = <&irq>;
> +               interrupts = <4 0>;
>                 compatible = "denx,u-boot-fdt-test";
>         };
>
> diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
> index 79eb7c200d..ac778593c9 100644
> --- a/drivers/misc/irq-uclass.c
> +++ b/drivers/misc/irq-uclass.c
> @@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
>         return ops->read_and_clear(irq);
>  }
>
> +int irq_get_interrupt_parent(const struct udevice *dev,
> +                            struct udevice **interrupt_parent)
> +{
> +       struct ofnode_phandle_args phandle_args;
> +       struct udevice *irq = NULL;
> +       ofnode node;
> +       int ret;
> +
> +       if (!dev || !interrupt_parent)
> +               return -EINVAL;
> +
> +       *interrupt_parent = NULL;
> +
> +       node = dev_ofnode(dev);
> +       if (!ofnode_valid(node))
> +               return -EINVAL;
> +
> +       while (ofnode_valid(node)) {
> +               ret = ofnode_parse_phandle_with_args(node, "interrupt-parent",
> +                                                    NULL, 0, 0, &phandle_args);
> +               if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq))
> +                       break;
> +               node = ofnode_get_parent(node);
> +       }
> +
> +       if (!irq) {
> +               log_err("Cannot find an interrupt parent for device %s\n", dev->name);
> +               return -ENODEV;
> +       }
> +       *interrupt_parent = irq;
> +
> +       return 0;
> +}
> +
>  #if CONFIG_IS_ENABLED(OF_PLATDATA)
>  int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
>                        struct irq *irq)
> @@ -142,10 +176,40 @@ err:
>  int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
>  {
>         struct ofnode_phandle_args args;
> -       int ret;
> +       struct udevice *interrupt_parent;
> +       int ret, size, i;
> +       const __be32 *list;
> +       u32 count;
>
>         ret = dev_read_phandle_with_args(dev, "interrupts-extended",
>                                          "#interrupt-cells", 0, index, &args);
> +       if (ret) {
> +               list = dev_read_prop(dev, "interrupts", &size);
> +               if (!list)
> +                       return -ENOENT;
> +
> +               ret = irq_get_interrupt_parent(dev, &interrupt_parent);
> +               if (ret)
> +                       return -ENODEV;
> +               args.node = dev_ofnode(interrupt_parent);
> +
> +               if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) {
> +                       log_err("%s: could not get #interrupt-cells for %s\n",
> +                               __func__, dev->name);
> +                       return -ENOENT;
> +               }
> +
> +               if (index * count >= size / sizeof(*list))
> +                       return -ENOENT;
> +               if (count > OF_MAX_PHANDLE_ARGS)
> +                       count = OF_MAX_PHANDLE_ARGS;
> +               args.args_count = count;
> +               for (i = 0; i < count; i++)
> +                       args.args[i] = be32_to_cpup(&list[index * count + i]);
> +
> +               return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
> +                                            "interrupts", index, irq);
> +       }
>
>         return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
>                                      "interrupts-extended", index > 0, irq);
> diff --git a/include/irq.h b/include/irq.h
> index 5638c10128..0fbc1a5f48 100644
> --- a/include/irq.h
> +++ b/include/irq.h
> @@ -200,6 +200,20 @@ int irq_restore_polarities(struct udevice *dev);
>   */
>  int irq_read_and_clear(struct irq *irq);
>
> +/**
> + * irq_get_interrupt_parent() - returns the interrupt parent
> + *
> + * Walks the devicetree and returns the interrupt parent's ofnode
> + * for the specified device.
> + *
> + * @dev: device
> + * @interrupt_parent: The interrupt parent's ofnode'
> + * Return: 0 success, or error value
> + *
> + */
> +int irq_get_interrupt_parent(const struct udevice *dev,
> +                            struct udevice **interrupt_parent);
> +
>  struct phandle_2_arg;
>  /**
>   * irq_get_by_phandle() - Get an irq by its phandle information (of-platadata)
> diff --git a/test/dm/irq.c b/test/dm/irq.c
> index 836f2d82e7..ca3e188065 100644
> --- a/test/dm/irq.c
> +++ b/test/dm/irq.c
> @@ -76,6 +76,21 @@ static int dm_test_request(struct unit_test_state *uts)
>  }
>  DM_TEST(dm_test_request, UTF_SCAN_PDATA | UTF_SCAN_FDT);
>
> +/* Test of irq_get_by_index() */
> +static int dm_test_irq_get_by_index(struct unit_test_state *uts)
> +{
> +       struct udevice *dev;
> +       struct irq irq;
> +
> +       ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "f-test",
> +                                             &dev));
> +       ut_assertok(irq_get_by_index(dev, 0, &irq));
> +       ut_asserteq(4, irq.id);
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_irq_get_by_index, UTF_SCAN_PDATA | UTF_SCAN_FDT);
> +
>  /* Test of irq_get_acpi() */
>  static int dm_test_irq_get_acpi(struct unit_test_state *uts)
>  {
> --
> 2.46.2
>


More information about the U-Boot mailing list