[PATCH 5.10.y-cip 15/28] of/irq: Allow matching of an interrupt-map local to an interrupt controller

Claudiu
2026-03-11T11:04:29Z

From: Marc Zyngier <maz@kernel.org>

commit c12346543a7850d20ff70923ce12b60ef81a8416 upstream.

of_irq_parse_raw() has a baked assumption that if a node has an
interrupt-controller property, it cannot possibly also have an
interrupt-map property (the latter being ignored).

This seems to be an odd behaviour, and there is no reason why we should
avoid supporting this use case. This is specially useful when a PCI root
port acts as an interrupt controller for PCI endpoints, such as this:

pcie0: pcie@690000000 {
[...]
port00: pci@0,0 {
device_type = "pci";
[...]
#address-cells = <3>;

interrupt-controller;
#interrupt-cells = <1>;

interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
<0 0 0 2 &port00 0 0 0 1>,
<0 0 0 3 &port00 0 0 0 2>,
<0 0 0 4 &port00 0 0 0 3>;
};
};

Handle it by detecting that we have an interrupt-map early in the parsing,
and special case the situation where the phandle in the interrupt map
refers to the current node (which is the interesting case here).

Link: https://lore.kernel.org/r/20210929163847.2807812-3-maz@kernel.org
Tested-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
[claudiu.beznea: made the code in this patch be executable only for the
Renesas RZ/G3S SoC]
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
drivers/of/irq.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index fe88a23240f5..691e72598f70 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -102,6 +102,14 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
int imaplen, match, i, rc = -EINVAL;
+ static const char * const renesas_socs[] = {
+ "renesas,r9a08g045", /* Renesas RZ/G3S */
+ NULL
+ };
+ bool renesas = false;
+
+ if (of_machine_compatible_match(renesas_socs))
+ renesas = true;

#ifdef DEBUG
of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -160,12 +168,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)

/* Now start the actual "proper" walk of the interrupt tree */
while (ipar != NULL) {
- /* Now check if cursor is an interrupt-controller and if it is
- * then we are done
+ /*
+ * Now check if cursor is an interrupt-controller and
+ * if it is then we are done, unless there is an
+ * interrupt-map which takes precedence.
*/
+ imap = of_get_property(ipar, "interrupt-map", &imaplen);
if (of_property_read_bool(ipar, "interrupt-controller")) {
- pr_debug(" -> got it !\n");
- return 0;
+ if ((renesas && !imap) || !renesas) {
+ pr_debug(" -> got it !\n");
+ return 0;
+ }
}

/*
@@ -177,8 +190,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
goto fail;
}

- /* Now look for an interrupt-map */
- imap = of_get_property(ipar, "interrupt-map", &imaplen);
/* No interrupt map, check for an interrupt parent */
if (imap == NULL) {
pr_debug(" -> no map, getting parent\n");
@@ -259,6 +270,13 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
out_irq->args_count = intsize = newintsize;
addrsize = newaddrsize;

+ if (renesas) {
+ if (ipar == newpar) {
+ pr_debug("%pOF interrupt-map entry to self\n", ipar);
+ return 0;
+ }
+ }
+
skiplevel:
/* Iterate again with new parent */
out_irq->np = newpar;
--
2.43.0