diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml index 8d330906bbbd19..c1ab865fcd64f1 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml @@ -4,23 +4,32 @@ $id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-sswi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: T-HEAD C900 ACLINT Supervisor-level Software Interrupt Device +title: ACLINT Supervisor-level Software Interrupt Device maintainers: - Inochi Amaoto description: - The SSWI device is a part of the THEAD ACLINT device. It provides - supervisor-level IPI functionality for a set of HARTs on a THEAD - platform. It provides a register to set an IPI (SETSSIP) for each - HART connected to the SSWI device. + The SSWI device is a part of the ACLINT device. It provides + supervisor-level IPI functionality for a set of HARTs on a supported + platforms. It provides a register to set an IPI (SETSSIP) for each + HART connected to the SSWI device. See draft specification + https://github.com/riscvarchive/riscv-aclint + + Following variants of the SSWI ACLINT supported, using dedicated + compatible string + - THEAD C900 + - MIPS P8700 properties: compatible: - items: - - enum: - - sophgo,sg2044-aclint-sswi - - const: thead,c900-aclint-sswi + oneOf: + - items: + - enum: + - sophgo,sg2044-aclint-sswi + - const: thead,c900-aclint-sswi + - items: + - const: mips,p8700-aclint-sswi reg: maxItems: 1 @@ -34,6 +43,14 @@ properties: minItems: 1 maxItems: 4095 + riscv,hart-indexes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4095 + description: + A list of hart indexes that APLIC should use to address each hart + that is mentioned in the "interrupts-extended" + additionalProperties: false required: @@ -43,8 +60,22 @@ required: - interrupt-controller - interrupts-extended +allOf: + - if: + properties: + compatible: + contains: + const: mips,p8700-aclint-sswi + then: + required: + - riscv,hart-indexes + else: + properties: + riscv,hart-indexes: false + examples: - | + //Example 1 interrupt-controller@94000000 { compatible = "sophgo,sg2044-aclint-sswi", "thead,c900-aclint-sswi"; reg = <0x94000000 0x00004000>; @@ -55,4 +86,19 @@ examples: <&cpu3intc 1>, <&cpu4intc 1>; }; + + - | + //Example 2 + interrupt-controller@94000000 { + compatible = "mips,p8700-aclint-sswi"; + reg = <0x94000000 0x00004000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupts-extended = <&cpu1intc 1>, + <&cpu2intc 1>, + <&cpu3intc 1>, + <&cpu4intc 1>; + riscv,hart-indexes = <0x0 0x1 0x10 0x11>; + }; + ... diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h index 7b038f3b7cb0b7..59c975f750c9d8 100644 --- a/arch/riscv/include/asm/irq.h +++ b/arch/riscv/include/asm/irq.h @@ -22,6 +22,8 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu); void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void)); struct fwnode_handle *riscv_get_intc_hwnode(void); +int riscv_get_hart_index(struct fwnode_handle *fwnode, u32 logical_index, + u32 *hart_index); #ifdef CONFIG_ACPI diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c index 9ceda02507cae9..b6af20bc300f57 100644 --- a/arch/riscv/kernel/irq.c +++ b/arch/riscv/kernel/irq.c @@ -32,6 +32,40 @@ struct fwnode_handle *riscv_get_intc_hwnode(void) } EXPORT_SYMBOL_GPL(riscv_get_intc_hwnode); +/** + * riscv_get_hart_index() - get hart index for interrupt delivery + * @fwnode: interrupt controller node + * @logical_index: index within the "interrupts-extended" property + * @hart_index: filled with the hart index to use + * + * RISC-V uses term "hart index" for its interrupt controllers, for the + * purpose of the interrupt routing to destination harts. + * It may be arbitrary numbers assigned to each destination hart in context + * of the particular interrupt domain. + * + * These numbers encoded in the optional property "riscv,hart-indexes" + * that should contain hart index for each interrupt destination in the same + * order as in the "interrupts-extended" property. If this property + * not exist, it assumed equal to the logical index, i.e. index within the + * "interrupts-extended" property. + * + * Return: error code + */ +int riscv_get_hart_index(struct fwnode_handle *fwnode, u32 logical_index, + u32 *hart_index) +{ + static const char *prop_hart_index = "riscv,hart-indexes"; + struct device_node *np = to_of_node(fwnode); + + if (!np || !of_property_present(np, prop_hart_index)) { + *hart_index = logical_index; + return 0; + } + + return of_property_read_u32_index(np, prop_hart_index, + logical_index, hart_index); +} + #ifdef CONFIG_IRQ_STACKS #include diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 0d196e44714266..39f6f421fc75f8 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -634,18 +634,25 @@ config STARFIVE_JH8100_INTC If you don't know what to do here, say Y. -config THEAD_C900_ACLINT_SSWI - bool "THEAD C9XX ACLINT S-mode IPI Interrupt Controller" +config ACLINT_SSWI + bool "RISC-V ACLINT S-mode IPI Interrupt Controller" depends on RISCV depends on SMP select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_IPI_MUX help - This enables support for T-HEAD specific ACLINT SSWI device - support. + This enables support for variants of the RISC-V ACLINT-SSWI device. + Supported variants are: + - T-HEAD, with compatible "thead,c900-aclint-sswi" + - MIPS P8700, with compatible "mips,p8700-aclint-sswi" If you don't know what to do here, say Y. +# Backwards compatibility so oldconfig does not drop it. +config THEAD_C900_ACLINT_SSWI + bool + select ACLINT_SSWI + config EXYNOS_IRQ_COMBINER bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 23ca4959e6ced0..0458d6c5d1619b 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -105,7 +105,7 @@ obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o -obj-$(CONFIG_THEAD_C900_ACLINT_SSWI) += irq-thead-c900-aclint-sswi.o +obj-$(CONFIG_ACLINT_SSWI) += irq-aclint-sswi.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o diff --git a/drivers/irqchip/irq-thead-c900-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c similarity index 63% rename from drivers/irqchip/irq-thead-c900-aclint-sswi.c rename to drivers/irqchip/irq-aclint-sswi.c index 8ff6e7a1363bd2..51ecb509a98413 100644 --- a/drivers/irqchip/irq-thead-c900-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -3,79 +3,66 @@ * Copyright (C) 2024 Inochi Amaoto */ -#define pr_fmt(fmt) "thead-c900-aclint-sswi: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include -#include -#include #include #include -#include -#include #include -#include -#include #include #include #include #include #include -#define THEAD_ACLINT_xSWI_REGISTER_SIZE 4 - -#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 -#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) - static int sswi_ipi_virq __ro_after_init; static DEFINE_PER_CPU(void __iomem *, sswi_cpu_regs); -static void thead_aclint_sswi_ipi_send(unsigned int cpu) +static void aclint_sswi_ipi_send(unsigned int cpu) { writel(0x1, per_cpu(sswi_cpu_regs, cpu)); } -static void thead_aclint_sswi_ipi_clear(void) +static void aclint_sswi_ipi_clear(void) { writel_relaxed(0x0, this_cpu_read(sswi_cpu_regs)); } -static void thead_aclint_sswi_ipi_handle(struct irq_desc *desc) +static void aclint_sswi_ipi_handle(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); csr_clear(CSR_IP, IE_SIE); - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); ipi_mux_process(); chained_irq_exit(chip, desc); } -static int thead_aclint_sswi_starting_cpu(unsigned int cpu) +static int aclint_sswi_starting_cpu(unsigned int cpu) { enable_percpu_irq(sswi_ipi_virq, irq_get_trigger_type(sswi_ipi_virq)); return 0; } -static int thead_aclint_sswi_dying_cpu(unsigned int cpu) +static int aclint_sswi_dying_cpu(unsigned int cpu) { - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); disable_percpu_irq(sswi_ipi_virq); return 0; } -static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, - void __iomem *reg) +static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, + void __iomem *reg) { - struct of_phandle_args parent; - unsigned long hartid; - u32 contexts, i; - int rc, cpu; + u32 contexts; contexts = of_irq_count(to_of_node(fwnode)); if (!(contexts)) { @@ -83,7 +70,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, return -EINVAL; } - for (i = 0; i < contexts; i++) { + for (u32 i = 0; i < contexts; i++) { + struct of_phandle_args parent; + unsigned long hartid; + int rc, cpu; + u32 hart_index; + rc = of_irq_parse_one(to_of_node(fwnode), i, &parent); if (rc) return rc; @@ -97,7 +89,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, cpu = riscv_hartid_to_cpuid(hartid); - per_cpu(sswi_cpu_regs, cpu) = reg + i * THEAD_ACLINT_xSWI_REGISTER_SIZE; + rc = riscv_get_hart_index(fwnode, i, &hart_index); + if (rc) { + pr_warn("%pfwP: hart index [%d] not found\n", fwnode, i); + return -EINVAL; + } + per_cpu(sswi_cpu_regs, cpu) = reg + hart_index * 4; } pr_info("%pfwP: register %u CPU%s\n", fwnode, contexts, str_plural(contexts)); @@ -105,17 +102,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, return 0; } -static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +static int __init aclint_sswi_probe(struct fwnode_handle *fwnode) { struct irq_domain *domain; void __iomem *reg; int virq, rc; - /* If it is T-HEAD CPU, check whether SSWI is enabled */ - if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && - !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) - return -ENOTSUPP; - if (!is_of_node(fwnode)) return -EINVAL; @@ -124,7 +116,7 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) return -ENOMEM; /* Parse SSWI setting */ - rc = thead_aclint_sswi_parse_irq(fwnode, reg); + rc = aclint_sswi_parse_irq(fwnode, reg); if (rc < 0) return rc; @@ -146,22 +138,64 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) } /* Register SSWI irq and handler */ - virq = ipi_mux_create(BITS_PER_BYTE, thead_aclint_sswi_ipi_send); + virq = ipi_mux_create(BITS_PER_BYTE, aclint_sswi_ipi_send); if (virq <= 0) { pr_err("unable to create muxed IPIs\n"); irq_dispose_mapping(sswi_ipi_virq); return virq < 0 ? virq : -ENOMEM; } - irq_set_chained_handler(sswi_ipi_virq, thead_aclint_sswi_ipi_handle); + irq_set_chained_handler(sswi_ipi_virq, aclint_sswi_ipi_handle); - cpuhp_setup_state(CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, - "irqchip/thead-aclint-sswi:starting", - thead_aclint_sswi_starting_cpu, - thead_aclint_sswi_dying_cpu); + cpuhp_setup_state(CPUHP_AP_IRQ_ACLINT_SSWI_STARTING, + "irqchip/aclint-sswi:starting", + aclint_sswi_starting_cpu, + aclint_sswi_dying_cpu); riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); + return 0; +} + +/* generic/MIPS variant */ +static int __init generic_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + + /* Announce that SSWI is providing IPIs */ + pr_info("providing IPIs using ACLINT SSWI\n"); + + return 0; +} + +static int __init generic_aclint_sswi_early_probe(struct device_node *node, + struct device_node *parent) +{ + return generic_aclint_sswi_probe(&node->fwnode); +} +IRQCHIP_DECLARE(generic_aclint_sswi, "mips,p8700-aclint-sswi", generic_aclint_sswi_early_probe); + +/* THEAD variant */ +#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 +#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) + +static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + /* If it is T-HEAD CPU, check whether SSWI is enabled */ + if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && + !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) + return -ENOTSUPP; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + /* Announce that SSWI is providing IPIs */ pr_info("providing IPIs using THEAD ACLINT SSWI\n"); diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c index 205ad61d15e49f..c2a75bf3d20c64 100644 --- a/drivers/irqchip/irq-riscv-aplic-direct.c +++ b/drivers/irqchip/irq-riscv-aplic-direct.c @@ -219,20 +219,6 @@ static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index, return 0; } -static int aplic_direct_get_hart_index(struct device *dev, u32 logical_index, - u32 *hart_index) -{ - const char *prop_hart_index = "riscv,hart-indexes"; - struct device_node *np = to_of_node(dev->fwnode); - - if (!np || !of_property_present(np, prop_hart_index)) { - *hart_index = logical_index; - return 0; - } - - return of_property_read_u32_index(np, prop_hart_index, logical_index, hart_index); -} - int aplic_direct_setup(struct device *dev, void __iomem *regs) { int i, j, rc, cpu, current_cpu, setup_count = 0; @@ -279,7 +265,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs) cpumask_set_cpu(cpu, &direct->lmask); idc = per_cpu_ptr(&aplic_idcs, cpu); - rc = aplic_direct_get_hart_index(dev, i, &idc->hart_index); + rc = riscv_get_hart_index(dev->fwnode, i, &idc->hart_index); if (rc) { dev_warn(dev, "hart index not found for IDC%d\n", i); continue; diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index df366ee15456bb..d381420bbd5f8f 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -145,7 +145,7 @@ enum cpuhp_state { CPUHP_AP_IRQ_EIOINTC_STARTING, CPUHP_AP_IRQ_AVECINTC_STARTING, CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, + CPUHP_AP_IRQ_ACLINT_SSWI_STARTING, CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING, CPUHP_AP_ARM_MVEBU_COHERENCY,