From nobody Mon Jun 29 05:22:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82E77C43219 for ; Mon, 14 Feb 2022 20:57:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229926AbiBNU5K (ORCPT ); Mon, 14 Feb 2022 15:57:10 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:43156 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229556AbiBNU4u (ORCPT ); Mon, 14 Feb 2022 15:56:50 -0500 Received: from polaris.svanheule.net (polaris.svanheule.net [84.16.241.116]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CE0BB1342E6 for ; Mon, 14 Feb 2022 12:56:25 -0800 (PST) Received: from terra.local.svanheule.net (104.153-136-217.adsl-dyn.isp.belgacom.be [217.136.153.104]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sander@svanheule.net) by polaris.svanheule.net (Postfix) with ESMTPSA id A555A2A25FA; Mon, 14 Feb 2022 19:57:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1644865026; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+86Lva2nWXdctV7renNiPdMAVhU1O2KM95YNgJd594E=; b=eOC++pB2oI/36x0RFPblsMEWhenygKKH7fBA/mDP3V7yTUMQZUX3CbpJwuZEfr5WhglQTF FNSJjmIxDFa7/kmOSXBLwLKu06K2gs6sa/tUJQuPr/cGEQrLXKsGrlLfJ8EYsrLijZIkDE 9DZK+OBDnJvFMx5Ro/aaGumdb+EQMJI+OiUd1oUj5BRo/DWafP4q7o8aTM2ejh/6OS+/w7 JW5VqdDik5TjKlc5ATsVYqXEv2Qboo39h0FwYK4K1DpxhG98RyzIO4PC6wtYi22qCLL/Gm RUIExlTKvzMFnEWkoHIqhBsHuo8HTCrrbpUrSu0V6I+SEvnyOFWuBfDcsILTkA== From: Sander Vanheule To: Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Thomas Gleixner , Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [PATCH v5 1/4] irqchip/realtek-rtl: use irq_domain_add_linear Date: Mon, 14 Feb 2022 19:56:58 +0100 Message-Id: X-Mailer: git-send-email 2.35.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" When using an offset of 0, irq_domain_add_simple is identical to irq_domain_add_linear on DT-based systems, so use the latter instead. Signed-off-by: Sander Vanheule --- drivers/irqchip/irq-realtek-rtl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realte= k-rtl.c index 50a56820c99b..14e049eed0f2 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -171,8 +171,7 @@ static int __init realtek_rtl_of_init(struct device_nod= e *node, struct device_no /* Disable all cascaded interrupts */ writel(0, REG(RTL_ICTL_GIMR)); =20 - domain =3D irq_domain_add_simple(node, 32, 0, - &irq_domain_ops, NULL); + domain =3D irq_domain_add_linear(node, 32, &irq_domain_ops, NULL); =20 ret =3D map_interrupts(node, domain); if (ret) { --=20 2.35.1 From nobody Mon Jun 29 05:22:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05881C433F5 for ; Mon, 14 Feb 2022 21:36:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231489AbiBNVgZ (ORCPT ); Mon, 14 Feb 2022 16:36:25 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:43862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231491AbiBNVgF (ORCPT ); Mon, 14 Feb 2022 16:36:05 -0500 Received: from polaris.svanheule.net (polaris.svanheule.net [84.16.241.116]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BDA2BBC8E for ; Mon, 14 Feb 2022 13:35:48 -0800 (PST) Received: from terra.local.svanheule.net (104.153-136-217.adsl-dyn.isp.belgacom.be [217.136.153.104]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sander@svanheule.net) by polaris.svanheule.net (Postfix) with ESMTPSA id 670EF2A25FB; Mon, 14 Feb 2022 19:57:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1644865027; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NWlSj3jND0Xw2BaE2cX6gEUMtrMa1vlnKfokepbt1e4=; b=nXya5L0GgmhPE3+2pHiO94UCKR06POE2QGOtaucxne1rk7/Dx31b5OCoUmJ8qM26bwgdac 7m/se8DraRuXQfA44Cs0Kjni1yI9RY1WgJ99pj1NtQLbA60aUxXetFzbki15AIX9i4f/L+ rp7cDSm91ob60+QBUq8DYh46/UX0ZWKxkyT+unmgbqPW89R28p2QDm+9HxrP97osL4ViMR AP3bqW41Etfad7dPg/WaetQjDJcusPyP8GRvRWlwHPW+jwICJrqlTFgTQn9kLTWqTIBsZb B6r5YslRtqIQW/AfuFKVLmZsRGxziF6nd3B1by0omI0JWdkRAWC0vmiSqj/Huw== From: Sander Vanheule To: Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Thomas Gleixner , Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule , Rob Herring Subject: [PATCH v5 2/4] dt-bindings: interrupt-controller: realtek,rtl-intc: require parents Date: Mon, 14 Feb 2022 19:56:59 +0100 Message-Id: X-Mailer: git-send-email 2.35.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The interrupt router has 32 inputs, and up to 15 outputs connected to the MIPS CPU's interrupts. The way these are mapped to each other is runtime configurable. This controller can also mask individual interrupt sources, and has a status register to indicate pending interrupts. This means the controller is not transparent, and the use of "interrupt-map" inappropriate. Instead, a list of parent interrupts should be specified. Two-part compatibles are introduced to be able to require "interrupts" for new devicetrees. The relevant descriptions are extended or added to more clearly describe the functionality of this controller. The old compatible, with "interrupt-map" and "#address-cells", is deprecated. Interrupt specifiers for new compatibles will require two cells, to indicate the output selection. To prevent spurious changes to the binding when more SoCs are added, "allOf" is used with one "if", and the compatible enum only has one item. The example is updated to provide a correct example for RTL8380 SoCs. Signed-off-by: Sander Vanheule Reviewed-by: Rob Herring --- Changes in v5: - Add Rob's Reviewed-by Changes in v4: - Indicate more clearly that the controller is not transparent. .../realtek,rtl-intc.yaml | 82 ++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek= ,rtl-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/rea= ltek,rtl-intc.yaml index 9e76fff20323..f212962afd62 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-in= tc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-in= tc.yaml @@ -6,6 +6,14 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# =20 title: Realtek RTL SoC interrupt controller devicetree bindings =20 +description: + Interrupt controller and router for Realtek MIPS SoCs, allowing each SoC + interrupt to be routed to one parent CPU (hardware) interrupt, or left + disconnected. + All connected input lines from SoC peripherals can be masked individuall= y, + and an interrupt status register is present to indicate which interrupts= are + pending. + maintainers: - Birger Koblitz - Bert Vermeulen @@ -13,45 +21,79 @@ maintainers: =20 properties: compatible: - const: realtek,rtl-intc + oneOf: + - items: + - enum: + - realtek,rtl8380-intc + - const: realtek,rtl-intc + - const: realtek,rtl-intc + deprecated: true =20 - "#interrupt-cells": - const: 1 + "#interrupt-cells": true =20 reg: maxItems: 1 =20 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 15 + description: + List of parent interrupts, in the order that they are connected to t= his + interrupt router's outputs. =20 interrupt-controller: true =20 - "#address-cells": - const: 0 - - interrupt-map: - description: Describes mapping from SoC interrupts to CPU interrupts - required: - compatible - reg - "#interrupt-cells" - interrupt-controller - - "#address-cells" - - interrupt-map + +allOf: + - if: + properties: + compatible: + const: realtek,rtl-intc + then: + properties: + "#interrupt-cells": + const: 1 + + "#address-cells": + const: 0 + + interrupt-map: true + required: + - "#address-cells" + - interrupt-map + else: + properties: + "#interrupt-cells": + description: + Two cells to specify which line to connect to, and which outpu= t it should + be routed to. Both cells use a zero-based index. + const: 2 + required: + - interrupts =20 additionalProperties: false =20 examples: - | intc: interrupt-controller@3000 { - compatible =3D "realtek,rtl-intc"; - #interrupt-cells =3D <1>; + compatible =3D "realtek,rtl8380-intc", "realtek,rtl-intc"; + #interrupt-cells =3D <2>; interrupt-controller; - reg =3D <0x3000 0x20>; - #address-cells =3D <0>; - interrupt-map =3D - <31 &cpuintc 2>, - <30 &cpuintc 1>, - <29 &cpuintc 5>; + reg =3D <0x3000 0x18>; + + interrupt-parent =3D <&cpuintc>; + interrupts =3D <2>, <3>, <4>, <5>, <6>; + }; + + irq-consumer@0 { + reg =3D <0 4>; + interrupt-parent =3D <&intc>; + interrupts =3D + <19 3>, /* IRQ 19, routed to output 3 (cpuintc 5) */ + <18 4>; /* IRQ 18, routed to output 4 (cpuintc 6) */ }; --=20 2.35.1 From nobody Mon Jun 29 05:22:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 648ABC433F5 for ; Mon, 14 Feb 2022 20:56:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229793AbiBNU43 (ORCPT ); Mon, 14 Feb 2022 15:56:29 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229802AbiBNU4W (ORCPT ); Mon, 14 Feb 2022 15:56:22 -0500 Received: from polaris.svanheule.net (polaris.svanheule.net [IPv6:2a00:c98:2060:a004:1::200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E9BB10781F for ; Mon, 14 Feb 2022 12:56:01 -0800 (PST) Received: from terra.local.svanheule.net (104.153-136-217.adsl-dyn.isp.belgacom.be [217.136.153.104]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sander@svanheule.net) by polaris.svanheule.net (Postfix) with ESMTPSA id D3FCA2A25FC; Mon, 14 Feb 2022 19:57:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1644865028; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YgNeTAxbgrC315MC1Jy5FCAajTIfZfPRjFdqJmtvvKY=; b=HN66mIkyyFsyVscl1o8gJyjO8eWD2hnaTwsJXHwZ7+ZHTwAJmoYuNj1H+C9s4+uAPLZBOH g25lPkv4buqJC8bNbUm+UssFwL6JvaxfUTBITi/uZuNj2dT5ggI8JsATC4JEudjgjVLVch YvMtUYweOZQ2TfdQ85efdWHA8TGZsXiWpRG55+maducZXNuNbpOR3ICNIA61a3No4TaKGZ BdnKA2mHhbKs09/WReffUUqHWWoHFY9QNrnfuN3Rvoy4U3W0b7h2NIqNg/Kg+WSC3o06N/ SarAxqUoNFvKTCB+x9TZM47wGqd3BX/M8wFUcZTFUnktA6DO21l3i+30KFodOg== From: Sander Vanheule To: Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Thomas Gleixner , Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [PATCH v5 3/4] irqchip/realtek-rtl: use parent interrupts Date: Mon, 14 Feb 2022 19:57:00 +0100 Message-Id: <6484523d69a41e262a7c2d8bac76d31e189cdcbc.1644864700.git.sander@svanheule.net> X-Mailer: git-send-email 2.35.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The interrupt-map property for "realtek,rtl-intc" has been deprecated in favor of a list of parent interrupts. Drop the open-coded parser for interrupt-map, and use the first parent interrupt instead. If no parent was provided, the driver will assume that this is the first hardware interrupt of the SoC's MIPS CPU. All SoC interrupts were treated equally, independent of which output they were actually routed to. This means the driver might as well route all interrupts to the first output, and achieve the same behaviour. Without the interrupt-map property, interrupt routing information is no longer available at initialisation. Routing setup will now happen later, when a hardware interrupt is mapped by the subsystem. Signed-off-by: Sander Vanheule --- Changes since v4: - Use irq_domain_add_linear instead of irq_domain_add_simple - Drop 'inline' specifiers from static functions drivers/irqchip/irq-realtek-rtl.c | 133 ++++++++++++++---------------- 1 file changed, 61 insertions(+), 72 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realte= k-rtl.c index 14e049eed0f2..2a349082af81 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -21,11 +21,33 @@ #define RTL_ICTL_IRR2 0x10 #define RTL_ICTL_IRR3 0x14 =20 +#define RTL_ICTL_NUM_INPUTS 32 + #define REG(x) (realtek_ictl_base + x) =20 static DEFINE_RAW_SPINLOCK(irq_lock); static void __iomem *realtek_ictl_base; =20 +/* + * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numberi= ng, + * placing IRQ 31 in the first four bits. A routing value of '0' means the + * interrupt is left disconnected. Routing values {1..15} connect to output + * lines {0..14}. + */ +#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32)) +#define IRR_SHIFT(idx) ((idx * 4) % 32) + +static void write_irr(void __iomem *irr0, int idx, u32 value) +{ + unsigned int offset =3D IRR_OFFSET(idx); + unsigned int shift =3D IRR_SHIFT(idx); + u32 irr; + + irr =3D readl(irr0 + offset) & ~(0xf << shift); + irr |=3D (value & 0xf) << shift; + writel(irr, irr0 + offset); +} + static void realtek_ictl_unmask_irq(struct irq_data *i) { unsigned long flags; @@ -62,8 +84,14 @@ static struct irq_chip realtek_ictl_irq =3D { =20 static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_= t hw) { + unsigned long flags; + irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq); =20 + raw_spin_lock_irqsave(&irq_lock, flags); + write_irr(REG(RTL_ICTL_IRR0), hw, 1); + raw_spin_unlock_irqrestore(&irq_lock, flags); + return 0; } =20 @@ -95,89 +123,50 @@ static void realtek_irq_dispatch(struct irq_desc *desc) chained_irq_exit(chip, desc); } =20 -/* - * SoC interrupts are cascaded to MIPS CPU interrupts according to the - * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for - * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrup= ts - * thus go into 4 IRRs. A routing value of '0' means the interrupt is left - * disconnected. Routing values {1..15} connect to output lines {0..14}. - */ -static int __init map_interrupts(struct device_node *node, struct irq_doma= in *domain) -{ - struct device_node *cpu_ictl; - const __be32 *imap; - u32 imaplen, soc_int, cpu_int, tmp, regs[4]; - int ret, i, irr_regs[] =3D { - RTL_ICTL_IRR3, - RTL_ICTL_IRR2, - RTL_ICTL_IRR1, - RTL_ICTL_IRR0, - }; - u8 mips_irqs_set; - - ret =3D of_property_read_u32(node, "#address-cells", &tmp); - if (ret || tmp) - return -EINVAL; - - imap =3D of_get_property(node, "interrupt-map", &imaplen); - if (!imap || imaplen % 3) - return -EINVAL; - - mips_irqs_set =3D 0; - memset(regs, 0, sizeof(regs)); - for (i =3D 0; i < imaplen; i +=3D 3 * sizeof(u32)) { - soc_int =3D be32_to_cpup(imap); - if (soc_int > 31) - return -EINVAL; - - cpu_ictl =3D of_find_node_by_phandle(be32_to_cpup(imap + 1)); - if (!cpu_ictl) - return -EINVAL; - ret =3D of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp); - if (ret || tmp !=3D 1) - return -EINVAL; - of_node_put(cpu_ictl); - - cpu_int =3D be32_to_cpup(imap + 2); - if (cpu_int > 7 || cpu_int < 2) - return -EINVAL; - - if (!(mips_irqs_set & BIT(cpu_int))) { - irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch, - domain); - mips_irqs_set |=3D BIT(cpu_int); - } - - /* Use routing values (1..6) for CPU interrupts (2..7) */ - regs[(soc_int * 4) / 32] |=3D (cpu_int - 1) << (soc_int * 4) % 32; - imap +=3D 3; - } - - for (i =3D 0; i < 4; i++) - writel(regs[i], REG(irr_regs[i])); - - return 0; -} - static int __init realtek_rtl_of_init(struct device_node *node, struct dev= ice_node *parent) { + struct of_phandle_args oirq; struct irq_domain *domain; - int ret; + unsigned int soc_irq; + int parent_irq; =20 realtek_ictl_base =3D of_iomap(node, 0); if (!realtek_ictl_base) return -ENXIO; =20 - /* Disable all cascaded interrupts */ + /* Disable all cascaded interrupts and clear routing */ writel(0, REG(RTL_ICTL_GIMR)); + for (soc_irq =3D 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) + write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0); + + if (WARN_ON(!of_irq_count(node))) { + /* + * If DT contains no parent interrupts, assume MIPS CPU IRQ 2 + * (HW0) is connected to the first output. This is the case for + * all known hardware anyway. "interrupt-map" is deprecated, so + * don't bother trying to parse that. + */ + oirq.np =3D of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-contr= oller"); + oirq.args_count =3D 1; + oirq.args[0] =3D 2; + + parent_irq =3D irq_create_of_mapping(&oirq); + + of_node_put(oirq.np); + } else { + parent_irq =3D of_irq_get(node, 0); + } =20 - domain =3D irq_domain_add_linear(node, 32, &irq_domain_ops, NULL); + if (parent_irq < 0) + return parent_irq; + else if (!parent_irq) + return -ENODEV; =20 - ret =3D map_interrupts(node, domain); - if (ret) { - pr_err("invalid interrupt map\n"); - return ret; - } + domain =3D irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_o= ps, NULL); + if (!domain) + return -ENOMEM; + + irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain= ); =20 return 0; } --=20 2.35.1 From nobody Mon Jun 29 05:22:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2E64C433F5 for ; Mon, 14 Feb 2022 20:48:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229585AbiBNUsv (ORCPT ); Mon, 14 Feb 2022 15:48:51 -0500 Received: from gmail-smtp-in.l.google.com ([23.128.96.19]:58114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229379AbiBNUst (ORCPT ); Mon, 14 Feb 2022 15:48:49 -0500 X-Greylist: delayed 6392 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Mon, 14 Feb 2022 12:48:22 PST Received: from polaris.svanheule.net (polaris.svanheule.net [84.16.241.116]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54A01166A6F for ; Mon, 14 Feb 2022 12:48:21 -0800 (PST) Received: from terra.local.svanheule.net (104.153-136-217.adsl-dyn.isp.belgacom.be [217.136.153.104]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sander@svanheule.net) by polaris.svanheule.net (Postfix) with ESMTPSA id 3F5852A25FE; Mon, 14 Feb 2022 19:57:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1644865029; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xG36KawVbQpRfxk6svXdxXAMh3RWTIg+IJcjKbB2Plc=; b=Ijn3tdqMHWtyzo0hep9yfKHBfVF4yRFbNs/yRUSB9XdlWpzxkru+24FSyOn1NpvybEe3Zm h/4C++BkEEFBSmBqGf/sVEqGHpo3f82U5HFQc4rnZlTFW1TmarJxpPmczF/YK7FvxxVWXF xTd9RVZXEzx2QPxHrqb2k/jGEmggaKE4DKxntO2HnHxE74MG2PO0u4LAt5hBpkqMOoZRK3 l77MJMNqGnjPnPNR/KRIkhmcngn9B9Ks3WwVCz9SY7MR9jDxbipAbVw+lImmdnLpBsWkvp ALZ2n5yZbfIHruPwj6nUM0usl3P19UlexMlVicSa8zZmc3uhCICp0YsbE0RZDQ== From: Sander Vanheule To: Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Thomas Gleixner , Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [PATCH v5 4/4] irqchip/realtek-rtl: use per-parent domains Date: Mon, 14 Feb 2022 19:57:01 +0100 Message-Id: X-Mailer: git-send-email 2.35.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The interrupt router can connect each of its inputs to one of the parent interrupts. These parent interrupts may be handled differently by their interrupt controller. SoC interrupts should be treated per-parent, to maintain this expected behaviour for routed child interrupts. For example, it is possible that both networking interrupts and the system event timer interrupts are routed through this controller. Even under high network load, event timer interrupts should take precedence, which can be ensured by routing them to a higher priority parent. Rework the driver to use a separate domain for each output, using all available parents interrupts (as specified in the devicetree). A per-parent mask of child interrupts is used to keep track of which domain should handle which interrupts. Signed-off-by: Sander Vanheule --- Changes since v4: - Use irq_domain_add_linear instead of irq_domain_add_simple - Drop 'inline' specifiers from static functions - Drop WARN in intc_select() to only warn once for old bindings drivers/irqchip/irq-realtek-rtl.c | 149 +++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 25 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realte= k-rtl.c index 2a349082af81..0cd25e2cb8cc 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -22,12 +22,22 @@ #define RTL_ICTL_IRR3 0x14 =20 #define RTL_ICTL_NUM_INPUTS 32 +#define RTL_ICTL_NUM_OUTPUTS 15 =20 #define REG(x) (realtek_ictl_base + x) =20 static DEFINE_RAW_SPINLOCK(irq_lock); static void __iomem *realtek_ictl_base; =20 +struct realtek_ictl_output { + /* IRQ controller data */ + struct fwnode_handle *fwnode; + /* Output specific data */ + unsigned int output_index; + struct irq_domain *domain; + u32 child_mask; +}; + /* * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numberi= ng, * placing IRQ 31 in the first four bits. A routing value of '0' means the @@ -37,6 +47,11 @@ static void __iomem *realtek_ictl_base; #define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32)) #define IRR_SHIFT(idx) ((idx * 4) % 32) =20 +static u32 read_irr(void __iomem *irr0, int idx) +{ + return (readl(irr0 + IRR_OFFSET(idx)) >> IRR_SHIFT(idx)) & 0xf; +} + static void write_irr(void __iomem *irr0, int idx, u32 value) { unsigned int offset =3D IRR_OFFSET(idx); @@ -84,51 +99,128 @@ static struct irq_chip realtek_ictl_irq =3D { =20 static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_= t hw) { + struct realtek_ictl_output *output =3D d->host_data; unsigned long flags; + u32 routing_old; + int err =3D 0; + + raw_spin_lock_irqsave(&irq_lock, flags); + + /* + * Inputs can only be routed to one output, so they shouldn't end up in + * multiple domains. Perform this check in the same atomic context as + * configuring the routing to prevent races. + */ + routing_old =3D read_irr(REG(RTL_ICTL_IRR0), hw); + if (routing_old && output->output_index !=3D routing_old - 1) { + pr_err("int %ld already routed to output %d\n", + hw, routing_old - 1); + err =3D -EINVAL; + goto out; + } + + output->child_mask |=3D BIT(hw); + write_irr(REG(RTL_ICTL_IRR0), hw, output->output_index + 1); =20 irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq); =20 - raw_spin_lock_irqsave(&irq_lock, flags); - write_irr(REG(RTL_ICTL_IRR0), hw, 1); +out: raw_spin_unlock_irqrestore(&irq_lock, flags); =20 - return 0; + return err; +} + +static int intc_select(struct irq_domain *d, struct irq_fwspec *fwspec, + enum irq_domain_bus_token bus_token) +{ + struct realtek_ictl_output *output =3D d->host_data; + + if (fwspec->fwnode !=3D output->fwnode) + return false; + + /* Original specifiers only had one parameter */ + if (fwspec->param_count < 2) + return true; + + return fwspec->param[1] =3D=3D output->output_index; } =20 static const struct irq_domain_ops irq_domain_ops =3D { .map =3D intc_map, + .select =3D intc_select, .xlate =3D irq_domain_xlate_onecell, }; =20 static void realtek_irq_dispatch(struct irq_desc *desc) { + struct realtek_ictl_output *output =3D irq_desc_get_handler_data(desc); struct irq_chip *chip =3D irq_desc_get_chip(desc); - struct irq_domain *domain; unsigned long pending; unsigned int soc_int; =20 chained_irq_enter(chip, desc); - pending =3D readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)); + pending =3D readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)) + & output->child_mask; =20 if (unlikely(!pending)) { spurious_interrupt(); goto out; } =20 - domain =3D irq_desc_get_handler_data(desc); - for_each_set_bit(soc_int, &pending, 32) - generic_handle_domain_irq(domain, soc_int); + for_each_set_bit(soc_int, &pending, RTL_ICTL_NUM_INPUTS) + generic_handle_domain_irq(output->domain, soc_int); =20 out: chained_irq_exit(chip, desc); } =20 +static int __init setup_parent_interrupts(struct device_node *node, int *p= arents, + unsigned int num_parents) +{ + struct realtek_ictl_output *outputs; + struct realtek_ictl_output *output; + struct irq_domain *domain; + unsigned int p; + + outputs =3D kcalloc(num_parents, sizeof(*outputs), GFP_KERNEL); + if (!outputs) + return -ENOMEM; + + for (p =3D 0; p < num_parents; p++) { + output =3D outputs + p; + + domain =3D irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, + &irq_domain_ops, output); + if (!domain) + goto domain_err; + + output->fwnode =3D of_node_to_fwnode(node); + output->output_index =3D p; + output->domain =3D domain; + + irq_set_chained_handler_and_data(parents[p], realtek_irq_dispatch, outpu= t); + } + + return 0; + +domain_err: + while (p--) { + irq_set_chained_handler_and_data(parents[p], NULL, NULL); + irq_domain_remove(outputs[p].domain); + } + + kfree(outputs); + + return -ENOMEM; +} + static int __init realtek_rtl_of_init(struct device_node *node, struct dev= ice_node *parent) { + int parent_irqs[RTL_ICTL_NUM_OUTPUTS]; struct of_phandle_args oirq; - struct irq_domain *domain; + unsigned int num_parents; unsigned int soc_irq; - int parent_irq; + unsigned int p; =20 realtek_ictl_base =3D of_iomap(node, 0); if (!realtek_ictl_base) @@ -139,36 +231,43 @@ static int __init realtek_rtl_of_init(struct device_n= ode *node, struct device_no for (soc_irq =3D 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0); =20 - if (WARN_ON(!of_irq_count(node))) { + num_parents =3D of_irq_count(node); + if (num_parents > RTL_ICTL_NUM_OUTPUTS) { + pr_err("too many parent interrupts\n"); + return -EINVAL; + } + + for (p =3D 0; p < num_parents; p++) + parent_irqs[p] =3D of_irq_get(node, p); + + if (WARN_ON(!num_parents)) { /* * If DT contains no parent interrupts, assume MIPS CPU IRQ 2 * (HW0) is connected to the first output. This is the case for * all known hardware anyway. "interrupt-map" is deprecated, so * don't bother trying to parse that. + * Since this is to account for old devicetrees with one-cell + * interrupt specifiers, only one output domain is needed. */ oirq.np =3D of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-contr= oller"); oirq.args_count =3D 1; oirq.args[0] =3D 2; =20 - parent_irq =3D irq_create_of_mapping(&oirq); + parent_irqs[0] =3D irq_create_of_mapping(&oirq); + num_parents =3D 1; =20 of_node_put(oirq.np); - } else { - parent_irq =3D of_irq_get(node, 0); } =20 - if (parent_irq < 0) - return parent_irq; - else if (!parent_irq) - return -ENODEV; - - domain =3D irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_o= ps, NULL); - if (!domain) - return -ENOMEM; - - irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain= ); + /* Ensure we haven't collected any errors before proceeding */ + for (p =3D 0; p < num_parents; p++) { + if (parent_irqs[p] < 0) + return parent_irqs[p]; + if (!parent_irqs[p]) + return -ENODEV; + } =20 - return 0; + return setup_parent_interrupts(node, parent_irqs, num_parents); } =20 IRQCHIP_DECLARE(realtek_rtl_intc, "realtek,rtl-intc", realtek_rtl_of_init); --=20 2.35.1