From patchwork Sun Dec 26 19:59:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sander Vanheule X-Patchwork-Id: 528196 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 0D851C433EF for ; Sun, 26 Dec 2021 20:02:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229461AbhLZUCi (ORCPT ); Sun, 26 Dec 2021 15:02:38 -0500 Received: from polaris.svanheule.net ([84.16.241.116]:57508 "EHLO polaris.svanheule.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232494AbhLZT7f (ORCPT ); Sun, 26 Dec 2021 14:59:35 -0500 Received: from terra.local.svanheule.net (unknown [IPv6:2a02:a03f:eafe:c901:201f:9f28:b747:b33a]) (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 5E791288173; Sun, 26 Dec 2021 20:59:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1640548773; 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=TpkkGK1HUml0mP08FJk1cHUKfwB7mgaDR1xVUUyYboc=; b=oFY52azimID0jDwssKlYBy6MiKluyiVyekTFxgy0s2+e/jPE2wT/JGogsiTXkimdkCxJ73 xdLLtcPD2SEmIGI4ej/Lh8QaskHjDroZn5PrboUt6GfaL2GEhnwjRRhQRRL7oBVpr7fevg MdKd6eNXk3qjlESiLFnznG10dH+UFtjBS/wZPNYA/7lyN2dpVYu3KL4IO5O2GNC0yrpcu4 zP6cCZApCUwWsoLngT9Xd3K0p8O5Oz3zpjx70NhxDE7Np3rm6bF+r397WYxKh1J4zDRsgD 0fYZlpQoL6ZiEHjEku2AQgEO7iqPuD06h/yfBJYfOPNT3N1i79EfONe4FPXtAA== From: Sander Vanheule To: Thomas Gleixner , Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [RFC PATCH v2 1/5] irqchip/realtek-rtl: map control data to virq Date: Sun, 26 Dec 2021 20:59:24 +0100 Message-Id: <6a853e21eb3edee268c8f99429673b89dd1517c5.1640548009.git.sander@svanheule.net> X-Mailer: git-send-email 2.33.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The driver assigned the irqchip and irq handler to the hardware irq, instead of the virq. This is incorrect, and only worked because these irq numbers happened to be the same on the devices used for testing the original driver. Fixes: 9f3a0f34b84a ("irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller") Signed-off-by: Sander Vanheule --- drivers/irqchip/irq-realtek-rtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c index fd9f275592d2..d6788dd93c7b 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -62,7 +62,7 @@ static struct irq_chip realtek_ictl_irq = { static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq); + irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq); return 0; } From patchwork Sun Dec 26 19:59:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sander Vanheule X-Patchwork-Id: 528355 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 4D39AC433EF for ; Sun, 26 Dec 2021 20:02:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230363AbhLZUCk (ORCPT ); Sun, 26 Dec 2021 15:02:40 -0500 Received: from polaris.svanheule.net ([84.16.241.116]:57524 "EHLO polaris.svanheule.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232529AbhLZT7f (ORCPT ); Sun, 26 Dec 2021 14:59:35 -0500 Received: from terra.local.svanheule.net (unknown [IPv6:2a02:a03f:eafe:c901:201f:9f28:b747:b33a]) (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 E80B7288174; Sun, 26 Dec 2021 20:59:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1640548774; 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=RffKHmKHsI7Q9f2s/yP75xd+8RX8KcPe5WgjwZP779I=; b=XHIWqvF0ek/Z8tWa9Xqr6uGIrmAXY9r0yJSxi54xQCRDsx4YcYPF7gpL/BXFsryvqpMXeX 9Y2jmIuoxEVVzlXlhmN/vkr4YIivTuFCncNBOPa6eOVttOLrphgYC2xyX3sN7/Vm2kD0NG 2tZ40liUhNwQWsfgFBKf2vRbV4wK+4o6qpYtpA9dakzdldxDtH00G2cJLR6wzgQmEJ/IQx DAnArK3TFqGsvVLwQ/KFX+ZWBSxLNPAj7f6NWD42xaVxIqZXQvihtRNBJh+6h+7GTjNKyC 1EieD0lxCuWtY5/yUNxEJOg4+k0/Udv4s7N9MLJpk9E+4Uy0tMkme+0MKlKGbg== From: Sander Vanheule To: Thomas Gleixner , Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [RFC PATCH v2 2/5] irqchip/realtek-rtl: fix off-by-one in routing Date: Sun, 26 Dec 2021 20:59:25 +0100 Message-Id: <2235a7748b8f7689a96b1e0f91461e36a946a4ef.1640548009.git.sander@svanheule.net> X-Mailer: git-send-email 2.33.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org There is an offset between routing values (1..6) and the connected MIPS CPU interrupts (2..7), but no distinction was made between these two values. This issue was previously hidden during testing, because an interrupt mapping was used where for each required interrupt another (unused) routing was configured, with an offset of +1. Offset the CPU IRQ numbers by -1 to retrieve the correct routing value. Fixes: 9f3a0f34b84a ("irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller") Signed-off-by: Sander Vanheule --- drivers/irqchip/irq-realtek-rtl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c index d6788dd93c7b..568614edd88f 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -95,7 +95,8 @@ static void realtek_irq_dispatch(struct irq_desc *desc) * 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 interrupts - * thus go into 4 IRRs. + * 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_domain *domain) { @@ -134,7 +135,7 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do of_node_put(cpu_ictl); cpu_int = be32_to_cpup(imap + 2); - if (cpu_int > 7) + if (cpu_int > 7 || cpu_int < 2) return -EINVAL; if (!(mips_irqs_set & BIT(cpu_int))) { @@ -143,7 +144,8 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do mips_irqs_set |= BIT(cpu_int); } - regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32; + /* Use routing values (1..6) for CPU interrupts (2..7) */ + regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32; imap += 3; } From patchwork Sun Dec 26 19:59:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sander Vanheule X-Patchwork-Id: 528356 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 4551CC433F5 for ; Sun, 26 Dec 2021 20:02:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232494AbhLZUCl (ORCPT ); Sun, 26 Dec 2021 15:02:41 -0500 Received: from polaris.svanheule.net ([84.16.241.116]:57542 "EHLO polaris.svanheule.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232572AbhLZT7g (ORCPT ); Sun, 26 Dec 2021 14:59:36 -0500 Received: from terra.local.svanheule.net (unknown [IPv6:2a02:a03f:eafe:c901:201f:9f28:b747:b33a]) (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 8C3E7288175; Sun, 26 Dec 2021 20:59:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1640548774; 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=WQROpGjB8/oQm8ho3AEhvLI6HBGxBtFxZGU3PVXv0XQ=; b=ZDfotFMp1H1rCjK7O6ye0opq79owqhClRE9K0OcK3KUi0IR+xu/5xFYOd7J1AL8WYVZ8po /9QgenL5UBXpcfKCRvCUH5gNHhJYeA0hvLl31tRGP/DWb13xCB18Dl0NoEDmcIC0AU3j11 UuJTfuwCUOf3DcYNGWWrMvmYNmTnADiSphWHqRkI948VHSxw+tBrFervlc6y0J1p6/5puw XAgrpVKmOPcAGs6MF+zDJfndklb3HIfKUCGjtdIRJrbNOMv5O5thNamM3/zUMwUL1Wj7G3 oVyBq4IXRKuoFNkTokqG51ydGkf/T4kutqn3PsdgSi7KCpvjXRY2+yD4eqI5Cg== From: Sander Vanheule To: Thomas Gleixner , Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [RFC PATCH v2 3/5] irqchip/realtek-rtl: use per-parent irq handling Date: Sun, 26 Dec 2021 20:59:26 +0100 Message-Id: <73789385f470b7630c19b4c632d60ef7b89a46d0.1640548009.git.sander@svanheule.net> X-Mailer: git-send-email 2.33.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The driver handled all SoC interrupts equally, independent of which parent interrupt it is routed to. Between all configured inputs, the use of __ffs actually gives higher priority to lower input lines, effectively bypassing any priority there might be among the parent interrupts. Rework the driver to use a separate handler for each parent interrupt, to respect the order in which those parents interrupt are handled. Signed-off-by: Sander Vanheule --- With switching back to chained handlers, it became impossible to route a SoC interrupt to the timer interrupt (CPU IRQ 7) on systems using the CEVT-R4K timer. If a chained handler is already set for the timer interrupt, the timer cannot request it anymore (due to IRQ_NOREQUEST) and the system hangs. It is probably a terrible idea to also run e.g. the console on the timer interrupt, but it is possible. If there are no solutions to this, I can live with it though; there are still 5 other interrupts. Changes since v1: - Limit scope to per-parent handling - Replace the "priority" naming with the more generic "output" - Don't request interrupts, but stick to chained handlers --- drivers/irqchip/irq-realtek-rtl.c | 109 ++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c index 568614edd88f..1f8f21a0bd1a 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -21,10 +22,45 @@ #define RTL_ICTL_IRR2 0x10 #define RTL_ICTL_IRR3 0x14 +#define RTL_ICTL_NUM_OUTPUTS 6 + #define REG(x) (realtek_ictl_base + x) static DEFINE_RAW_SPINLOCK(irq_lock); static void __iomem *realtek_ictl_base; +static struct irq_domain *realtek_ictl_domain; + +struct realtek_ictl_output { + unsigned int routing_value; + u32 child_mask; +}; + +static struct realtek_ictl_output realtek_ictl_outputs[RTL_ICTL_NUM_OUTPUTS]; + +/* + * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering, + * 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 inline u32 read_irr(void __iomem *irr0, int idx) +{ + return (readl(irr0 + IRR_OFFSET(idx)) >> IRR_SHIFT(idx)) & 0xf; +} + +static inline void write_irr(void __iomem *irr0, int idx, u32 value) +{ + unsigned int offset = IRR_OFFSET(idx); + unsigned int shift = IRR_SHIFT(idx); + u32 irr; + + irr = readl(irr0 + offset) & ~(0xf << shift); + irr |= (value & 0xf) << shift; + writel(irr, irr0 + offset); +} static void realtek_ictl_unmask_irq(struct irq_data *i) { @@ -74,42 +110,45 @@ static const struct irq_domain_ops irq_domain_ops = { static void realtek_irq_dispatch(struct irq_desc *desc) { + struct realtek_ictl_output *parent = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_domain *domain; unsigned int pending; chained_irq_enter(chip, desc); - pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)); + pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR)) + & parent->child_mask; + if (unlikely(!pending)) { spurious_interrupt(); goto out; } - domain = irq_desc_get_handler_data(desc); - generic_handle_domain_irq(domain, __ffs(pending)); + generic_handle_domain_irq(realtek_ictl_domain, __ffs(pending)); out: chained_irq_exit(chip, desc); } -/* - * 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 interrupts - * 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_domain *domain) +static void __init set_routing(struct realtek_ictl_output *output, unsigned int soc_int) { + unsigned int routing_old; + + routing_old = read_irr(REG(RTL_ICTL_IRR0), soc_int); + if (routing_old) { + pr_warn("int %d already routed to %d, not updating\n", soc_int, routing_old); + return; + } + + output->child_mask |= BIT(soc_int); + write_irr(REG(RTL_ICTL_IRR0), soc_int, output->routing_value); +} + +static int __init map_interrupts(struct device_node *node) +{ + struct realtek_ictl_output *output; struct device_node *cpu_ictl; const __be32 *imap; - u32 imaplen, soc_int, cpu_int, tmp, regs[4]; - int ret, i, irr_regs[] = { - RTL_ICTL_IRR3, - RTL_ICTL_IRR2, - RTL_ICTL_IRR1, - RTL_ICTL_IRR0, - }; - u8 mips_irqs_set; + u32 imaplen, soc_int, cpu_int, tmp; + int ret, i; ret = of_property_read_u32(node, "#address-cells", &tmp); if (ret || tmp) @@ -119,8 +158,6 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do if (!imap || imaplen % 3) return -EINVAL; - mips_irqs_set = 0; - memset(regs, 0, sizeof(regs)); for (i = 0; i < imaplen; i += 3 * sizeof(u32)) { soc_int = be32_to_cpup(imap); if (soc_int > 31) @@ -138,39 +175,41 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do 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 |= BIT(cpu_int); + output = &realtek_ictl_outputs[cpu_int - 2]; + + if (!output->routing_value) { + irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch, output); + /* Use routing values (1..6) for CPU interrupts (2..7) */ + output->routing_value = cpu_int - 1; } - /* Use routing values (1..6) for CPU interrupts (2..7) */ - regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32; + set_routing(output, soc_int); + imap += 3; } - for (i = 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 device_node *parent) { - struct irq_domain *domain; + unsigned int soc_irq; int ret; + memset(&realtek_ictl_outputs, 0, sizeof(realtek_ictl_outputs)); + realtek_ictl_base = of_iomap(node, 0); if (!realtek_ictl_base) return -ENXIO; /* Disable all cascaded interrupts */ writel(0, REG(RTL_ICTL_GIMR)); + for (soc_irq = 0; soc_irq < 32; soc_irq++) + write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0); - domain = irq_domain_add_simple(node, 32, 0, - &irq_domain_ops, NULL); + realtek_ictl_domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL); - ret = map_interrupts(node, domain); + ret = map_interrupts(node); if (ret) { pr_err("invalid interrupt map\n"); return ret; From patchwork Sun Dec 26 19:59:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sander Vanheule X-Patchwork-Id: 528354 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 E953AC433F5 for ; Sun, 26 Dec 2021 20:02:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232575AbhLZUCm (ORCPT ); Sun, 26 Dec 2021 15:02:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232678AbhLZT7h (ORCPT ); Sun, 26 Dec 2021 14:59:37 -0500 Received: from polaris.svanheule.net (polaris.svanheule.net [IPv6:2a00:c98:2060:a004:1::200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 83D1EC061401 for ; Sun, 26 Dec 2021 11:59:37 -0800 (PST) Received: from terra.local.svanheule.net (unknown [IPv6:2a02:a03f:eafe:c901:201f:9f28:b747:b33a]) (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 784A2288176; Sun, 26 Dec 2021 20:59:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1640548775; 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=YhFl1HSPo01ZnFhZbm1q0BwTt+dtDmUDaRbMk0PbM0o=; b=4q8SwDYhpdTaj3LfEZPnyKDfwXzRfbYJ/cfjy2FoQAYTJgBoU+kuhU60I+1z9INpX1aDGu +NhGgtKeP60rktNbFL9x+MpOsdYMMGURY9Dopze2htrWY/vYTUhjGrDlIpJS+xamaDbwWD x2yUPR+mlXsb6y513k2+sXMe2vXKIGh53L+GrewoyveqYVcBfddU44cyhvN1z3Q+S4NH2N cEagDPKdOvGgsXFbMMKnQ3FCvlR6vtHUJgflBbpxXo3hsU0bwI+r+uEm2r+4KW8xeu5x+w /Iq3NRcwPR1mYZzgU868M/kaaRiX0Y9lBMT7iaTdIB1dB6anH1J5Av/XEkNV7g== From: Sander Vanheule To: Thomas Gleixner , Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [RFC PATCH v2 4/5] dt-bindings: interrupt-controller: realtek,rtl-intc: map output lines Date: Sun, 26 Dec 2021 20:59:27 +0100 Message-Id: <0a91967d40d486bb8cccd0dcf5a817df11317cf0.1640548009.git.sander@svanheule.net> X-Mailer: git-send-email 2.33.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Amend the binding to also require a list of parent interrupts, and an optional mask to specify which parent is mapped to which output. Without this information, any driver would have to make an assumption on which parent interrupt is connected to which output. Additionally, extend (or add) the relevant descriptions to more clearly describe the inputs and outputs of this router. Signed-off-by: Sander Vanheule --- Since it does not properly describe the hardware, I would still really rather get rid of "interrupt-map", even though that would mean breaking ABI for this binding. As we've argued before [1], that is our prefered solution, and would enable us to not carry more (hacky) code because of a mistake with the initial submission. Vendors don't ship independent DT blobs for devices with this hardware, so the independent devicetree/kernel upgrades issue is really rather theoretical here. Realtek isn't driving the development of the bindings and associated drivers for this platform. They have their SDK and seem to care very little about proper kernel integration. Furthermore, there are currently no device descriptions in the kernel using this binding. There are in OpenWrt, but OpenWrt firmware images for this platform always contain both the kernel and the appended DTB, so there's also no breakage to worry about. [1] https://lore.kernel.org/all/9c169aad-3c7b-2ffb-90a2-1ca791a3f411@phrozen.org/ Differences with v1: - Don't drop the "interrupt-map" property - Add the "realtek,output-valid-mask" property --- .../realtek,rtl-intc.yaml | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml index 9e76fff20323..29014673c34e 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/realtek,rtl-intc.yaml @@ -6,6 +6,10 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Realtek RTL SoC interrupt controller devicetree bindings +description: + Interrupt router for Realtek MIPS SoCs, allowing up to 32 SoC interrupts to + be routed to one of up to 15 parent interrupts, or left disconnected. + maintainers: - Birger Koblitz - Bert Vermeulen @@ -22,7 +26,11 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 15 + description: + List of parent interrupts, in the order that they are connected to this + interrupt router's outputs. interrupt-controller: true @@ -30,7 +38,21 @@ properties: const: 0 interrupt-map: - description: Describes mapping from SoC interrupts to CPU interrupts + description: + List of tuples, where "soc_int" + is the interrupt input line number as provided by this controller. + "parent_phandle" and "parent_args" specify which parent interrupt this + line should be routed to. Note that interrupt specifiers should be + identical to the parents specified in the "interrupts" property. + + realtek,output-valid-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Optional bit mask indicating which outputs are connected to the parent + interrupts. The lowest set bit indicates which output line the first + interrupt from "interrupts" is connected to, the second lowest set bit + for the second interrupt, etc. If not provided, parent interrupts will be + assigned sequentially to the outputs. required: - compatible @@ -39,6 +61,7 @@ required: - interrupt-controller - "#address-cells" - interrupt-map + - interrupts additionalProperties: false @@ -49,9 +72,14 @@ examples: #interrupt-cells = <1>; interrupt-controller; reg = <0x3000 0x20>; + + interrupt-parent = <&cpuintc>; + interrupts = <1>, <2>, <5>; + realtek,output-valid-mask = <0x13>; + #address-cells = <0>; interrupt-map = - <31 &cpuintc 2>, - <30 &cpuintc 1>, - <29 &cpuintc 5>; + <31 &cpuintc 2>, /* connect to cpuintc 2 via output 1 */ + <30 &cpuintc 1>, /* connect to cpuintc 1 via output 0 */ + <29 &cpuintc 5>; /* connect to cpuintc 5 via output 4 */ }; From patchwork Sun Dec 26 19:59:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sander Vanheule X-Patchwork-Id: 528194 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 6454DC43217 for ; Sun, 26 Dec 2021 20:02:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232520AbhLZUCl (ORCPT ); Sun, 26 Dec 2021 15:02:41 -0500 Received: from polaris.svanheule.net ([84.16.241.116]:57590 "EHLO polaris.svanheule.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232647AbhLZT7h (ORCPT ); Sun, 26 Dec 2021 14:59:37 -0500 Received: from terra.local.svanheule.net (unknown [IPv6:2a02:a03f:eafe:c901:201f:9f28:b747:b33a]) (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 2A5FC288177; Sun, 26 Dec 2021 20:59:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1640548776; 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=9tboXP4goP5ZcMhJTfz6d5ExIJnyvh4FVmcwRpjzX8U=; b=ZKVplqAxgh3uB2I5MozredAqciHl2raryWchRJC+Sk/SFQHiONUqLfzqys4W2hcWNJFfn+ Xj4a8DoakijxUB9JAF66Rz9fu7yhkQclFnVAQLy11pesKltvdRATuK5d0oB50Q1fbvMU9r h32H48XVQOpuU4Q/dmhGotnoeDCxYEOKxM5QK7GMTmDXN/oGEHXOgxYlwv+YPjVkU5EcAl WjJNJMFIZdszdB1RG8LCSo/c2uWxf7WOGMx3CUehmnl7EfwYGQNGAFGT5W+7ap3NRblgk3 V3tC3eWF7J4iiCHfAKtPcv24y+N87pzjWo1KoFClVv8bJCbjBIdrptC/EuF5Aw== From: Sander Vanheule To: Thomas Gleixner , Marc Zyngier , Rob Herring , devicetree@vger.kernel.org Cc: Birger Koblitz , Bert Vermeulen , John Crispin , linux-kernel@vger.kernel.org, Sander Vanheule Subject: [RFC PATCH v2 5/5] irqchip/realtek-rtl: add explicit output routing Date: Sun, 26 Dec 2021 20:59:28 +0100 Message-Id: <5ac543a6b61bbf825519e5cb0e36f8fe218f7054.1640548009.git.sander@svanheule.net> X-Mailer: git-send-email 2.33.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Use the list of parent interrupts, and the optional output validity mask, to build the list of routed output interrupts. This enables us to remove the assumption that interrupt outputs (1..6) are always connected to MIPS CPU interrupts (2..7). Since the use of interrupt-map is non-standard, extra logic is required to resolve the specified interrupts to one of the parent interrupts. Signed-off-by: Sander Vanheule --- drivers/irqchip/irq-realtek-rtl.c | 137 +++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 20 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c index 1f8f21a0bd1a..1b9c1108e945 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -22,6 +22,8 @@ #define RTL_ICTL_IRR2 0x10 #define RTL_ICTL_IRR3 0x14 +/* Support up to 6 active outputs for now */ +#define RTL_ICTL_OUTPUT_MASK GENMASK(14, 0) #define RTL_ICTL_NUM_OUTPUTS 6 #define REG(x) (realtek_ictl_base + x) @@ -31,6 +33,7 @@ static void __iomem *realtek_ictl_base; static struct irq_domain *realtek_ictl_domain; struct realtek_ictl_output { + int parent; unsigned int routing_value; u32 child_mask; }; @@ -142,10 +145,58 @@ static void __init set_routing(struct realtek_ictl_output *output, unsigned int write_irr(REG(RTL_ICTL_IRR0), soc_int, output->routing_value); } +static int __init resolve_parent(struct device_node *node, const __be32 *table, + unsigned int table_len, int *parent) +{ + struct of_phandle_args parent_irq; + struct device_node *parent_ictl; + unsigned int parent_cell_count; + unsigned int table_len_left; + int cell; + int ret; + + if (!table_len) + return -EINVAL; + + parent_ictl = of_find_node_by_phandle(be32_to_cpup(table++)); + table_len_left = table_len - 1; + + if (!parent_ictl) + return -EINVAL; + + parent_irq.np = parent_ictl; + + parent_cell_count = 0; + ret = of_property_read_u32(parent_ictl, "#interrupt-cells", &parent_cell_count); + if (ret) + goto out; + + if (table_len_left < parent_cell_count) { + ret = -EINVAL; + goto out; + } + + parent_irq.args_count = parent_cell_count; + + for (cell = 0; cell < parent_cell_count; cell++) + parent_irq.args[cell] = be32_to_cpup(table++); + + table_len_left -= parent_cell_count; + + ret = of_irq_parse_raw(of_get_property(node, "reg", NULL), &parent_irq); + if (ret < 0) + goto out; + + *parent = irq_create_of_mapping(&parent_irq); + ret = table_len - table_len_left; +out: + of_node_put(parent_ictl); + return ret; +} + static int __init map_interrupts(struct device_node *node) { struct realtek_ictl_output *output; - struct device_node *cpu_ictl; const __be32 *imap; u32 imaplen, soc_int, cpu_int, tmp; int ret, i; @@ -158,34 +209,76 @@ static int __init map_interrupts(struct device_node *node) if (!imap || imaplen % 3) return -EINVAL; - for (i = 0; i < imaplen; i += 3 * sizeof(u32)) { - soc_int = be32_to_cpup(imap); - if (soc_int > 31) - return -EINVAL; + imaplen /= sizeof(*imap); + while (imaplen > 1) { + soc_int = be32_to_cpup(imap++); + imaplen--; - cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1)); - if (!cpu_ictl) - return -EINVAL; - ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp); - if (ret || tmp != 1) + if (soc_int > 31) return -EINVAL; - of_node_put(cpu_ictl); - cpu_int = be32_to_cpup(imap + 2); - if (cpu_int > 7 || cpu_int < 2) - return -EINVAL; + cpu_int = 0; + ret = resolve_parent(node, imap, imaplen, &cpu_int); + if (ret < 0) + return ret; + imaplen -= ret; + imap += ret; - output = &realtek_ictl_outputs[cpu_int - 2]; + i = 0; + output = &realtek_ictl_outputs[0]; - if (!output->routing_value) { - irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch, output); - /* Use routing values (1..6) for CPU interrupts (2..7) */ - output->routing_value = cpu_int - 1; + while (i < RTL_ICTL_NUM_OUTPUTS && output->parent != cpu_int) { + output++; + i++; } + if (i == RTL_ICTL_NUM_OUTPUTS) + return -EINVAL; + set_routing(output, soc_int); + } + + return 0; +} - imap += 3; +static int __init route_parent_interrupts(struct device_node *node) +{ + struct realtek_ictl_output *output; + unsigned int current_output; + unsigned int num_parents; + unsigned int parent; + u32 output_mask; + int parent_irq; + + output_mask = RTL_ICTL_OUTPUT_MASK; + of_property_read_u32(node, "realtek,output-valid-mask", &output_mask); + if (output_mask & ~RTL_ICTL_OUTPUT_MASK) { + pr_warn("realtek,output-valid-mask contains unsupported outputs\n"); + output_mask &= RTL_ICTL_OUTPUT_MASK; + } + + num_parents = of_irq_count(node); + if (num_parents > RTL_ICTL_NUM_OUTPUTS) { + pr_err("too many parent interrupts\n"); + return -EINVAL; + } + + for (parent = 0; output_mask && parent < num_parents; parent++) { + current_output = __ffs(output_mask); + + parent_irq = of_irq_get(node, parent); + if (parent_irq < 0) + return parent_irq; + else if (!parent_irq) + return -ENODEV; + + output = &realtek_ictl_outputs[parent]; + output->parent = parent_irq; + output->routing_value = current_output + 1; + + irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, output); + + output_mask &= ~BIT(current_output); } return 0; @@ -209,6 +302,10 @@ static int __init realtek_rtl_of_init(struct device_node *node, struct device_no realtek_ictl_domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL); + ret = route_parent_interrupts(node); + if (ret) + return ret; + ret = map_interrupts(node); if (ret) { pr_err("invalid interrupt map\n");