From nobody Wed Dec 17 16:56:10 2025 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 CBD79C77B75 for ; Fri, 5 May 2023 09:47:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231896AbjEEJrt (ORCPT ); Fri, 5 May 2023 05:47:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231848AbjEEJrg (ORCPT ); Fri, 5 May 2023 05:47:36 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 4CEFE1A118; Fri, 5 May 2023 02:47:33 -0700 (PDT) Received: from loongson.cn (unknown [112.20.110.102]) by gateway (Coremail) with SMTP id _____8Dxi+q00FRkXiQFAA--.8475S3; Fri, 05 May 2023 17:47:32 +0800 (CST) Received: from localhost.localdomain (unknown [112.20.110.102]) by localhost.localdomain (Coremail) with SMTP id AQAAf8BxKL2u0FRkQKZLAA--.7843S4; Fri, 05 May 2023 17:47:31 +0800 (CST) From: Binbin Zhou To: Huacai Chen , WANG Xuerui , Jiaxun Yang , Thomas Gleixner , Marc Zyngier , Rob Herring , Krzysztof Kozlowski Cc: Jianmin Lv , Huacai Chen , linux-kernel@vger.kernel.org, loongarch@lists.linux.dev, devicetree@vger.kernel.org, loongson-kernel@lists.loongnix.cn, Binbin Zhou Subject: [PATCH V5 2/2] irqchip/loongson-eiointc: Add DT init support Date: Fri, 5 May 2023 17:46:49 +0800 Message-Id: <764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubinbin@loongson.cn> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8BxKL2u0FRkQKZLAA--.7843S4 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBjvJXoW3JFWUCr1fWw18ur4kAr48Xrb_yoWxZFykpF WUCF98trWrXFy7WrWrta1DX343Aws5urW7Xa4fWFWftanrCr18GF1FyF1qkryjk3yrXF4a vF4UZr1Uu3W5Kw7anT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bSkYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s 1l1IIY67AEw4v_Jrv_JF1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2x7M28EF7xv wVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVWxJVW8Jr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVWxJr0_GcWl n4kS14v26r126r1DM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6x ACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E 87Iv67AKxVWxJVW8Jr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkF7I 0En4kS14v26r126r1DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMxCI bckI1I0E14v26r126r1DMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_Jr I_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v2 6ryj6F1UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj4 0_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8 JrUvcSsGvfC2KfnxnUUI43ZEXa7IU82jg7UUUUU== Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add EIOINTC irqchip DT support, which is needed for Loongson chips based on DT and supporting EIOINTC, such as the Loongson-2K0500 SOC. Signed-off-by: Binbin Zhou --- drivers/irqchip/irq-loongson-eiointc.c | 133 ++++++++++++++++++------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-l= oongson-eiointc.c index 90181c42840b..b3905146524f 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -39,6 +39,7 @@ static int nr_pics; =20 struct eiointc_priv { u32 node; + u32 vec_count; nodemask_t node_map; cpumask_t cpuspan_map; struct fwnode_handle *domain_handle; @@ -156,18 +157,18 @@ static int eiointc_router_init(unsigned int cpu) if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) =3D=3D 0) { eiointc_enable(); =20 - for (i =3D 0; i < VEC_COUNT / 32; i++) { + for (i =3D 0; i < eiointc_priv[0]->vec_count / 32; i++) { data =3D (((1 << (i * 2 + 1)) << 16) | (1 << (i * 2))); iocsr_write32(data, EIOINTC_REG_NODEMAP + i * 4); } =20 - for (i =3D 0; i < VEC_COUNT / 32 / 4; i++) { + for (i =3D 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) { bit =3D BIT(1 + index); /* Route to IP[1 + index] */ data =3D bit | (bit << 8) | (bit << 16) | (bit << 24); iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4); } =20 - for (i =3D 0; i < VEC_COUNT / 4; i++) { + for (i =3D 0; i < eiointc_priv[0]->vec_count / 4; i++) { /* Route to Node-0 Core-0 */ if (index =3D=3D 0) bit =3D BIT(cpu_logical_map(0)); @@ -178,7 +179,7 @@ static int eiointc_router_init(unsigned int cpu) iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4); } =20 - for (i =3D 0; i < VEC_COUNT / 32; i++) { + for (i =3D 0; i < eiointc_priv[0]->vec_count / 32; i++) { data =3D 0xffffffff; iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4); iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4); @@ -198,7 +199,7 @@ static void eiointc_irq_dispatch(struct irq_desc *desc) =20 chained_irq_enter(chip, desc); =20 - for (i =3D 0; i < VEC_REG_COUNT; i++) { + for (i =3D 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) { pending =3D iocsr_read64(EIOINTC_REG_ISR + (i << 3)); iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3)); while (pending) { @@ -313,7 +314,7 @@ static void eiointc_resume(void) eiointc_router_init(0); =20 for (i =3D 0; i < nr_pics; i++) { - for (j =3D 0; j < VEC_COUNT; j++) { + for (j =3D 0; j < eiointc_priv[0]->vec_count; j++) { desc =3D irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j); if (desc && desc->handle_irq && desc->handle_irq !=3D handle_bad_irq) { raw_spin_lock(&desc->lock); @@ -378,11 +379,47 @@ static int __init acpi_cascade_irqdomain_init(void) return 0; } =20 +static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq, + u64 node_map) +{ + int i; + + node_map =3D node_map ? node_map : -1ULL; + for_each_possible_cpu(i) { + if (node_map & (1ULL << (cpu_to_eio_node(i)))) { + node_set(cpu_to_eio_node(i), priv->node_map); + cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, + cpumask_of(i)); + } + } + + priv->eiointc_domain =3D irq_domain_create_linear(priv->domain_handle, + priv->vec_count, + &eiointc_domain_ops, + priv); + if (!priv->eiointc_domain) { + pr_err("loongson-extioi: cannot add IRQ domain\n"); + return -ENOMEM; + } + + eiointc_priv[nr_pics++] =3D priv; + eiointc_router_init(0); + irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); + + if (nr_pics =3D=3D 1) { + register_syscore_ops(&eiointc_syscore_ops); + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, + "irqchip/loongarch/intc:starting", + eiointc_router_init, NULL); + } + + return 0; +} + int __init eiointc_acpi_init(struct irq_domain *parent, struct acpi_madt_eio_pic *acpi_eiointc) { - int i, ret, parent_irq; - unsigned long node_map; + int parent_irq, ret; struct eiointc_priv *priv; int node; =20 @@ -397,37 +434,14 @@ int __init eiointc_acpi_init(struct irq_domain *paren= t, goto out_free_priv; } =20 + priv->vec_count =3D VEC_COUNT; priv->node =3D acpi_eiointc->node; - node_map =3D acpi_eiointc->node_map ? : -1ULL; - - for_each_possible_cpu(i) { - if (node_map & (1ULL << cpu_to_eio_node(i))) { - node_set(cpu_to_eio_node(i), priv->node_map); - cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, cpumask_of(i)); - } - } - - /* Setup IRQ domain */ - priv->eiointc_domain =3D irq_domain_create_linear(priv->domain_handle, VE= C_COUNT, - &eiointc_domain_ops, priv); - if (!priv->eiointc_domain) { - pr_err("loongson-eiointc: cannot add IRQ domain\n"); - goto out_free_handle; - } - - eiointc_priv[nr_pics++] =3D priv; - - eiointc_router_init(0); =20 parent_irq =3D irq_create_mapping(parent, acpi_eiointc->cascade); - irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); =20 - if (nr_pics =3D=3D 1) { - register_syscore_ops(&eiointc_syscore_ops); - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, - "irqchip/loongarch/intc:starting", - eiointc_router_init, NULL); - } + ret =3D eiointc_init(priv, parent_irq, acpi_eiointc->node_map); + if (ret < 0) + goto out_free_handle; =20 if (cpu_has_flatmode) node =3D cpu_to_node(acpi_eiointc->node * CORES_PER_EIO_NODE); @@ -435,7 +449,10 @@ int __init eiointc_acpi_init(struct irq_domain *parent, node =3D acpi_eiointc->node; acpi_set_vec_parent(node, priv->eiointc_domain, pch_group); acpi_set_vec_parent(node, priv->eiointc_domain, msi_group); + ret =3D acpi_cascade_irqdomain_init(); + if (ret < 0) + goto out_free_handle; =20 return ret; =20 @@ -447,3 +464,49 @@ int __init eiointc_acpi_init(struct irq_domain *parent, =20 return -ENOMEM; } + +static int __init eiointc_of_init(struct device_node *of_node, + struct device_node *parent) +{ + int parent_irq, ret; + struct eiointc_priv *priv; + + priv =3D kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + parent_irq =3D irq_of_parse_and_map(of_node, 0); + if (parent_irq <=3D 0) { + ret =3D -ENODEV; + goto out_free_priv; + } + + ret =3D irq_set_handler_data(parent_irq, priv); + if (ret < 0) + goto out_free_priv; + + /* + * In particular, the number of devices supported by the LS2K0500 + * extended I/O interrupt vector is 128. + */ + if (of_device_is_compatible(of_node, "loongson,ls2k0500-eiointc")) + priv->vec_count =3D 128; + else + priv->vec_count =3D VEC_COUNT; + + priv->node =3D 0; + priv->domain_handle =3D of_node_to_fwnode(of_node); + + ret =3D eiointc_init(priv, parent_irq, 0); + if (ret < 0) + goto out_free_priv; + + return 0; + +out_free_priv: + kfree(priv); + return ret; +} + +IRQCHIP_DECLARE(loongson_ls2k0500_eiointc, "loongson,ls2k0500-eiointc", ei= ointc_of_init); +IRQCHIP_DECLARE(loongson_ls2k2000_eiointc, "loongson,ls2k2000-eiointc", ei= ointc_of_init); --=20 2.39.1