Messages in this thread Patch in this message | | | From | Jianmin Lv <> | Subject | [PATCH RFC 02/10] irqchip: Add LoongArch CPU interrupt controller support | Date | Sun, 15 May 2022 11:37:05 +0800 |
| |
We are preparing to add new Loongson (based on LoongArch, not compatible with old MIPS-based Loongson) support. This patch add the LoongArch CPU interrupt controller support.
LoongArch CPUINTC stands for CSR.ECFG/CSR.ESTAT and related interrupt controller that described in Section 7.4 of "LoongArch Reference Manual, Vol 1". For more information please refer Documentation/loongarch/irq- chip-model.rst.
LoongArch CPUINTC has 13 interrupt sources: SWI0~1, HWI0~7, IPI, TI (Timer) and PCOV (PMC). IRQ mappings of HWI0~7 are configurable (can be created from DT/ACPI), but IPI, TI (Timer) and PCOV (PMC) are hardcoded bits, so we define get_xxx_irq() for them.
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> --- drivers/irqchip/Kconfig | 10 +++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-loongarch-cpu.c | 134 +++++++++++++++++++++++++++++ drivers/irqchip/irq-loongarch-pic-common.c | 66 ++++++++++++++ drivers/irqchip/irq-loongarch-pic-common.h | 22 +++++ 5 files changed, 233 insertions(+) create mode 100644 drivers/irqchip/irq-loongarch-cpu.c create mode 100644 drivers/irqchip/irq-loongarch-pic-common.c create mode 100644 drivers/irqchip/irq-loongarch-pic-common.h
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 39d6be2..a596ee7 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -545,6 +545,16 @@ config EXYNOS_IRQ_COMBINER Say yes here to add support for the IRQ combiner devices embedded in Samsung Exynos chips. +config IRQ_LOONGARCH_CPU + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + select GENERIC_IRQ_EFFECTIVE_AFF_MASK + help + Support for the LoongArch CPU Interrupt Controller. For details of + irq chip hierarchy on LoongArch platforms please read the document + Documentation/loongarch/irq-chip-model.rst. + config LOONGSON_LIOINTC bool "Loongson Local I/O Interrupt Controller" depends on MACH_LOONGSON64 diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 160a1d8..736f030 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o +obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-pic-common.o obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o obj-$(CONFIG_LOONGSON_HTVEC) += irq-loongson-htvec.o diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c new file mode 100644 index 0000000..b1f12f5 --- /dev/null +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> + +#include <asm/loongarch.h> +#include <asm/setup.h> +#include "irq-loongarch-pic-common.h" + +static struct irq_domain *irq_domain; + +static void mask_loongarch_irq(struct irq_data *d) +{ + clear_csr_ecfg(ECFGF(d->hwirq)); +} + +static void unmask_loongarch_irq(struct irq_data *d) +{ + set_csr_ecfg(ECFGF(d->hwirq)); +} + +static struct irq_chip cpu_irq_controller = { + .name = "LoongArch", + .irq_mask = mask_loongarch_irq, + .irq_unmask = unmask_loongarch_irq, +}; + +static void handle_cpu_irq(struct pt_regs *regs) +{ + int hwirq; + unsigned int estat = read_csr_estat() & CSR_ESTAT_IS; + + while ((hwirq = ffs(estat))) { + estat &= ~BIT(hwirq - 1); + generic_handle_domain_irq(irq_domain, hwirq - 1); + } +} + +int get_ipi_irq(void) +{ + return irq_create_mapping(irq_domain, EXCCODE_IPI - EXCCODE_INT_START); +} + +int get_pmc_irq(void) +{ + return irq_create_mapping(irq_domain, EXCCODE_PMC - EXCCODE_INT_START); +} + +int get_timer_irq(void) +{ + return irq_create_mapping(irq_domain, EXCCODE_TIMER - EXCCODE_INT_START); +} + +static int loongarch_cpu_intc_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_noprobe(irq); + irq_set_chip_and_handler(irq, &cpu_irq_controller, handle_percpu_irq); + + return 0; +} + +static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { + .map = loongarch_cpu_intc_map, + .xlate = irq_domain_xlate_onecell, +}; + +struct irq_domain * __init loongarch_cpu_irq_init(void) +{ + struct fwnode_handle *domain_handle; + + /* Mask interrupts. */ + clear_csr_ecfg(ECFG0_IM); + clear_csr_estat(ESTATF_IP); + + domain_handle = irq_domain_alloc_fwnode(NULL); + irq_domain = irq_domain_create_linear(domain_handle, EXCCODE_INT_NUM, + &loongarch_cpu_intc_irq_domain_ops, NULL); + + if (!irq_domain) + panic("Failed to add irqdomain for LoongArch CPU"); + + set_handle_irq(&handle_cpu_irq); + + return irq_domain; +} +#ifdef CONFIG_ACPI +static int __init +liointc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header; + + return liointc_acpi_init(irq_domain, liointc_entry); +} + +static int __init +eiointc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header; + + return eiointc_acpi_init(irq_domain, eiointc_entry); +} +static int __init acpi_cascade_irqdomain_init(void) +{ + acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, + liointc_parse_madt, 0); + acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, + eiointc_parse_madt, 0); + return 0; +} +static int __init coreintc_acpi_init_v1(union acpi_subtable_headers *header, + const unsigned long end) +{ + if (irq_domain) + return 0; + + init_vector_parent_group(); + loongarch_cpu_irq_init(); + acpi_cascade_irqdomain_init(); + return 0; +} +IRQCHIP_ACPI_DECLARE(coreintc_v1, ACPI_MADT_TYPE_CORE_PIC, + NULL, ACPI_MADT_CORE_PIC_VERSION_V1, + coreintc_acpi_init_v1); +#endif diff --git a/drivers/irqchip/irq-loongarch-pic-common.c b/drivers/irqchip/irq-loongarch-pic-common.c new file mode 100644 index 0000000..1be544a --- /dev/null +++ b/drivers/irqchip/irq-loongarch-pic-common.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Loongson Limited, All Rights Reserved. + */ + +#include <linux/irq.h> +#include <linux/acpi.h> +#include "irq-loongarch-pic-common.h" + +static struct acpi_vector_group vector_group[MAX_IO_PICS]; + +static int pci_mcfg_parse(struct acpi_table_header *header) +{ + struct acpi_table_mcfg *mcfg; + struct acpi_mcfg_allocation *mptr; + int i, n; + + if (header->length < sizeof(struct acpi_table_mcfg)) + return -EINVAL; + + n = (header->length - sizeof(struct acpi_table_mcfg)) / + sizeof(struct acpi_mcfg_allocation); + mcfg = (struct acpi_table_mcfg *)header; + mptr = (struct acpi_mcfg_allocation *) &mcfg[1]; + + for (i = 0; i < n; i++, mptr++) + vector_group[mptr->pci_segment].node = (mptr->address >> 44) & 0xf; + + return 0; +} + +void __init init_vector_parent_group(void) +{ + acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse); +} + +void acpi_set_vector_parent(int node, struct irq_domain *parent) +{ + int i; + + if (cpu_has_flatmode) + node = cpu_to_node(node * CORES_PER_EIO_NODE); + + for (i = 0; i < MAX_IO_PICS; i++) { + if (node == vector_group[i].node) { + vector_group[i].parent = parent; + return; + } + } +} + +struct irq_domain *acpi_get_msi_parent(int index) +{ + return vector_group[index].parent; +} + +struct irq_domain *acpi_get_pch_parent(int node) +{ + int i; + + for (i = 0; i < MAX_IO_PICS; i++) { + if (node == vector_group[i].node) + return vector_group[i].parent; + } + return NULL; +} diff --git a/drivers/irqchip/irq-loongarch-pic-common.h b/drivers/irqchip/irq-loongarch-pic-common.h new file mode 100644 index 0000000..1844776 --- /dev/null +++ b/drivers/irqchip/irq-loongarch-pic-common.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Loongson Limited, All Rights Reserved. + */ + +#ifndef _IRQ_LOONGARCH_PIC_COMMON_H +#define _IRQ_LOONGARCH_PIC_COMMON_H + +#include <linux/of.h> +#include <linux/irqdomain.h> + +struct acpi_vector_group { + int node; + struct irq_domain *parent; +}; + +void init_vector_parent_group(void); +void acpi_set_vector_parent(int node, struct irq_domain *parent); +struct irq_domain *acpi_get_msi_parent(int index); +struct irq_domain *acpi_get_pch_parent(int node); + +#endif /* _IRQ_LOONGARCH_PIC_COMMON_H */ -- 1.8.3.1
| |