From nobody Mon Feb 9 09:42:37 2026 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 401F37DA7E; Thu, 15 Aug 2024 11:26:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723721180; cv=none; b=TJ98QELyESC9DCKUtqJ3q54OpsHXDlaSxph6qunX5uj6rBIYRkHWINEzKR+ne20SriXgudHB9nDSsl+ttKPBOhJDUk1FdT3nZOiz9arBvWf5OPam6mH0y8LPtGY+67xCvWfXXi26pnCd2qZItDnVDVwQdOdGn5CqzwNJBg6AKfA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723721180; c=relaxed/simple; bh=99qHv74OASxAlC3ZKG47sDwra5wLJQY/UxW60bDJNYQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=tAyuKICZYG5ALHP8hA+PcaKh0EqoU1790ipZr51+ogLUh8f93+w8dMFDWJT+BYo1YwAfRtAbPN11MpGtZL28/VlwKYrB+XUoZ/PlsPJZz6t0vFYBCbM7r7RTRyNMOBDb8kcr7C4NdULLYeELUma90oRQh/0S8T5MVyBX3nuKySI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [10.2.10.34]) by gateway (Coremail) with SMTP id _____8AxHuvY5b1mkcgUAA--.49389S3; Thu, 15 Aug 2024 19:26:16 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.10.34]) by front1 (Coremail) with SMTP id qMiowMAxVODU5b1mwT4VAA--.33702S3; Thu, 15 Aug 2024 19:26:16 +0800 (CST) From: Tianyang Zhang To: corbet@lwn.net, alexs@kernel.org, chenhuacai@kernel.org, kernel@xen0n.name, tglx@linutronix.de, jiaxun.yang@flygoat.com, gaoliang@loongson.cn, wangliupu@loongson.cn, lvjianmin@loongson.cn, zhangtianyang@loongson.cn, yijun@loongson.cn, mhocko@suse.com, akpm@linux-foundation.org, dianders@chromium.org, maobibo@loongson.cn, xry111@xry111.site, zhaotianrui@loongson.cn, nathan@kernel.org, yangtiezhu@loongson.cn, zhoubinbin@loongson.cn Cc: loongarch@lists.linux.dev, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Huacai Chen Subject: [PATCH v10 1/2] irqchip/loongson-pch-msi: Switch to MSI parent domains Date: Thu, 15 Aug 2024 19:26:07 +0800 Message-Id: <20240815112608.26925-2-zhangtianyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20240815112608.26925-1-zhangtianyang@loongson.cn> References: <20240815112608.26925-1-zhangtianyang@loongson.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qMiowMAxVODU5b1mwT4VAA--.33702S3 X-CM-SenderInfo: x2kd0wxwld05hdqjqz5rrqw2lrqou0/ X-Coremail-Antispam: 1Uk129KBj93XoWxAryxAryrKr1xXFyUXw43urX_yoWrAw4fpF W3u342vrW8Aay8ZFZ7GwnrZFy3Cas3tFWUta1fGw1ftry8Zw1vgF1DtF42krWYyFWkGryD Aa18Jr4Dua1DGFbCm3ZEXasCq-sJn29KB7ZKAUJUUUUD529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBab4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AK xVW8Jr0_Cr1UM2kKe7AKxVWUAVWUtwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07 AIYIkI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWU tVWrXwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7V AKI48JMxkF7I0En4kS14v26r1q6r43MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY 6r1j6r4UMxCIbckI1I0E14v26r126r1DMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7 xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVW8ZVWrXwCIc40Y0x0EwIxGrwCI42IY6xII jxv20xvE14v26r4j6ryUMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw2 0EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Cr0_Gr1UMIIF0xvEx4A2jsIEc7Cj xVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jr9NsUUUUU= Content-Type: text/plain; charset="utf-8" From: Huacai Chen Now remove the global PCI/MSI irqdomain implementation and provide the required MSI parent functionality by filling in msi_parent_ops, so the PCI/MSI code can detect the new parent and setup per-device MSI domains. Signed-off-by: Huacai Chen Signed-off-by: Tianyang Zhang --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-loongson-pch-msi.c | 58 ++++++++++---------------- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d078bdc48c38..341cd9ca5a05 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -685,6 +685,7 @@ config LOONGSON_PCH_MSI depends on PCI default MACH_LOONGSON64 select IRQ_DOMAIN_HIERARCHY + select IRQ_MSI_LIB select PCI_MSI help Support for the Loongson PCH MSI Controller. diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-l= oongson-pch-msi.c index dd4d699170f4..2242f63c66fc 100644 --- a/drivers/irqchip/irq-loongson-pch-msi.c +++ b/drivers/irqchip/irq-loongson-pch-msi.c @@ -15,6 +15,8 @@ #include #include =20 +#include "irq-msi-lib.h" + static int nr_pics; =20 struct pch_msi_data { @@ -27,26 +29,6 @@ struct pch_msi_data { =20 static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS]; =20 -static void pch_msi_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void pch_msi_unmask_msi_irq(struct irq_data *d) -{ - irq_chip_unmask_parent(d); - pci_msi_unmask_irq(d); -} - -static struct irq_chip pch_msi_irq_chip =3D { - .name =3D "PCH PCI MSI", - .irq_mask =3D pch_msi_mask_msi_irq, - .irq_unmask =3D pch_msi_unmask_msi_irq, - .irq_ack =3D irq_chip_ack_parent, - .irq_set_affinity =3D irq_chip_set_affinity_parent, -}; - static int pch_msi_allocate_hwirq(struct pch_msi_data *priv, int num_req) { int first; @@ -85,12 +67,6 @@ static void pch_msi_compose_msi_msg(struct irq_data *dat= a, msg->data =3D data->hwirq; } =20 -static struct msi_domain_info pch_msi_domain_info =3D { - .flags =3D MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, - .chip =3D &pch_msi_irq_chip, -}; - static struct irq_chip middle_irq_chip =3D { .name =3D "PCH MSI", .irq_mask =3D irq_chip_mask_parent, @@ -155,13 +131,31 @@ static void pch_msi_middle_domain_free(struct irq_dom= ain *domain, static const struct irq_domain_ops pch_msi_middle_domain_ops =3D { .alloc =3D pch_msi_middle_domain_alloc, .free =3D pch_msi_middle_domain_free, + .select =3D msi_lib_irq_domain_select, +}; + +#define PCH_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) + +#define PCH_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ + MSI_FLAG_PCI_MSIX | \ + MSI_FLAG_MULTI_PCI_MSI) + +static struct msi_parent_ops pch_msi_parent_ops =3D { + .required_flags =3D PCH_MSI_FLAGS_REQUIRED, + .supported_flags =3D PCH_MSI_FLAGS_SUPPORTED, + .bus_select_mask =3D MATCH_PCI_MSI, + .bus_select_token =3D DOMAIN_BUS_NEXUS, + .prefix =3D "PCH-", + .init_dev_msi_info =3D msi_lib_init_dev_msi_info, }; =20 static int pch_msi_init_domains(struct pch_msi_data *priv, struct irq_domain *parent, struct fwnode_handle *domain_handle) { - struct irq_domain *middle_domain, *msi_domain; + struct irq_domain *middle_domain; =20 middle_domain =3D irq_domain_create_hierarchy(parent, 0, priv->num_irqs, domain_handle, @@ -174,14 +168,8 @@ static int pch_msi_init_domains(struct pch_msi_data *p= riv, =20 irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); =20 - msi_domain =3D pci_msi_create_irq_domain(domain_handle, - &pch_msi_domain_info, - middle_domain); - if (!msi_domain) { - pr_err("Failed to create PCI MSI domain\n"); - irq_domain_remove(middle_domain); - return -ENOMEM; - } + middle_domain->flags |=3D IRQ_DOMAIN_FLAG_MSI_PARENT; + middle_domain->msi_parent_ops =3D &pch_msi_parent_ops; =20 return 0; } --=20 2.20.1 From nobody Mon Feb 9 09:42:37 2026 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7B6B91714C7; Thu, 15 Aug 2024 11:26:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723721183; cv=none; b=lkUEGYnVrwa2HWxtmpnT6xFO+JUd76qiJv5O5IRfOqrqiYUnIVfxNHY9VDAvug/5n39ssRgkkFFyF9UIAVDmL3juQvF/wa0sBIPa1gNG+bYliKahM1cF97yMcAcHnQCwcGUkvuRsbffdPOvbRgJXFCCtt7iZwGdxNmEY4AsOYVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723721183; c=relaxed/simple; bh=q3vkPy4T7mbjF+x5fyskpB4/4T8eGbH7g+VwXS7RsMw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=gvzzc/IvO5BpWmbkV8uu3U0qFCLZ6ZkXzWhdQGsvUlYyTSyk1JbBmTZGSiHu2xD0BHamgJsibUNG7vFZ7xYRQzn87yzxadz4rmupAnYjdw/SC7j4FOjQhIs2Js55GkaXOjuGSVQCGqiFTRbvb4pvSi81vqGWhLkC9aFIRq+yWRY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [10.2.10.34]) by gateway (Coremail) with SMTP id _____8CxKJra5b1moMgUAA--.11687S3; Thu, 15 Aug 2024 19:26:18 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.10.34]) by front1 (Coremail) with SMTP id qMiowMAxVODU5b1mwT4VAA--.33702S4; Thu, 15 Aug 2024 19:26:17 +0800 (CST) From: Tianyang Zhang To: corbet@lwn.net, alexs@kernel.org, chenhuacai@kernel.org, kernel@xen0n.name, tglx@linutronix.de, jiaxun.yang@flygoat.com, gaoliang@loongson.cn, wangliupu@loongson.cn, lvjianmin@loongson.cn, zhangtianyang@loongson.cn, yijun@loongson.cn, mhocko@suse.com, akpm@linux-foundation.org, dianders@chromium.org, maobibo@loongson.cn, xry111@xry111.site, zhaotianrui@loongson.cn, nathan@kernel.org, yangtiezhu@loongson.cn, zhoubinbin@loongson.cn Cc: loongarch@lists.linux.dev, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Huacai Chen Subject: [PATCH v10 2/2] irqchip/loongarch-avec: Add AVEC irqchip support Date: Thu, 15 Aug 2024 19:26:08 +0800 Message-Id: <20240815112608.26925-3-zhangtianyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20240815112608.26925-1-zhangtianyang@loongson.cn> References: <20240815112608.26925-1-zhangtianyang@loongson.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qMiowMAxVODU5b1mwT4VAA--.33702S4 X-CM-SenderInfo: x2kd0wxwld05hdqjqz5rrqw2lrqou0/ X-Coremail-Antispam: 1Uk129KBj9fXoWfuFy5CryfJw4xWrW3WF1kXrc_yoW5ZF1rWo WfZF1Yy348Gr45urZ8Jw1qqFWUZr4qkrWkA3srua13CayxAF15KryUKw13KFy3Grs5GFZx CayfWrn3Jayxtrn5l-sFpf9Il3svdjkaLaAFLSUrUUUU5b8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn0xqx4xG64xvF2IEw4CE5I8CrVC2j2Jv73VFW2AGmfu7bjvjm3AaLaJ3 UjIYCTnIWjp_UUUYZ7kC6x804xWl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI 8IcIk0rVWrJVCq3wAFIxvE14AKwVWUXVWUAwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xG Y2AK021l84ACjcxK6xIIjxv20xvE14v26ryj6F1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14 v26r4j6F4UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr1j6F4UJwAaw2AFwI0_JF0_Jw1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2 xF0cIa020Ex4CE44I27wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_ Jw0_WrylYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvY0x 0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkE bVWUJVW8JwCFI7km07C267AKxVWUAVWUtwC20s026c02F40E14v26r1j6r18MI8I3I0E74 80Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0 I7IYx2IY67AKxVW5JVW7JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04 k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26F4j6r4UJwCI42IY6I8E87Iv6xkF 7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxU4YLvDUUUU Introduce the advanced extended interrupt controllers (AVECINTC). This feature will allow each core to have 256 independent interrupt vectors and MSI interrupts can be independently routed to any vector on any CPU. The whole topology of irqchips in LoongArch machines looks like this if AVECINTC is supported: +-----+ +-----------------------+ +-------+ | IPI | --> | CPUINTC | <-- | Timer | +-----+ +-----------------------+ +-------+ ^ ^ ^ | | | +---------+ +----------+ +---------+ +-------+ | EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs | +---------+ +----------+ +---------+ +-------+ ^ ^ | | +---------+ +---------+ | PCH-PIC | | PCH-MSI | +---------+ +---------+ ^ ^ ^ | | | +---------+ +---------+ +---------+ | Devices | | PCH-LPC | | Devices | +---------+ +---------+ +---------+ ^ | +---------+ | Devices | +---------+ Co-developed-by: Jianmin Lv Signed-off-by: Jianmin Lv Co-developed-by: Liupu Wang Signed-off-by: Liupu Wang Co-developed-by: Huacai Chen Signed-off-by: Huacai Chen Signed-off-by: Tianyang Zhang --- .../arch/loongarch/irq-chip-model.rst | 32 ++ .../zh_CN/arch/loongarch/irq-chip-model.rst | 32 ++ arch/loongarch/Kconfig | 1 + arch/loongarch/include/asm/cpu-features.h | 1 + arch/loongarch/include/asm/cpu.h | 2 + arch/loongarch/include/asm/hardirq.h | 3 +- arch/loongarch/include/asm/hw_irq.h | 2 + arch/loongarch/include/asm/irq.h | 25 +- arch/loongarch/include/asm/loongarch.h | 18 +- arch/loongarch/include/asm/smp.h | 2 + arch/loongarch/kernel/cpu-probe.c | 3 +- arch/loongarch/kernel/irq.c | 15 +- arch/loongarch/kernel/paravirt.c | 5 + arch/loongarch/kernel/smp.c | 6 + drivers/irqchip/Makefile | 2 +- drivers/irqchip/irq-loongarch-avec.c | 426 ++++++++++++++++++ drivers/irqchip/irq-loongarch-cpu.c | 5 +- drivers/irqchip/irq-loongson-eiointc.c | 7 +- drivers/irqchip/irq-loongson-pch-msi.c | 24 +- include/linux/cpuhotplug.h | 3 +- 20 files changed, 591 insertions(+), 23 deletions(-) create mode 100644 drivers/irqchip/irq-loongarch-avec.c diff --git a/Documentation/arch/loongarch/irq-chip-model.rst b/Documentatio= n/arch/loongarch/irq-chip-model.rst index 7988f4192363..6dd48256e39f 100644 --- a/Documentation/arch/loongarch/irq-chip-model.rst +++ b/Documentation/arch/loongarch/irq-chip-model.rst @@ -85,6 +85,38 @@ to CPUINTC directly:: | Devices | +---------+ =20 +Advanced Extended IRQ model +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interru= pt go +to CPUINTC directly, CPU UARTS interrupts go to LIOINTC, PCH-MSI interrupt= s go +to AVECINTC, and then go to CPUINTC directly, while all other devices inte= rrupts +go to PCH-PIC/PCH-LPC and gathered by EIOINTC, and then go to CPUINTC dire= ctly:: + + +-----+ +-----------------------+ +-------+ + | IPI | --> | CPUINTC | <-- | Timer | + +-----+ +-----------------------+ +-------+ + ^ ^ ^ + | | | + +---------+ +----------+ +---------+ +-------+ + | EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs | + +---------+ +----------+ +---------+ +-------+ + ^ ^ + | | + +---------+ +---------+ + | PCH-PIC | | PCH-MSI | + +---------+ +---------+ + ^ ^ ^ + | | | + +---------+ +---------+ +---------+ + | Devices | | PCH-LPC | | Devices | + +---------+ +---------+ +---------+ + ^ + | + +---------+ + | Devices | + +---------+ + ACPI-related definitions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model= .rst b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst index f1e9ab18206c..472761938682 100644 --- a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst +++ b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst @@ -87,6 +87,38 @@ PCH-LPC/PCH-MSI=EF=BC=8C=E7=84=B6=E5=90=8E=E8=A2=ABEIOIN= TC=E7=BB=9F=E4=B8=80=E6=94=B6=E9=9B=86=EF=BC=8C=E5=86=8D=E7=9B=B4=E6=8E=A5= =E5=88=B0=E8=BE=BECPUINTC:: | Devices | +---------+ =20 +=E9=AB=98=E7=BA=A7=E6=89=A9=E5=B1=95IRQ=E6=A8=A1=E5=9E=8B +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +=E5=9C=A8=E8=BF=99=E7=A7=8D=E6=A8=A1=E5=9E=8B=E9=87=8C=E9=9D=A2=EF=BC=8CIP= I=EF=BC=88Inter-Processor Interrupt=EF=BC=89=E5=92=8CCPU=E6=9C=AC=E5=9C=B0= =E6=97=B6=E9=92=9F=E4=B8=AD=E6=96=AD=E7=9B=B4=E6=8E=A5=E5=8F=91=E9=80=81=E5= =88=B0CPUINTC=EF=BC=8C +CPU=E4=B8=B2=E5=8F=A3=EF=BC=88UARTs=EF=BC=89=E4=B8=AD=E6=96=AD=E5=8F=91=E9= =80=81=E5=88=B0LIOINTC=EF=BC=8CPCH-MSI=E4=B8=AD=E6=96=AD=E5=8F=91=E9=80=81= =E5=88=B0AVECINTC=EF=BC=8C=E8=80=8C=E5=90=8E=E9=80=9A=E8=BF=87AVECINTC=E7= =9B=B4=E6=8E=A5 +=E9=80=81=E8=BE=BECPUINTC=EF=BC=8C=E8=80=8C=E5=85=B6=E4=BB=96=E6=89=80=E6= =9C=89=E8=AE=BE=E5=A4=87=E7=9A=84=E4=B8=AD=E6=96=AD=E5=88=99=E5=88=86=E5=88= =AB=E5=8F=91=E9=80=81=E5=88=B0=E6=89=80=E8=BF=9E=E6=8E=A5=E7=9A=84PCH-PIC/P= CH-LPC=EF=BC=8C=E7=84=B6=E5=90=8E=E7=94=B1EIOINTC +=E7=BB=9F=E4=B8=80=E6=94=B6=E9=9B=86=EF=BC=8C=E5=86=8D=E7=9B=B4=E6=8E=A5= =E5=88=B0=E8=BE=BECPUINTC:: + + +-----+ +-----------------------+ +-------+ + | IPI | --> | CPUINTC | <-- | Timer | + +-----+ +-----------------------+ +-------+ + ^ ^ ^ + | | | + +---------+ +----------+ +---------+ +-------+ + | EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs | + +---------+ +----------+ +---------+ +-------+ + ^ ^ + | | + +---------+ +---------+ + | PCH-PIC | | PCH-MSI | + +---------+ +---------+ + ^ ^ ^ + | | | + +---------+ +---------+ +---------+ + | Devices | | PCH-LPC | | Devices | + +---------+ +---------+ +---------+ + ^ + | + +---------+ + | Devices | + +---------+ + ACPI=E7=9B=B8=E5=85=B3=E7=9A=84=E5=AE=9A=E4=B9=89 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 70f169210b52..0e3abf7b0bd3 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -85,6 +85,7 @@ config LOONGARCH select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY select GENERIC_IOREMAP if !ARCH_IOREMAP + select GENERIC_IRQ_MATRIX_ALLOCATOR select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/inc= lude/asm/cpu-features.h index 2eafe6a6aca8..16a716f88a5c 100644 --- a/arch/loongarch/include/asm/cpu-features.h +++ b/arch/loongarch/include/asm/cpu-features.h @@ -65,5 +65,6 @@ #define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID) #define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR) #define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW) +#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT) =20 #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/= cpu.h index 48b9f7168bcc..843f9c4ec980 100644 --- a/arch/loongarch/include/asm/cpu.h +++ b/arch/loongarch/include/asm/cpu.h @@ -99,6 +99,7 @@ enum cpu_type_enum { #define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */ #define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */ #define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */ +#define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */ =20 #define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) #define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) @@ -127,5 +128,6 @@ enum cpu_type_enum { #define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID) #define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR) #define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW) +#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT) =20 #endif /* _ASM_CPU_H */ diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/= asm/hardirq.h index 1d7feb719515..10da8d6961cb 100644 --- a/arch/loongarch/include/asm/hardirq.h +++ b/arch/loongarch/include/asm/hardirq.h @@ -12,12 +12,13 @@ extern void ack_bad_irq(unsigned int irq); #define ack_bad_irq ack_bad_irq =20 -#define NR_IPI 3 +#define NR_IPI 4 =20 enum ipi_msg_type { IPI_RESCHEDULE, IPI_CALL_FUNCTION, IPI_IRQ_WORK, + IPI_CLEAR_VECTOR, }; =20 typedef struct { diff --git a/arch/loongarch/include/asm/hw_irq.h b/arch/loongarch/include/a= sm/hw_irq.h index af4f4e8fbd85..8156ffb67415 100644 --- a/arch/loongarch/include/asm/hw_irq.h +++ b/arch/loongarch/include/asm/hw_irq.h @@ -9,6 +9,8 @@ =20 extern atomic_t irq_err_count; =20 +#define ARCH_IRQ_INIT_FLAGS IRQ_NOPROBE + /* * interrupt-retrigger: NOP for now. This may not be appropriate for all * machines, we'll see ... diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/= irq.h index 480418bc5071..1b255bf8168f 100644 --- a/arch/loongarch/include/asm/irq.h +++ b/arch/loongarch/include/asm/irq.h @@ -39,11 +39,22 @@ void spurious_interrupt(void); =20 #define NR_IRQS_LEGACY 16 =20 +/* + * 256 Vectors Mapping for AVECINTC: + * + * 0 - 15: Mapping classic IPs, e.g. IP0-12. + * 16 - 255: Mapping vectors for external IRQ. + * + */ +#define NR_VECTORS 256 +#define NR_LEGACY_VECTORS 16 +#define IRQ_MATRIX_BITS NR_VECTORS + #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclud= e_cpu); =20 #define MAX_IO_PICS 2 -#define NR_IRQS (64 + (256 * MAX_IO_PICS)) +#define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS)) =20 struct acpi_vector_group { int node; @@ -65,7 +76,7 @@ extern struct acpi_vector_group msi_group[MAX_IO_PICS]; #define LOONGSON_LPC_LAST_IRQ (LOONGSON_LPC_IRQ_BASE + 15) =20 #define LOONGSON_CPU_IRQ_BASE 16 -#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 14) +#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 15) =20 #define LOONGSON_PCH_IRQ_BASE 64 #define LOONGSON_PCH_ACPI_IRQ (LOONGSON_PCH_IRQ_BASE + 47) @@ -92,15 +103,21 @@ int liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc); int eiointc_acpi_init(struct irq_domain *parent, struct acpi_madt_eio_pic *acpi_eiointc); +int avecintc_acpi_init(struct irq_domain *parent); + +void complete_irq_moving(void); =20 int htvec_acpi_init(struct irq_domain *parent, struct acpi_madt_ht_pic *acpi_htvec); int pch_lpc_acpi_init(struct irq_domain *parent, struct acpi_madt_lpc_pic *acpi_pchlpc); -int pch_msi_acpi_init(struct irq_domain *parent, - struct acpi_madt_msi_pic *acpi_pchmsi); int pch_pic_acpi_init(struct irq_domain *parent, struct acpi_madt_bio_pic *acpi_pchpic); +int pch_msi_acpi_init(struct irq_domain *parent, + struct acpi_madt_msi_pic *acpi_pchmsi); +int pch_msi_acpi_init_v2(struct irq_domain *parent, + struct acpi_madt_msi_pic *acpi_pchmsi); + int find_pch_pic(u32 gsi); struct fwnode_handle *get_pch_msi_handle(int pci_segment); =20 diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/includ= e/asm/loongarch.h index 04a78010fc72..70834a47257d 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -253,8 +253,8 @@ #define CSR_ESTAT_EXC_WIDTH 6 #define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT) #define CSR_ESTAT_IS_SHIFT 0 -#define CSR_ESTAT_IS_WIDTH 14 -#define CSR_ESTAT_IS (_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT) +#define CSR_ESTAT_IS_WIDTH 15 +#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT) =20 #define LOONGARCH_CSR_ERA 0x6 /* ERA */ =20 @@ -649,6 +649,13 @@ =20 #define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ =20 +#define LOONGARCH_CSR_ISR0 0xa0 +#define LOONGARCH_CSR_ISR1 0xa1 +#define LOONGARCH_CSR_ISR2 0xa2 +#define LOONGARCH_CSR_ISR3 0xa3 + +#define LOONGARCH_CSR_IRR 0xa4 + #define LOONGARCH_CSR_PRID 0xc0 =20 /* Shadow MCSR : 0xc0 ~ 0xff */ @@ -1011,7 +1018,7 @@ /* * CSR_ECFG IM */ -#define ECFG0_IM 0x00001fff +#define ECFG0_IM 0x00005fff #define ECFGB_SIP0 0 #define ECFGF_SIP0 (_ULCAST_(1) << ECFGB_SIP0) #define ECFGB_SIP1 1 @@ -1054,6 +1061,7 @@ #define IOCSRF_EIODECODE BIT_ULL(9) #define IOCSRF_FLATMODE BIT_ULL(10) #define IOCSRF_VM BIT_ULL(11) +#define IOCSRF_AVEC BIT_ULL(15) =20 #define LOONGARCH_IOCSR_VENDOR 0x10 =20 @@ -1065,6 +1073,7 @@ #define IOCSR_MISC_FUNC_SOFT_INT BIT_ULL(10) #define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) #define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) +#define IOCSR_MISC_FUNC_AVEC_EN BIT_ULL(51) =20 #define LOONGARCH_IOCSR_CPUTEMP 0x428 =20 @@ -1387,9 +1396,10 @@ __BUILD_CSR_OP(tlbidx) #define INT_TI 11 /* Timer */ #define INT_IPI 12 #define INT_NMI 13 +#define INT_AVEC 14 =20 /* ExcCodes corresponding to interrupts */ -#define EXCCODE_INT_NUM (INT_NMI + 1) +#define EXCCODE_INT_NUM (INT_AVEC + 1) #define EXCCODE_INT_START 64 #define EXCCODE_INT_END (EXCCODE_INT_START + EXCCODE_INT_NUM - 1) =20 diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/= smp.h index 50db503f44e3..3383c9d24e94 100644 --- a/arch/loongarch/include/asm/smp.h +++ b/arch/loongarch/include/asm/smp.h @@ -70,10 +70,12 @@ extern int __cpu_logical_map[NR_CPUS]; #define ACTION_RESCHEDULE 1 #define ACTION_CALL_FUNCTION 2 #define ACTION_IRQ_WORK 3 +#define ACTION_CLEAR_VECTOR 4 #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU) #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE) #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION) #define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK) +#define SMP_CLEAR_VECTOR BIT(ACTION_CLEAR_VECTOR) =20 struct secondary_data { unsigned long stack; diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-= probe.c index 55320813ee08..14f0449f5452 100644 --- a/arch/loongarch/kernel/cpu-probe.c +++ b/arch/loongarch/kernel/cpu-probe.c @@ -106,7 +106,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *= c) elf_hwcap |=3D HWCAP_LOONGARCH_CRC32; } =20 - config =3D read_cpucfg(LOONGARCH_CPUCFG2); if (config & CPUCFG2_LAM) { c->options |=3D LOONGARCH_CPU_LAM; @@ -174,6 +173,8 @@ static void cpu_probe_common(struct cpuinfo_loongarch *= c) c->options |=3D LOONGARCH_CPU_FLATMODE; if (config & IOCSRF_EIODECODE) c->options |=3D LOONGARCH_CPU_EIODECODE; + if (config & IOCSRF_AVEC) + c->options |=3D LOONGARCH_CPU_AVECINT; if (config & IOCSRF_VM) c->options |=3D LOONGARCH_CPU_HYPERVISOR; =20 diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c index f4991c03514f..d129039b368b 100644 --- a/arch/loongarch/kernel/irq.c +++ b/arch/loongarch/kernel/irq.c @@ -87,6 +87,18 @@ static void __init init_vec_parent_group(void) acpi_table_parse(ACPI_SIG_MCFG, early_pci_mcfg_parse); } =20 +int __init arch_probe_nr_irqs(void) +{ + int nr_io_pics =3D bitmap_weight(loongson_sysconf.cores_io_master, NR_CPU= S); + + if (!cpu_has_avecint) + nr_irqs =3D (64 + NR_VECTORS * nr_io_pics); + else + nr_irqs =3D (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics)); + + return NR_IRQS_LEGACY; +} + void __init init_IRQ(void) { int i; @@ -102,9 +114,6 @@ void __init init_IRQ(void) mp_ops.init_ipi(); #endif =20 - for (i =3D 0; i < NR_IRQS; i++) - irq_set_noprobe(i); - for_each_possible_cpu(i) { page =3D alloc_pages_node(cpu_to_node(i), GFP_KERNEL, order); =20 diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/parav= irt.c index 9c9b75b76f62..4d736a4e488d 100644 --- a/arch/loongarch/kernel/paravirt.c +++ b/arch/loongarch/kernel/paravirt.c @@ -134,6 +134,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev) info->ipi_irqs[IPI_IRQ_WORK]++; } =20 + if (action & SMP_CLEAR_VECTOR) { + complete_irq_moving(); + info->ipi_irqs[IPI_CLEAR_VECTOR]++; + } + return IRQ_HANDLED; } =20 diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index ca405ab86aae..4adbbef3450a 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -72,6 +72,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = =3D { [IPI_RESCHEDULE] =3D "Rescheduling interrupts", [IPI_CALL_FUNCTION] =3D "Function call interrupts", [IPI_IRQ_WORK] =3D "IRQ work interrupts", + [IPI_CLEAR_VECTOR] =3D "Clear vector interrupts", }; =20 void show_ipi_list(struct seq_file *p, int prec) @@ -248,6 +249,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, voi= d *dev) per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++; } =20 + if (action & SMP_CLEAR_VECTOR) { + complete_irq_moving(); + per_cpu(irq_stat, cpu).ipi_irqs[IPI_CLEAR_VECTOR]++; + } + return IRQ_HANDLED; } =20 diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 15635812b2d6..e3679ec2b9f7 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -110,7 +110,7 @@ obj-$(CONFIG_LS1X_IRQ) +=3D irq-ls1x.o obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) +=3D irq-ti-sci-intr.o obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) +=3D irq-ti-sci-inta.o obj-$(CONFIG_TI_PRUSS_INTC) +=3D irq-pruss-intc.o -obj-$(CONFIG_IRQ_LOONGARCH_CPU) +=3D irq-loongarch-cpu.o +obj-$(CONFIG_IRQ_LOONGARCH_CPU) +=3D irq-loongarch-cpu.o irq-loongarch-av= ec.o obj-$(CONFIG_LOONGSON_LIOINTC) +=3D irq-loongson-liointc.o obj-$(CONFIG_LOONGSON_EIOINTC) +=3D irq-loongson-eiointc.o obj-$(CONFIG_LOONGSON_HTPIC) +=3D irq-loongson-htpic.o diff --git a/drivers/irqchip/irq-loongarch-avec.c b/drivers/irqchip/irq-loo= ngarch-avec.c new file mode 100644 index 000000000000..d66fae41d95a --- /dev/null +++ b/drivers/irqchip/irq-loongarch-avec.c @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2024 Loongson Technologies, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "irq-msi-lib.h" + +#define VECTORS_PER_REG 64 +#define IRR_VECTOR_MASK 0xffUL +#define IRR_INVALID_MASK 0x80000000UL +#define AVEC_MSG_OFFSET 0x100000 + +static phys_addr_t msi_base_addr; + +#ifdef CONFIG_SMP +struct pending_list { + struct list_head head; +}; + +static struct cpumask intersect_mask; +static DEFINE_PER_CPU(struct pending_list, pending_list); +#endif + +static DEFINE_PER_CPU(struct irq_desc * [NR_VECTORS], irq_map); + +struct avecintc_chip { + struct fwnode_handle *fwnode; + struct irq_domain *domain; + struct irq_matrix *vector_matrix; + raw_spinlock_t lock; +}; + +static struct avecintc_chip loongarch_avec; + +struct avecintc_data { + struct list_head entry; + unsigned int cpu; + unsigned int vec; + unsigned int prev_cpu; + unsigned int prev_vec; + unsigned int moving : 1, + managed : 1; +}; + +static inline void avecintc_ack_irq(struct irq_data *d) +{ +} + +static inline void avecintc_mask_irq(struct irq_data *d) +{ +} + +static inline void avecintc_unmask_irq(struct irq_data *d) +{ +} + +#ifdef CONFIG_SMP +static inline void pending_list_init(int cpu) +{ + struct pending_list *plist =3D per_cpu_ptr(&pending_list, cpu); + + INIT_LIST_HEAD(&plist->head); +} + +static void avecintc_sync(struct avecintc_data *adata) +{ + struct pending_list *plist; + + if (cpu_online(adata->prev_cpu)) { + plist =3D per_cpu_ptr(&pending_list, adata->prev_cpu); + list_add_tail(&adata->entry, &plist->head); + adata->moving =3D 1; + mp_ops.send_ipi_single(adata->prev_cpu, ACTION_CLEAR_VECTOR); + } +} + +static int avecintc_set_affinity(struct irq_data *data, const struct cpuma= sk *dest, bool force) +{ + unsigned int cpu, ret, vector; + struct avecintc_data *adata; + + scoped_guard(raw_spinlock, &loongarch_avec.lock) { + adata =3D irq_data_get_irq_chip_data(data); + + if (adata->moving) + return -EBUSY; + + if (adata->vec =3D=3D UINT_MAX) + return -EINVAL; + + if (cpu_online(adata->cpu) && cpumask_test_cpu(adata->cpu, dest)) + return 0; + + cpumask_and(&intersect_mask, dest, cpu_online_mask); + + ret =3D irq_matrix_alloc(loongarch_avec.vector_matrix, &intersect_mask, = false, &cpu); + if (ret < 0) + return ret; + + vector =3D ret; + adata->cpu =3D cpu; + adata->vec =3D vector; + per_cpu_ptr(irq_map, adata->cpu)[adata->vec] =3D irq_data_to_desc(data); + avecintc_sync(adata); + } + + irq_data_update_effective_affinity(data, cpumask_of(cpu)); + + return IRQ_SET_MASK_OK; +} + +static int avecintc_cpu_online(unsigned int cpu) +{ + if (!loongarch_avec.vector_matrix) + return 0; + + guard(raw_spinlock)(&loongarch_avec.lock); + + irq_matrix_online(loongarch_avec.vector_matrix); + + pending_list_init(cpu); + + return 0; +} + +static int avecintc_cpu_offline(unsigned int cpu) +{ + struct pending_list *plist =3D per_cpu_ptr(&pending_list, cpu); + + if (!loongarch_avec.vector_matrix) + return 0; + + guard(raw_spinlock)(&loongarch_avec.lock); + + if (!list_empty(&plist->head)) + pr_warn("CPU#%d vector is busy\n", cpu); + + irq_matrix_offline(loongarch_avec.vector_matrix); + + return 0; +} + +void complete_irq_moving(void) +{ + struct pending_list *plist =3D this_cpu_ptr(&pending_list); + struct avecintc_data *adata, *tdata; + int cpu, vector, bias; + uint64_t isr; + + guard(raw_spinlock)(&loongarch_avec.lock); + + list_for_each_entry_safe(adata, tdata, &plist->head, entry) { + cpu =3D adata->prev_cpu; + vector =3D adata->prev_vec; + bias =3D vector / VECTORS_PER_REG; + switch (bias) { + case 0: + isr =3D csr_read64(LOONGARCH_CSR_ISR0); + break; + case 1: + isr =3D csr_read64(LOONGARCH_CSR_ISR1); + break; + case 2: + isr =3D csr_read64(LOONGARCH_CSR_ISR2); + break; + case 3: + isr =3D csr_read64(LOONGARCH_CSR_ISR3); + break; + } + + if (isr & (1UL << (vector % VECTORS_PER_REG))) { + mp_ops.send_ipi_single(cpu, ACTION_CLEAR_VECTOR); + continue; + } + list_del(&adata->entry); + irq_matrix_free(loongarch_avec.vector_matrix, cpu, vector, adata->manage= d); + this_cpu_write(irq_map[vector], NULL); + adata->moving =3D 0; + adata->prev_cpu =3D adata->cpu; + adata->prev_vec =3D adata->vec; + } +} +#endif + +static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *m= sg) +{ + struct avecintc_data *adata =3D irq_data_get_irq_chip_data(d); + + msg->address_hi =3D 0x0; + msg->address_lo =3D (msi_base_addr | (adata->vec & 0xff) << 4) | + ((cpu_logical_map(adata->cpu & 0xffff)) << 12); + msg->data =3D 0x0; +} + +static struct irq_chip avec_irq_controller =3D { + .name =3D "AVECINTC", + .irq_ack =3D avecintc_ack_irq, + .irq_mask =3D avecintc_mask_irq, + .irq_unmask =3D avecintc_unmask_irq, +#ifdef CONFIG_SMP + .irq_set_affinity =3D avecintc_set_affinity, +#endif + .irq_compose_msi_msg =3D avecintc_compose_msi_msg, +}; + +static void avecintc_irq_dispatch(struct irq_desc *desc) +{ + struct irq_chip *chip =3D irq_desc_get_chip(desc); + struct irq_desc *d; + + chained_irq_enter(chip, desc); + + while (true) { + unsigned long vector =3D csr_read64(LOONGARCH_CSR_IRR); + if (vector & IRR_INVALID_MASK) + break; + + vector &=3D IRR_VECTOR_MASK; + + d =3D this_cpu_read(irq_map[vector]); + if (d) { + generic_handle_irq_desc(d); + } else { + spurious_interrupt(); + pr_warn("Unexpected IRQ occurs on CPU#%d [vector %ld]\n", smp_processor= _id(), vector); + } + } + + chained_irq_exit(chip, desc); +} + +static int avecintc_domain_alloc(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs, void *arg) +{ + guard(raw_spinlock_irqsave)(&loongarch_avec.lock); + + for (unsigned int i =3D 0; i < nr_irqs; i++) { + struct irq_data *irqd =3D irq_domain_get_irq_data(domain, virq + i); + struct avecintc_data *adata =3D kzalloc(sizeof(*adata), GFP_KERNEL); + unsigned int cpu, ret; + + if (!adata) + return -ENOMEM; + + ret =3D irq_matrix_alloc(loongarch_avec.vector_matrix, cpu_online_mask, = false, &cpu); + if (ret < 0) { + kfree(adata); + return ret; + } + + adata->moving =3D 0; + adata->prev_cpu =3D adata->cpu =3D cpu; + adata->prev_vec =3D adata->vec =3D ret; + adata->managed =3D irqd_affinity_is_managed(irqd); + irq_domain_set_info(domain, virq + i, virq + i, &avec_irq_controller, + adata, handle_edge_irq, NULL, NULL); + irqd_set_single_target(irqd); + irqd_set_affinity_on_activate(irqd); + + per_cpu_ptr(irq_map, adata->cpu)[adata->vec] =3D irq_data_to_desc(irqd); + } + + return 0; +} + +static void clear_free_vector(struct irq_data *irqd) +{ + struct avecintc_data *adata =3D irq_data_get_irq_chip_data(irqd); + bool managed =3D irqd_affinity_is_managed(irqd); + + per_cpu(irq_map, adata->cpu)[adata->vec] =3D NULL; + irq_matrix_free(loongarch_avec.vector_matrix, adata->cpu, adata->vec, man= aged); + adata->cpu =3D UINT_MAX; + adata->vec =3D UINT_MAX; + +#ifdef CONFIG_SMP + if (!adata->moving) + return; + + per_cpu(irq_map, adata->prev_cpu)[adata->prev_vec] =3D NULL; + irq_matrix_free(loongarch_avec.vector_matrix, + adata->prev_cpu, adata->prev_vec, adata->managed); + adata->moving =3D 0; + adata->prev_vec =3D UINT_MAX; + adata->prev_cpu =3D UINT_MAX; + list_del_init(&adata->entry); +#endif + kfree(adata); +} + +static void avecintc_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + guard(raw_spinlock_irqsave)(&loongarch_avec.lock); + + for (unsigned int i =3D 0; i < nr_irqs; i++) { + struct irq_data *d =3D irq_domain_get_irq_data(domain, virq + i); + if (d) { + clear_free_vector(d); + irq_domain_reset_irq_data(d); + } + } +} + +static const struct irq_domain_ops avecintc_domain_ops =3D { + .alloc =3D avecintc_domain_alloc, + .free =3D avecintc_domain_free, + .select =3D msi_lib_irq_domain_select, +}; + +static int __init irq_matrix_init(void) +{ + loongarch_avec.vector_matrix =3D irq_alloc_matrix(NR_VECTORS, 0, NR_VECTO= RS); + if (!loongarch_avec.vector_matrix) + return -ENOMEM; + + for (int i =3D 0; i < NR_LEGACY_VECTORS; i++) + irq_matrix_assign_system(loongarch_avec.vector_matrix, i, false); + + irq_matrix_online(loongarch_avec.vector_matrix); + + return 0; +} + +static int __init avecintc_init(struct irq_domain *parent) +{ + int ret, parent_irq; + unsigned long value; + + raw_spin_lock_init(&loongarch_avec.lock); + + loongarch_avec.fwnode =3D irq_domain_alloc_named_fwnode("AVECINTC"); + if (!loongarch_avec.fwnode) { + pr_err("Unable to allocate domain handle\n"); + ret =3D -ENOMEM; + goto out; + } + + loongarch_avec.domain =3D irq_domain_create_tree(loongarch_avec.fwnode, + &avecintc_domain_ops, NULL); + if (!loongarch_avec.domain) { + pr_err("Unable to create IRQ domain\n"); + ret =3D -ENOMEM; + goto out_free_handle; + } + + parent_irq =3D irq_create_mapping(parent, INT_AVEC); + if (!parent_irq) { + pr_err("Failed to mapping hwirq\n"); + ret =3D -EINVAL; + goto out_remove_domain; + } + + ret =3D irq_matrix_init(); + if (ret < 0) { + pr_err("Failed to init irq matrix\n"); + goto out_remove_domain; + } + irq_set_chained_handler_and_data(parent_irq, avecintc_irq_dispatch, NULL); + +#ifdef CONFIG_SMP + pending_list_init(0); + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_AVECINTC_STARTING, + "irqchip/loongarch/avecintc:starting", + avecintc_cpu_online, avecintc_cpu_offline); +#endif + value =3D iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); + value |=3D IOCSR_MISC_FUNC_AVEC_EN; + iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC); + + return ret; + +out_remove_domain: + irq_domain_remove(loongarch_avec.domain); +out_free_handle: + irq_domain_free_fwnode(loongarch_avec.fwnode); +out: + return ret; +} + +static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_msi_pic *pchmsi_entry =3D (struct acpi_madt_msi_pic *)he= ader; + + msi_base_addr =3D pchmsi_entry->msg_address - AVEC_MSG_OFFSET; + + return pch_msi_acpi_init_v2(loongarch_avec.domain, pchmsi_entry); +} + +static inline int __init acpi_cascade_irqdomain_init(void) +{ + return acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, = 1); +} + +int __init avecintc_acpi_init(struct irq_domain *parent) +{ + int ret =3D avecintc_init(parent); + if (ret < 0) { + pr_err("Failed to init IRQ domain\n"); + return ret; + } + + ret =3D acpi_cascade_irqdomain_init(); + if (ret < 0) { + pr_err("Failed to init cascade IRQ domain\n"); + return ret; + } + + return ret; +} diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loon= garch-cpu.c index 9d8f2c406043..4fdc490b94c3 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -138,7 +138,10 @@ static int __init acpi_cascade_irqdomain_init(void) if (r < 0) return r; =20 - return 0; + if (cpu_has_avecint) + r =3D avecintc_acpi_init(irq_domain); + + return r; } =20 static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-l= oongson-eiointc.c index b1f2080be2be..895d15b96669 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -360,6 +360,9 @@ static int __init acpi_cascade_irqdomain_init(void) if (r < 0) return r; =20 + if (cpu_has_avecint) + return 0; + r =3D acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1= ); if (r < 0) return r; @@ -396,8 +399,8 @@ static int __init eiointc_init(struct eiointc_priv *pri= v, int parent_irq, =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", + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_EIOINTC_STARTING, + "irqchip/loongarch/eiointc:starting", eiointc_router_init, NULL); } =20 diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-l= oongson-pch-msi.c index 2242f63c66fc..a56127314ecc 100644 --- a/drivers/irqchip/irq-loongson-pch-msi.c +++ b/drivers/irqchip/irq-loongson-pch-msi.c @@ -254,17 +254,17 @@ IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_= msi_of_init); #ifdef CONFIG_ACPI struct fwnode_handle *get_pch_msi_handle(int pci_segment) { - int i; + if (cpu_has_avecint) + return pch_msi_handle[0]; =20 - for (i =3D 0; i < MAX_IO_PICS; i++) { + for (int i =3D 0; i < MAX_IO_PICS; i++) { if (msi_group[i].pci_segment =3D=3D pci_segment) return pch_msi_handle[i]; } - return NULL; + return pch_msi_handle[0]; } =20 -int __init pch_msi_acpi_init(struct irq_domain *parent, - struct acpi_madt_msi_pic *acpi_pchmsi) +int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_m= si_pic *acpi_pchmsi) { int ret; struct fwnode_handle *domain_handle; @@ -277,4 +277,18 @@ int __init pch_msi_acpi_init(struct irq_domain *parent, =20 return ret; } + +int __init pch_msi_acpi_init_v2(struct irq_domain *parent, struct acpi_mad= t_msi_pic *acpi_pchmsi) +{ + if (pch_msi_handle[0]) + return 0; + + pch_msi_handle[0] =3D parent->fwnode; + irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); + + parent->flags |=3D IRQ_DOMAIN_FLAG_MSI_PARENT; + parent->msi_parent_ops =3D &pch_msi_parent_ops; + + return 0; +} #endif diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 51ba681b915a..55a726d317d4 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -145,7 +145,8 @@ enum cpuhp_state { CPUHP_AP_IRQ_ARMADA_XP_STARTING, CPUHP_AP_IRQ_BCM2836_STARTING, CPUHP_AP_IRQ_MIPS_GIC_STARTING, - CPUHP_AP_IRQ_LOONGARCH_STARTING, + CPUHP_AP_IRQ_EIOINTC_STARTING, + CPUHP_AP_IRQ_AVECINTC_STARTING, CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, CPUHP_AP_ARM_MVEBU_COHERENCY, --=20 2.20.1