Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'irq-core-2024-09-16' into loongarch-next

LoongArch architecture changes for 6.12 depend on the irq core
changes about AVEC irqchip to avoid confliction, so merge them
to create a base.

+1268 -683
+13 -1
Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml
··· 31 31 This device also represents the FIQ interrupt sources on platforms using AIC, 32 32 which do not go through a discrete interrupt controller. 33 33 34 + IPIs may be performed via MMIO registers on all variants of AIC. Starting 35 + from A11, system registers may also be used for "fast" IPIs. Starting from 36 + M1, even faster IPIs within the same cluster may be achieved by writing to 37 + a "local" fast IPI register as opposed to using the "global" fast IPI 38 + register. 39 + 34 40 allOf: 35 41 - $ref: /schemas/interrupt-controller.yaml# 36 42 37 43 properties: 38 44 compatible: 39 45 items: 40 - - const: apple,t8103-aic 46 + - enum: 47 + - apple,s5l8960x-aic 48 + - apple,t7000-aic 49 + - apple,s8000-aic 50 + - apple,t8010-aic 51 + - apple,t8015-aic 52 + - apple,t8103-aic 41 53 - const: apple,aic 42 54 43 55 interrupt-controller: true
+1
arch/loongarch/Kconfig
··· 85 85 select GENERIC_ENTRY 86 86 select GENERIC_GETTIMEOFDAY 87 87 select GENERIC_IOREMAP if !ARCH_IOREMAP 88 + select GENERIC_IRQ_MATRIX_ALLOCATOR 88 89 select GENERIC_IRQ_MULTI_HANDLER 89 90 select GENERIC_IRQ_PROBE 90 91 select GENERIC_IRQ_SHOW
+1
arch/loongarch/include/asm/cpu-features.h
··· 65 65 #define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID) 66 66 #define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR) 67 67 #define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW) 68 + #define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT) 68 69 69 70 #endif /* __ASM_CPU_FEATURES_H */
+2
arch/loongarch/include/asm/cpu.h
··· 99 99 #define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */ 100 100 #define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */ 101 101 #define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */ 102 + #define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */ 102 103 103 104 #define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) 104 105 #define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) ··· 128 127 #define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID) 129 128 #define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR) 130 129 #define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW) 130 + #define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT) 131 131 132 132 #endif /* _ASM_CPU_H */
+2 -1
arch/loongarch/include/asm/hardirq.h
··· 12 12 extern void ack_bad_irq(unsigned int irq); 13 13 #define ack_bad_irq ack_bad_irq 14 14 15 - #define NR_IPI 3 15 + #define NR_IPI 4 16 16 17 17 enum ipi_msg_type { 18 18 IPI_RESCHEDULE, 19 19 IPI_CALL_FUNCTION, 20 20 IPI_IRQ_WORK, 21 + IPI_CLEAR_VECTOR, 21 22 }; 22 23 23 24 typedef struct {
+14 -15
arch/loongarch/include/asm/irq.h
··· 39 39 40 40 #define NR_IRQS_LEGACY 16 41 41 42 + /* 43 + * 256 Vectors Mapping for AVECINTC: 44 + * 45 + * 0 - 15: Mapping classic IPs, e.g. IP0-12. 46 + * 16 - 255: Mapping vectors for external IRQ. 47 + * 48 + */ 49 + #define NR_VECTORS 256 50 + #define NR_LEGACY_VECTORS 16 51 + #define IRQ_MATRIX_BITS NR_VECTORS 52 + 42 53 #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace 43 54 void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu); 44 55 45 56 #define MAX_IO_PICS 2 46 - #define NR_IRQS (64 + (256 * MAX_IO_PICS)) 57 + #define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS)) 47 58 48 59 struct acpi_vector_group { 49 60 int node; ··· 76 65 #define LOONGSON_LPC_LAST_IRQ (LOONGSON_LPC_IRQ_BASE + 15) 77 66 78 67 #define LOONGSON_CPU_IRQ_BASE 16 79 - #define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 14) 68 + #define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 15) 80 69 81 70 #define LOONGSON_PCH_IRQ_BASE 64 82 71 #define LOONGSON_PCH_ACPI_IRQ (LOONGSON_PCH_IRQ_BASE + 47) ··· 99 88 struct acpi_madt_msi_pic; 100 89 struct acpi_madt_lpc_pic; 101 90 102 - int liointc_acpi_init(struct irq_domain *parent, 103 - struct acpi_madt_lio_pic *acpi_liointc); 104 - int eiointc_acpi_init(struct irq_domain *parent, 105 - struct acpi_madt_eio_pic *acpi_eiointc); 91 + void complete_irq_moving(void); 106 92 107 - int htvec_acpi_init(struct irq_domain *parent, 108 - struct acpi_madt_ht_pic *acpi_htvec); 109 - int pch_lpc_acpi_init(struct irq_domain *parent, 110 - struct acpi_madt_lpc_pic *acpi_pchlpc); 111 - int pch_msi_acpi_init(struct irq_domain *parent, 112 - struct acpi_madt_msi_pic *acpi_pchmsi); 113 - int pch_pic_acpi_init(struct irq_domain *parent, 114 - struct acpi_madt_bio_pic *acpi_pchpic); 115 - int find_pch_pic(u32 gsi); 116 93 struct fwnode_handle *get_pch_msi_handle(int pci_segment); 117 94 118 95 extern struct acpi_madt_lio_pic *acpi_liointc;
+14 -4
arch/loongarch/include/asm/loongarch.h
··· 253 253 #define CSR_ESTAT_EXC_WIDTH 6 254 254 #define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT) 255 255 #define CSR_ESTAT_IS_SHIFT 0 256 - #define CSR_ESTAT_IS_WIDTH 14 257 - #define CSR_ESTAT_IS (_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT) 256 + #define CSR_ESTAT_IS_WIDTH 15 257 + #define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT) 258 258 259 259 #define LOONGARCH_CSR_ERA 0x6 /* ERA */ 260 260 ··· 649 649 650 650 #define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ 651 651 652 + #define LOONGARCH_CSR_ISR0 0xa0 653 + #define LOONGARCH_CSR_ISR1 0xa1 654 + #define LOONGARCH_CSR_ISR2 0xa2 655 + #define LOONGARCH_CSR_ISR3 0xa3 656 + 657 + #define LOONGARCH_CSR_IRR 0xa4 658 + 652 659 #define LOONGARCH_CSR_PRID 0xc0 653 660 654 661 /* Shadow MCSR : 0xc0 ~ 0xff */ ··· 1018 1011 /* 1019 1012 * CSR_ECFG IM 1020 1013 */ 1021 - #define ECFG0_IM 0x00001fff 1014 + #define ECFG0_IM 0x00005fff 1022 1015 #define ECFGB_SIP0 0 1023 1016 #define ECFGF_SIP0 (_ULCAST_(1) << ECFGB_SIP0) 1024 1017 #define ECFGB_SIP1 1 ··· 1061 1054 #define IOCSRF_EIODECODE BIT_ULL(9) 1062 1055 #define IOCSRF_FLATMODE BIT_ULL(10) 1063 1056 #define IOCSRF_VM BIT_ULL(11) 1057 + #define IOCSRF_AVEC BIT_ULL(15) 1064 1058 1065 1059 #define LOONGARCH_IOCSR_VENDOR 0x10 1066 1060 ··· 1073 1065 #define IOCSR_MISC_FUNC_SOFT_INT BIT_ULL(10) 1074 1066 #define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) 1075 1067 #define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) 1068 + #define IOCSR_MISC_FUNC_AVEC_EN BIT_ULL(51) 1076 1069 1077 1070 #define LOONGARCH_IOCSR_CPUTEMP 0x428 1078 1071 ··· 1396 1387 #define INT_TI 11 /* Timer */ 1397 1388 #define INT_IPI 12 1398 1389 #define INT_NMI 13 1390 + #define INT_AVEC 14 1399 1391 1400 1392 /* ExcCodes corresponding to interrupts */ 1401 - #define EXCCODE_INT_NUM (INT_NMI + 1) 1393 + #define EXCCODE_INT_NUM (INT_AVEC + 1) 1402 1394 #define EXCCODE_INT_START 64 1403 1395 #define EXCCODE_INT_END (EXCCODE_INT_START + EXCCODE_INT_NUM - 1) 1404 1396
+2
arch/loongarch/include/asm/smp.h
··· 70 70 #define ACTION_RESCHEDULE 1 71 71 #define ACTION_CALL_FUNCTION 2 72 72 #define ACTION_IRQ_WORK 3 73 + #define ACTION_CLEAR_VECTOR 4 73 74 #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU) 74 75 #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE) 75 76 #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION) 76 77 #define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK) 78 + #define SMP_CLEAR_VECTOR BIT(ACTION_CLEAR_VECTOR) 77 79 78 80 struct secondary_data { 79 81 unsigned long stack;
+2 -1
arch/loongarch/kernel/cpu-probe.c
··· 106 106 elf_hwcap |= HWCAP_LOONGARCH_CRC32; 107 107 } 108 108 109 - 110 109 config = read_cpucfg(LOONGARCH_CPUCFG2); 111 110 if (config & CPUCFG2_LAM) { 112 111 c->options |= LOONGARCH_CPU_LAM; ··· 173 174 c->options |= LOONGARCH_CPU_FLATMODE; 174 175 if (config & IOCSRF_EIODECODE) 175 176 c->options |= LOONGARCH_CPU_EIODECODE; 177 + if (config & IOCSRF_AVEC) 178 + c->options |= LOONGARCH_CPU_AVECINT; 176 179 if (config & IOCSRF_VM) 177 180 c->options |= LOONGARCH_CPU_HYPERVISOR; 178 181
+12
arch/loongarch/kernel/irq.c
··· 87 87 acpi_table_parse(ACPI_SIG_MCFG, early_pci_mcfg_parse); 88 88 } 89 89 90 + int __init arch_probe_nr_irqs(void) 91 + { 92 + int nr_io_pics = bitmap_weight(loongson_sysconf.cores_io_master, NR_CPUS); 93 + 94 + if (!cpu_has_avecint) 95 + nr_irqs = (64 + NR_VECTORS * nr_io_pics); 96 + else 97 + nr_irqs = (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics)); 98 + 99 + return NR_IRQS_LEGACY; 100 + } 101 + 90 102 void __init init_IRQ(void) 91 103 { 92 104 int i;
+5
arch/loongarch/kernel/paravirt.c
··· 134 134 info->ipi_irqs[IPI_IRQ_WORK]++; 135 135 } 136 136 137 + if (action & SMP_CLEAR_VECTOR) { 138 + complete_irq_moving(); 139 + info->ipi_irqs[IPI_CLEAR_VECTOR]++; 140 + } 141 + 137 142 return IRQ_HANDLED; 138 143 } 139 144
+6
arch/loongarch/kernel/smp.c
··· 72 72 [IPI_RESCHEDULE] = "Rescheduling interrupts", 73 73 [IPI_CALL_FUNCTION] = "Function call interrupts", 74 74 [IPI_IRQ_WORK] = "IRQ work interrupts", 75 + [IPI_CLEAR_VECTOR] = "Clear vector interrupts", 75 76 }; 76 77 77 78 void show_ipi_list(struct seq_file *p, int prec) ··· 247 246 if (action & SMP_IRQ_WORK) { 248 247 irq_work_run(); 249 248 per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++; 249 + } 250 + 251 + if (action & SMP_CLEAR_VECTOR) { 252 + complete_irq_moving(); 253 + per_cpu(irq_stat, cpu).ipi_irqs[IPI_CLEAR_VECTOR]++; 250 254 } 251 255 252 256 return IRQ_HANDLED;
+1 -1
block/blk-mq.c
··· 1128 1128 rq->q->mq_ops->complete(rq); 1129 1129 } 1130 1130 1131 - static __latent_entropy void blk_done_softirq(struct softirq_action *h) 1131 + static __latent_entropy void blk_done_softirq(void) 1132 1132 { 1133 1133 blk_complete_reqs(this_cpu_ptr(&blk_cpu_done)); 1134 1134 }
+1
drivers/irqchip/Kconfig
··· 685 685 depends on PCI 686 686 default MACH_LOONGSON64 687 687 select IRQ_DOMAIN_HIERARCHY 688 + select IRQ_MSI_LIB 688 689 select PCI_MSI 689 690 help 690 691 Support for the Loongson PCH MSI Controller.
+1 -1
drivers/irqchip/Makefile
··· 110 110 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o 111 111 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o 112 112 obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o 113 - obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o 113 + obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-avec.o 114 114 obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o 115 115 obj-$(CONFIG_LOONGSON_EIOINTC) += irq-loongson-eiointc.o 116 116 obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o
+39 -20
drivers/irqchip/irq-apple-aic.c
··· 234 234 AIC_NR_FIQ 235 235 }; 236 236 237 + /* True if UNCORE/UNCORE2 and Sn_... IPI registers are present and used (A11+) */ 237 238 static DEFINE_STATIC_KEY_TRUE(use_fast_ipi); 239 + /* True if SYS_IMP_APL_IPI_RR_LOCAL_EL1 exists for local fast IPIs (M1+) */ 240 + static DEFINE_STATIC_KEY_TRUE(use_local_fast_ipi); 238 241 239 242 struct aic_info { 240 243 int version; ··· 255 252 256 253 /* Features */ 257 254 bool fast_ipi; 255 + bool local_fast_ipi; 258 256 }; 259 257 260 258 static const struct aic_info aic1_info __initconst = { ··· 274 270 .fast_ipi = true, 275 271 }; 276 272 273 + static const struct aic_info aic1_local_fipi_info __initconst = { 274 + .version = 1, 275 + 276 + .event = AIC_EVENT, 277 + .target_cpu = AIC_TARGET_CPU, 278 + 279 + .fast_ipi = true, 280 + .local_fast_ipi = true, 281 + }; 282 + 277 283 static const struct aic_info aic2_info __initconst = { 278 284 .version = 2, 279 285 280 286 .irq_cfg = AIC2_IRQ_CFG, 281 287 282 288 .fast_ipi = true, 289 + .local_fast_ipi = true, 283 290 }; 284 291 285 292 static const struct of_device_id aic_info_match[] = { 286 293 { 287 294 .compatible = "apple,t8103-aic", 295 + .data = &aic1_local_fipi_info, 296 + }, 297 + { 298 + .compatible = "apple,t8015-aic", 288 299 .data = &aic1_fipi_info, 289 300 }, 290 301 { ··· 551 532 * we check for everything here, even things we don't support yet. 552 533 */ 553 534 554 - if (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) { 555 - if (static_branch_likely(&use_fast_ipi)) { 556 - aic_handle_ipi(regs); 557 - } else { 558 - pr_err_ratelimited("Fast IPI fired. Acking.\n"); 559 - write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); 560 - } 561 - } 535 + if (static_branch_likely(&use_fast_ipi) && 536 + (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING)) 537 + aic_handle_ipi(regs); 562 538 563 539 if (TIMER_FIRING(read_sysreg(cntp_ctl_el0))) 564 540 generic_handle_domain_irq(aic_irqc->hw_domain, ··· 588 574 AIC_FIQ_HWIRQ(irq)); 589 575 } 590 576 591 - if (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ && 592 - (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) { 577 + if (static_branch_likely(&use_fast_ipi) && 578 + (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ) && 579 + (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) { 593 580 /* Same story with uncore PMCs */ 594 581 pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n"); 595 582 sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, ··· 765 750 u64 cluster = MPIDR_CLUSTER(mpidr); 766 751 u64 idx = MPIDR_CPU(mpidr); 767 752 768 - if (MPIDR_CLUSTER(my_mpidr) == cluster) 769 - write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx), 770 - SYS_IMP_APL_IPI_RR_LOCAL_EL1); 771 - else 753 + if (static_branch_likely(&use_local_fast_ipi) && MPIDR_CLUSTER(my_mpidr) == cluster) { 754 + write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx), SYS_IMP_APL_IPI_RR_LOCAL_EL1); 755 + } else { 772 756 write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx) | FIELD_PREP(IPI_RR_CLUSTER, cluster), 773 757 SYS_IMP_APL_IPI_RR_GLOBAL_EL1); 758 + } 774 759 isb(); 775 760 } 776 761 ··· 826 811 /* Mask all hard-wired per-CPU IRQ/FIQ sources */ 827 812 828 813 /* Pending Fast IPI FIQs */ 829 - write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); 814 + if (static_branch_likely(&use_fast_ipi)) 815 + write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1); 830 816 831 817 /* Timer FIQs */ 832 818 sysreg_clear_set(cntp_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK); ··· 848 832 FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF)); 849 833 850 834 /* Uncore PMC FIQ */ 851 - sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, 852 - FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); 835 + if (static_branch_likely(&use_fast_ipi)) { 836 + sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE, 837 + FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF)); 838 + } 853 839 854 840 /* Commit all of the above */ 855 841 isb(); ··· 1005 987 off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_CLR */ 1006 988 off += sizeof(u32) * (irqc->max_irq >> 5); /* HW_STATE */ 1007 989 1008 - if (irqc->info.fast_ipi) 1009 - static_branch_enable(&use_fast_ipi); 1010 - else 990 + if (!irqc->info.fast_ipi) 1011 991 static_branch_disable(&use_fast_ipi); 992 + 993 + if (!irqc->info.local_fast_ipi) 994 + static_branch_disable(&use_local_fast_ipi); 1012 995 1013 996 irqc->info.die_stride = off - start_off; 1014 997
+441 -424
drivers/irqchip/irq-armada-370-xp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 2 3 * Marvell Armada 370 and Armada XP SoC IRQ handling 3 4 * ··· 8 7 * Gregory CLEMENT <gregory.clement@free-electrons.com> 9 8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 10 9 * Ben Dooks <ben.dooks@codethink.co.uk> 11 - * 12 - * This file is licensed under the terms of the GNU General Public 13 - * License version 2. This program is licensed "as is" without any 14 - * warranty of any kind, whether express or implied. 15 10 */ 16 11 12 + #include <linux/bitfield.h> 17 13 #include <linux/bits.h> 14 + #include <linux/err.h> 18 15 #include <linux/kernel.h> 19 16 #include <linux/module.h> 20 17 #include <linux/init.h> ··· 65 66 * device 66 67 * 67 68 * The "global interrupt mask/unmask" is modified using the 68 - * ARMADA_370_XP_INT_SET_ENABLE_OFFS and 69 - * ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS registers, which are relative 70 - * to "main_int_base". 69 + * MPIC_INT_SET_ENABLE and MPIC_INT_CLEAR_ENABLE 70 + * registers, which are relative to "mpic->base". 71 71 * 72 - * The "per-CPU mask/unmask" is modified using the 73 - * ARMADA_370_XP_INT_SET_MASK_OFFS and 74 - * ARMADA_370_XP_INT_CLEAR_MASK_OFFS registers, which are relative to 75 - * "per_cpu_int_base". This base address points to a special address, 72 + * The "per-CPU mask/unmask" is modified using the MPIC_INT_SET_MASK 73 + * and MPIC_INT_CLEAR_MASK registers, which are relative to 74 + * "mpic->per_cpu". This base address points to a special address, 76 75 * which automatically accesses the registers of the current CPU. 77 76 * 78 77 * The per-CPU mask/unmask can also be adjusted using the global 79 - * per-interrupt ARMADA_370_XP_INT_SOURCE_CTL register, which we use 80 - * to configure interrupt affinity. 78 + * per-interrupt MPIC_INT_SOURCE_CTL register, which we use to 79 + * configure interrupt affinity. 81 80 * 82 81 * Due to this model, all interrupts need to be mask/unmasked at two 83 82 * different levels: at the global level and at the per-CPU level. ··· 89 92 * the current CPU, running the ->map() code. This allows to have 90 93 * the interrupt unmasked at this level in non-SMP 91 94 * configurations. In SMP configurations, the ->set_affinity() 92 - * callback is called, which using the 93 - * ARMADA_370_XP_INT_SOURCE_CTL() readjusts the per-CPU mask/unmask 94 - * for the interrupt. 95 + * callback is called, which using the MPIC_INT_SOURCE_CTL() 96 + * readjusts the per-CPU mask/unmask for the interrupt. 95 97 * 96 98 * The ->mask() and ->unmask() operations only mask/unmask the 97 99 * interrupt at the "global" level. ··· 112 116 * at the per-CPU level. 113 117 */ 114 118 115 - /* Registers relative to main_int_base */ 116 - #define ARMADA_370_XP_INT_CONTROL (0x00) 117 - #define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x04) 118 - #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) 119 - #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) 120 - #define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) 121 - #define ARMADA_370_XP_INT_SOURCE_CPU_MASK 0xF 122 - #define ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid) ((BIT(0) | BIT(8)) << cpuid) 119 + /* Registers relative to mpic->base */ 120 + #define MPIC_INT_CONTROL 0x00 121 + #define MPIC_INT_CONTROL_NUMINT_MASK GENMASK(12, 2) 122 + #define MPIC_SW_TRIG_INT 0x04 123 + #define MPIC_INT_SET_ENABLE 0x30 124 + #define MPIC_INT_CLEAR_ENABLE 0x34 125 + #define MPIC_INT_SOURCE_CTL(hwirq) (0x100 + (hwirq) * 4) 126 + #define MPIC_INT_SOURCE_CPU_MASK GENMASK(3, 0) 127 + #define MPIC_INT_IRQ_FIQ_MASK(cpuid) ((BIT(0) | BIT(8)) << (cpuid)) 123 128 124 - /* Registers relative to per_cpu_int_base */ 125 - #define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x08) 126 - #define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0x0c) 127 - #define ARMADA_375_PPI_CAUSE (0x10) 128 - #define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 129 - #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) 130 - #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) 131 - #define ARMADA_370_XP_INT_FABRIC_MASK_OFFS (0x54) 132 - #define ARMADA_370_XP_INT_CAUSE_PERF(cpu) (1 << cpu) 129 + /* Registers relative to mpic->per_cpu */ 130 + #define MPIC_IN_DRBEL_CAUSE 0x08 131 + #define MPIC_IN_DRBEL_MASK 0x0c 132 + #define MPIC_PPI_CAUSE 0x10 133 + #define MPIC_CPU_INTACK 0x44 134 + #define MPIC_CPU_INTACK_IID_MASK GENMASK(9, 0) 135 + #define MPIC_INT_SET_MASK 0x48 136 + #define MPIC_INT_CLEAR_MASK 0x4C 137 + #define MPIC_INT_FABRIC_MASK 0x54 138 + #define MPIC_INT_CAUSE_PERF(cpu) BIT(cpu) 133 139 134 - #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) 140 + #define MPIC_PER_CPU_IRQS_NR 29 135 141 136 142 /* IPI and MSI interrupt definitions for IPI platforms */ 137 - #define IPI_DOORBELL_START (0) 138 - #define IPI_DOORBELL_END (8) 139 - #define IPI_DOORBELL_MASK 0xFF 140 - #define PCI_MSI_DOORBELL_START (16) 141 - #define PCI_MSI_DOORBELL_NR (16) 142 - #define PCI_MSI_DOORBELL_END (32) 143 - #define PCI_MSI_DOORBELL_MASK 0xFFFF0000 143 + #define IPI_DOORBELL_NR 8 144 + #define IPI_DOORBELL_MASK GENMASK(7, 0) 145 + #define PCI_MSI_DOORBELL_START 16 146 + #define PCI_MSI_DOORBELL_NR 16 147 + #define PCI_MSI_DOORBELL_MASK GENMASK(31, 16) 144 148 145 149 /* MSI interrupt definitions for non-IPI platforms */ 146 150 #define PCI_MSI_FULL_DOORBELL_START 0 147 151 #define PCI_MSI_FULL_DOORBELL_NR 32 148 - #define PCI_MSI_FULL_DOORBELL_END 32 149 152 #define PCI_MSI_FULL_DOORBELL_MASK GENMASK(31, 0) 150 153 #define PCI_MSI_FULL_DOORBELL_SRC0_MASK GENMASK(15, 0) 151 154 #define PCI_MSI_FULL_DOORBELL_SRC1_MASK GENMASK(31, 16) 152 155 153 - static void __iomem *per_cpu_int_base; 154 - static void __iomem *main_int_base; 155 - static struct irq_domain *armada_370_xp_mpic_domain; 156 - static u32 doorbell_mask_reg; 157 - static int parent_irq; 158 - #ifdef CONFIG_PCI_MSI 159 - static struct irq_domain *armada_370_xp_msi_domain; 160 - static struct irq_domain *armada_370_xp_msi_inner_domain; 161 - static DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); 162 - static DEFINE_MUTEX(msi_used_lock); 163 - static phys_addr_t msi_doorbell_addr; 156 + /** 157 + * struct mpic - MPIC private data structure 158 + * @base: MPIC registers base address 159 + * @per_cpu: per-CPU registers base address 160 + * @parent_irq: parent IRQ if MPIC is not top-level interrupt controller 161 + * @domain: MPIC main interrupt domain 162 + * @ipi_domain: IPI domain 163 + * @msi_domain: MSI domain 164 + * @msi_inner_domain: MSI inner domain 165 + * @msi_used: bitmap of used MSI numbers 166 + * @msi_lock: mutex serializing access to @msi_used 167 + * @msi_doorbell_addr: physical address of MSI doorbell register 168 + * @msi_doorbell_mask: mask of available doorbell bits for MSIs (either PCI_MSI_DOORBELL_MASK or 169 + * PCI_MSI_FULL_DOORBELL_MASK) 170 + * @msi_doorbell_start: first set bit in @msi_doorbell_mask 171 + * @msi_doorbell_size: number of set bits in @msi_doorbell_mask 172 + * @doorbell_mask: doorbell mask of MSIs and IPIs, stored on suspend, restored on resume 173 + */ 174 + struct mpic { 175 + void __iomem *base; 176 + void __iomem *per_cpu; 177 + int parent_irq; 178 + struct irq_domain *domain; 179 + #ifdef CONFIG_SMP 180 + struct irq_domain *ipi_domain; 164 181 #endif 182 + #ifdef CONFIG_PCI_MSI 183 + struct irq_domain *msi_domain; 184 + struct irq_domain *msi_inner_domain; 185 + DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); 186 + struct mutex msi_lock; 187 + phys_addr_t msi_doorbell_addr; 188 + u32 msi_doorbell_mask; 189 + unsigned int msi_doorbell_start, msi_doorbell_size; 190 + #endif 191 + u32 doorbell_mask; 192 + }; 165 193 166 - static inline bool is_ipi_available(void) 194 + static struct mpic *mpic_data __ro_after_init; 195 + 196 + static inline bool mpic_is_ipi_available(struct mpic *mpic) 167 197 { 168 198 /* 169 199 * We distinguish IPI availability in the IC by the IC not having a ··· 197 175 * interrupt controller (e.g. GIC) that takes care of inter-processor 198 176 * interrupts. 199 177 */ 200 - return parent_irq <= 0; 178 + return mpic->parent_irq <= 0; 201 179 } 202 180 203 - static inline u32 msi_doorbell_mask(void) 181 + static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq) 204 182 { 205 - return is_ipi_available() ? PCI_MSI_DOORBELL_MASK : 206 - PCI_MSI_FULL_DOORBELL_MASK; 207 - } 208 - 209 - static inline unsigned int msi_doorbell_start(void) 210 - { 211 - return is_ipi_available() ? PCI_MSI_DOORBELL_START : 212 - PCI_MSI_FULL_DOORBELL_START; 213 - } 214 - 215 - static inline unsigned int msi_doorbell_size(void) 216 - { 217 - return is_ipi_available() ? PCI_MSI_DOORBELL_NR : 218 - PCI_MSI_FULL_DOORBELL_NR; 219 - } 220 - 221 - static inline unsigned int msi_doorbell_end(void) 222 - { 223 - return is_ipi_available() ? PCI_MSI_DOORBELL_END : 224 - PCI_MSI_FULL_DOORBELL_END; 225 - } 226 - 227 - static inline bool is_percpu_irq(irq_hw_number_t irq) 228 - { 229 - if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS) 230 - return true; 231 - 232 - return false; 183 + return hwirq < MPIC_PER_CPU_IRQS_NR; 233 184 } 234 185 235 186 /* ··· 210 215 * For shared global interrupts, mask/unmask global enable bit 211 216 * For CPU interrupts, mask/unmask the calling CPU's bit 212 217 */ 213 - static void armada_370_xp_irq_mask(struct irq_data *d) 218 + static void mpic_irq_mask(struct irq_data *d) 214 219 { 220 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 215 221 irq_hw_number_t hwirq = irqd_to_hwirq(d); 216 222 217 - if (!is_percpu_irq(hwirq)) 218 - writel(hwirq, main_int_base + 219 - ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); 223 + if (!mpic_is_percpu_irq(hwirq)) 224 + writel(hwirq, mpic->base + MPIC_INT_CLEAR_ENABLE); 220 225 else 221 - writel(hwirq, per_cpu_int_base + 222 - ARMADA_370_XP_INT_SET_MASK_OFFS); 226 + writel(hwirq, mpic->per_cpu + MPIC_INT_SET_MASK); 223 227 } 224 228 225 - static void armada_370_xp_irq_unmask(struct irq_data *d) 229 + static void mpic_irq_unmask(struct irq_data *d) 226 230 { 231 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 227 232 irq_hw_number_t hwirq = irqd_to_hwirq(d); 228 233 229 - if (!is_percpu_irq(hwirq)) 230 - writel(hwirq, main_int_base + 231 - ARMADA_370_XP_INT_SET_ENABLE_OFFS); 234 + if (!mpic_is_percpu_irq(hwirq)) 235 + writel(hwirq, mpic->base + MPIC_INT_SET_ENABLE); 232 236 else 233 - writel(hwirq, per_cpu_int_base + 234 - ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 237 + writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 235 238 } 236 239 237 240 #ifdef CONFIG_PCI_MSI 238 241 239 - static struct irq_chip armada_370_xp_msi_irq_chip = { 240 - .name = "MPIC MSI", 241 - .irq_mask = pci_msi_mask_irq, 242 - .irq_unmask = pci_msi_unmask_irq, 242 + static struct irq_chip mpic_msi_irq_chip = { 243 + .name = "MPIC MSI", 244 + .irq_mask = pci_msi_mask_irq, 245 + .irq_unmask = pci_msi_unmask_irq, 243 246 }; 244 247 245 - static struct msi_domain_info armada_370_xp_msi_domain_info = { 248 + static struct msi_domain_info mpic_msi_domain_info = { 246 249 .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 247 250 MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), 248 - .chip = &armada_370_xp_msi_irq_chip, 251 + .chip = &mpic_msi_irq_chip, 249 252 }; 250 253 251 - static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 254 + static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) 252 255 { 253 - unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(data)); 256 + unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); 257 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 254 258 255 - msg->address_lo = lower_32_bits(msi_doorbell_addr); 256 - msg->address_hi = upper_32_bits(msi_doorbell_addr); 257 - msg->data = BIT(cpu + 8) | (data->hwirq + msi_doorbell_start()); 259 + msg->address_lo = lower_32_bits(mpic->msi_doorbell_addr); 260 + msg->address_hi = upper_32_bits(mpic->msi_doorbell_addr); 261 + msg->data = BIT(cpu + 8) | (d->hwirq + mpic->msi_doorbell_start); 258 262 } 259 263 260 - static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data, 261 - const struct cpumask *mask, bool force) 264 + static int mpic_msi_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force) 262 265 { 263 266 unsigned int cpu; 264 267 ··· 268 275 if (cpu >= nr_cpu_ids) 269 276 return -EINVAL; 270 277 271 - irq_data_update_effective_affinity(irq_data, cpumask_of(cpu)); 278 + irq_data_update_effective_affinity(d, cpumask_of(cpu)); 272 279 273 280 return IRQ_SET_MASK_OK; 274 281 } 275 282 276 - static struct irq_chip armada_370_xp_msi_bottom_irq_chip = { 283 + static struct irq_chip mpic_msi_bottom_irq_chip = { 277 284 .name = "MPIC MSI", 278 - .irq_compose_msi_msg = armada_370_xp_compose_msi_msg, 279 - .irq_set_affinity = armada_370_xp_msi_set_affinity, 285 + .irq_compose_msi_msg = mpic_compose_msi_msg, 286 + .irq_set_affinity = mpic_msi_set_affinity, 280 287 }; 281 288 282 - static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq, 283 - unsigned int nr_irqs, void *args) 289 + static int mpic_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, 290 + void *args) 284 291 { 285 - int hwirq, i; 292 + struct mpic *mpic = domain->host_data; 293 + int hwirq; 286 294 287 - mutex_lock(&msi_used_lock); 288 - hwirq = bitmap_find_free_region(msi_used, msi_doorbell_size(), 295 + mutex_lock(&mpic->msi_lock); 296 + hwirq = bitmap_find_free_region(mpic->msi_used, mpic->msi_doorbell_size, 289 297 order_base_2(nr_irqs)); 290 - mutex_unlock(&msi_used_lock); 298 + mutex_unlock(&mpic->msi_lock); 291 299 292 300 if (hwirq < 0) 293 301 return -ENOSPC; 294 302 295 - for (i = 0; i < nr_irqs; i++) { 303 + for (unsigned int i = 0; i < nr_irqs; i++) { 296 304 irq_domain_set_info(domain, virq + i, hwirq + i, 297 - &armada_370_xp_msi_bottom_irq_chip, 305 + &mpic_msi_bottom_irq_chip, 298 306 domain->host_data, handle_simple_irq, 299 307 NULL, NULL); 300 308 } ··· 303 309 return 0; 304 310 } 305 311 306 - static void armada_370_xp_msi_free(struct irq_domain *domain, 307 - unsigned int virq, unsigned int nr_irqs) 312 + static void mpic_msi_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) 308 313 { 309 314 struct irq_data *d = irq_domain_get_irq_data(domain, virq); 315 + struct mpic *mpic = domain->host_data; 310 316 311 - mutex_lock(&msi_used_lock); 312 - bitmap_release_region(msi_used, d->hwirq, order_base_2(nr_irqs)); 313 - mutex_unlock(&msi_used_lock); 317 + mutex_lock(&mpic->msi_lock); 318 + bitmap_release_region(mpic->msi_used, d->hwirq, order_base_2(nr_irqs)); 319 + mutex_unlock(&mpic->msi_lock); 314 320 } 315 321 316 - static const struct irq_domain_ops armada_370_xp_msi_domain_ops = { 317 - .alloc = armada_370_xp_msi_alloc, 318 - .free = armada_370_xp_msi_free, 322 + static const struct irq_domain_ops mpic_msi_domain_ops = { 323 + .alloc = mpic_msi_alloc, 324 + .free = mpic_msi_free, 319 325 }; 320 326 321 - static void armada_370_xp_msi_reenable_percpu(void) 327 + static void mpic_msi_reenable_percpu(struct mpic *mpic) 322 328 { 323 329 u32 reg; 324 330 325 331 /* Enable MSI doorbell mask and combined cpu local interrupt */ 326 - reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 327 - reg |= msi_doorbell_mask(); 328 - writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 332 + reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK); 333 + reg |= mpic->msi_doorbell_mask; 334 + writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK); 329 335 330 336 /* Unmask local doorbell interrupt */ 331 - writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 337 + writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 332 338 } 333 339 334 - static int armada_370_xp_msi_init(struct device_node *node, 335 - phys_addr_t main_int_phys_base) 340 + static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node, 341 + phys_addr_t main_int_phys_base) 336 342 { 337 - msi_doorbell_addr = main_int_phys_base + 338 - ARMADA_370_XP_SW_TRIG_INT_OFFS; 343 + mpic->msi_doorbell_addr = main_int_phys_base + MPIC_SW_TRIG_INT; 339 344 340 - armada_370_xp_msi_inner_domain = 341 - irq_domain_add_linear(NULL, msi_doorbell_size(), 342 - &armada_370_xp_msi_domain_ops, NULL); 343 - if (!armada_370_xp_msi_inner_domain) 345 + mutex_init(&mpic->msi_lock); 346 + 347 + if (mpic_is_ipi_available(mpic)) { 348 + mpic->msi_doorbell_start = PCI_MSI_DOORBELL_START; 349 + mpic->msi_doorbell_size = PCI_MSI_DOORBELL_NR; 350 + mpic->msi_doorbell_mask = PCI_MSI_DOORBELL_MASK; 351 + } else { 352 + mpic->msi_doorbell_start = PCI_MSI_FULL_DOORBELL_START; 353 + mpic->msi_doorbell_size = PCI_MSI_FULL_DOORBELL_NR; 354 + mpic->msi_doorbell_mask = PCI_MSI_FULL_DOORBELL_MASK; 355 + } 356 + 357 + mpic->msi_inner_domain = irq_domain_add_linear(NULL, mpic->msi_doorbell_size, 358 + &mpic_msi_domain_ops, mpic); 359 + if (!mpic->msi_inner_domain) 344 360 return -ENOMEM; 345 361 346 - armada_370_xp_msi_domain = 347 - pci_msi_create_irq_domain(of_node_to_fwnode(node), 348 - &armada_370_xp_msi_domain_info, 349 - armada_370_xp_msi_inner_domain); 350 - if (!armada_370_xp_msi_domain) { 351 - irq_domain_remove(armada_370_xp_msi_inner_domain); 362 + mpic->msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), &mpic_msi_domain_info, 363 + mpic->msi_inner_domain); 364 + if (!mpic->msi_domain) { 365 + irq_domain_remove(mpic->msi_inner_domain); 352 366 return -ENOMEM; 353 367 } 354 368 355 - armada_370_xp_msi_reenable_percpu(); 369 + mpic_msi_reenable_percpu(mpic); 356 370 357 371 /* Unmask low 16 MSI irqs on non-IPI platforms */ 358 - if (!is_ipi_available()) 359 - writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 372 + if (!mpic_is_ipi_available(mpic)) 373 + writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 360 374 361 375 return 0; 362 376 } 363 377 #else 364 - static __maybe_unused void armada_370_xp_msi_reenable_percpu(void) {} 378 + static __maybe_unused void mpic_msi_reenable_percpu(struct mpic *mpic) {} 365 379 366 - static inline int armada_370_xp_msi_init(struct device_node *node, 367 - phys_addr_t main_int_phys_base) 380 + static inline int mpic_msi_init(struct mpic *mpic, struct device_node *node, 381 + phys_addr_t main_int_phys_base) 368 382 { 369 383 return 0; 370 384 } 371 385 #endif 372 386 373 - static void armada_xp_mpic_perf_init(void) 387 + static void mpic_perf_init(struct mpic *mpic) 374 388 { 375 - unsigned long cpuid; 389 + u32 cpuid; 376 390 377 391 /* 378 392 * This Performance Counter Overflow interrupt is specific for ··· 392 390 cpuid = cpu_logical_map(smp_processor_id()); 393 391 394 392 /* Enable Performance Counter Overflow interrupts */ 395 - writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), 396 - per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); 393 + writel(MPIC_INT_CAUSE_PERF(cpuid), mpic->per_cpu + MPIC_INT_FABRIC_MASK); 397 394 } 398 395 399 396 #ifdef CONFIG_SMP 400 - static struct irq_domain *ipi_domain; 401 - 402 - static void armada_370_xp_ipi_mask(struct irq_data *d) 397 + static void mpic_ipi_mask(struct irq_data *d) 403 398 { 399 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 404 400 u32 reg; 405 - reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 401 + 402 + reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK); 406 403 reg &= ~BIT(d->hwirq); 407 - writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 404 + writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK); 408 405 } 409 406 410 - static void armada_370_xp_ipi_unmask(struct irq_data *d) 407 + static void mpic_ipi_unmask(struct irq_data *d) 411 408 { 409 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 412 410 u32 reg; 413 - reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 411 + 412 + reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK); 414 413 reg |= BIT(d->hwirq); 415 - writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 414 + writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK); 416 415 } 417 416 418 - static void armada_370_xp_ipi_send_mask(struct irq_data *d, 419 - const struct cpumask *mask) 417 + static void mpic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) 420 418 { 421 - unsigned long map = 0; 422 - int cpu; 419 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 420 + unsigned int cpu; 421 + u32 map = 0; 423 422 424 423 /* Convert our logical CPU mask into a physical one. */ 425 424 for_each_cpu(cpu, mask) 426 - map |= 1 << cpu_logical_map(cpu); 425 + map |= BIT(cpu_logical_map(cpu)); 427 426 428 427 /* 429 428 * Ensure that stores to Normal memory are visible to the ··· 433 430 dsb(); 434 431 435 432 /* submit softirq */ 436 - writel((map << 8) | d->hwirq, main_int_base + 437 - ARMADA_370_XP_SW_TRIG_INT_OFFS); 433 + writel((map << 8) | d->hwirq, mpic->base + MPIC_SW_TRIG_INT); 438 434 } 439 435 440 - static void armada_370_xp_ipi_ack(struct irq_data *d) 436 + static void mpic_ipi_ack(struct irq_data *d) 441 437 { 442 - writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 438 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 439 + 440 + writel(~BIT(d->hwirq), mpic->per_cpu + MPIC_IN_DRBEL_CAUSE); 443 441 } 444 442 445 - static struct irq_chip ipi_irqchip = { 443 + static struct irq_chip mpic_ipi_irqchip = { 446 444 .name = "IPI", 447 - .irq_ack = armada_370_xp_ipi_ack, 448 - .irq_mask = armada_370_xp_ipi_mask, 449 - .irq_unmask = armada_370_xp_ipi_unmask, 450 - .ipi_send_mask = armada_370_xp_ipi_send_mask, 445 + .irq_ack = mpic_ipi_ack, 446 + .irq_mask = mpic_ipi_mask, 447 + .irq_unmask = mpic_ipi_unmask, 448 + .ipi_send_mask = mpic_ipi_send_mask, 451 449 }; 452 450 453 - static int armada_370_xp_ipi_alloc(struct irq_domain *d, 454 - unsigned int virq, 455 - unsigned int nr_irqs, void *args) 451 + static int mpic_ipi_alloc(struct irq_domain *d, unsigned int virq, 452 + unsigned int nr_irqs, void *args) 456 453 { 457 - int i; 458 - 459 - for (i = 0; i < nr_irqs; i++) { 454 + for (unsigned int i = 0; i < nr_irqs; i++) { 460 455 irq_set_percpu_devid(virq + i); 461 - irq_domain_set_info(d, virq + i, i, &ipi_irqchip, 462 - d->host_data, 463 - handle_percpu_devid_irq, 464 - NULL, NULL); 456 + irq_domain_set_info(d, virq + i, i, &mpic_ipi_irqchip, d->host_data, 457 + handle_percpu_devid_irq, NULL, NULL); 465 458 } 466 459 467 460 return 0; 468 461 } 469 462 470 - static void armada_370_xp_ipi_free(struct irq_domain *d, 471 - unsigned int virq, 472 - unsigned int nr_irqs) 463 + static void mpic_ipi_free(struct irq_domain *d, unsigned int virq, 464 + unsigned int nr_irqs) 473 465 { 474 466 /* Not freeing IPIs */ 475 467 } 476 468 477 - static const struct irq_domain_ops ipi_domain_ops = { 478 - .alloc = armada_370_xp_ipi_alloc, 479 - .free = armada_370_xp_ipi_free, 469 + static const struct irq_domain_ops mpic_ipi_domain_ops = { 470 + .alloc = mpic_ipi_alloc, 471 + .free = mpic_ipi_free, 480 472 }; 481 473 482 - static void ipi_resume(void) 474 + static void mpic_ipi_resume(struct mpic *mpic) 483 475 { 484 - int i; 476 + for (irq_hw_number_t i = 0; i < IPI_DOORBELL_NR; i++) { 477 + unsigned int virq = irq_find_mapping(mpic->ipi_domain, i); 478 + struct irq_data *d; 485 479 486 - for (i = 0; i < IPI_DOORBELL_END; i++) { 487 - int irq; 488 - 489 - irq = irq_find_mapping(ipi_domain, i); 490 - if (irq <= 0) 480 + if (!virq || !irq_percpu_is_enabled(virq)) 491 481 continue; 492 - if (irq_percpu_is_enabled(irq)) { 493 - struct irq_data *d; 494 - d = irq_domain_get_irq_data(ipi_domain, irq); 495 - armada_370_xp_ipi_unmask(d); 496 - } 482 + 483 + d = irq_domain_get_irq_data(mpic->ipi_domain, virq); 484 + mpic_ipi_unmask(d); 497 485 } 498 486 } 499 487 500 - static __init void armada_xp_ipi_init(struct device_node *node) 488 + static int __init mpic_ipi_init(struct mpic *mpic, struct device_node *node) 501 489 { 502 490 int base_ipi; 503 491 504 - ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), 505 - IPI_DOORBELL_END, 506 - &ipi_domain_ops, NULL); 507 - if (WARN_ON(!ipi_domain)) 508 - return; 492 + mpic->ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_NR, 493 + &mpic_ipi_domain_ops, mpic); 494 + if (WARN_ON(!mpic->ipi_domain)) 495 + return -ENOMEM; 509 496 510 - irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI); 511 - base_ipi = irq_domain_alloc_irqs(ipi_domain, IPI_DOORBELL_END, NUMA_NO_NODE, NULL); 497 + irq_domain_update_bus_token(mpic->ipi_domain, DOMAIN_BUS_IPI); 498 + base_ipi = irq_domain_alloc_irqs(mpic->ipi_domain, IPI_DOORBELL_NR, NUMA_NO_NODE, NULL); 512 499 if (WARN_ON(!base_ipi)) 513 - return; 500 + return -ENOMEM; 514 501 515 - set_smp_ipi_range(base_ipi, IPI_DOORBELL_END); 502 + set_smp_ipi_range(base_ipi, IPI_DOORBELL_NR); 503 + 504 + return 0; 516 505 } 517 506 518 - static int armada_xp_set_affinity(struct irq_data *d, 519 - const struct cpumask *mask_val, bool force) 507 + static int mpic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) 520 508 { 509 + struct mpic *mpic = irq_data_get_irq_chip_data(d); 521 510 irq_hw_number_t hwirq = irqd_to_hwirq(d); 522 - int cpu; 511 + unsigned int cpu; 523 512 524 513 /* Select a single core from the affinity mask which is online */ 525 514 cpu = cpumask_any_and(mask_val, cpu_online_mask); 526 515 527 - atomic_io_modify(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq), 528 - ARMADA_370_XP_INT_SOURCE_CPU_MASK, 529 - BIT(cpu_logical_map(cpu))); 516 + atomic_io_modify(mpic->base + MPIC_INT_SOURCE_CTL(hwirq), 517 + MPIC_INT_SOURCE_CPU_MASK, BIT(cpu_logical_map(cpu))); 530 518 531 519 irq_data_update_effective_affinity(d, cpumask_of(cpu)); 532 520 533 521 return IRQ_SET_MASK_OK; 534 522 } 535 523 536 - static void armada_xp_mpic_smp_cpu_init(void) 524 + static void mpic_smp_cpu_init(struct mpic *mpic) 537 525 { 538 - u32 control; 539 - int nr_irqs, i; 526 + for (irq_hw_number_t i = 0; i < mpic->domain->hwirq_max; i++) 527 + writel(i, mpic->per_cpu + MPIC_INT_SET_MASK); 540 528 541 - control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); 542 - nr_irqs = (control >> 2) & 0x3ff; 543 - 544 - for (i = 0; i < nr_irqs; i++) 545 - writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); 546 - 547 - if (!is_ipi_available()) 529 + if (!mpic_is_ipi_available(mpic)) 548 530 return; 549 531 550 532 /* Disable all IPIs */ 551 - writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 533 + writel(0, mpic->per_cpu + MPIC_IN_DRBEL_MASK); 552 534 553 535 /* Clear pending IPIs */ 554 - writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 536 + writel(0, mpic->per_cpu + MPIC_IN_DRBEL_CAUSE); 555 537 556 538 /* Unmask IPI interrupt */ 557 - writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 539 + writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 558 540 } 559 541 560 - static void armada_xp_mpic_reenable_percpu(void) 542 + static void mpic_reenable_percpu(struct mpic *mpic) 561 543 { 562 - unsigned int irq; 563 - 564 544 /* Re-enable per-CPU interrupts that were enabled before suspend */ 565 - for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) { 566 - struct irq_data *data; 567 - int virq; 545 + for (irq_hw_number_t i = 0; i < MPIC_PER_CPU_IRQS_NR; i++) { 546 + unsigned int virq = irq_linear_revmap(mpic->domain, i); 547 + struct irq_data *d; 568 548 569 - virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq); 570 - if (virq == 0) 549 + if (!virq || !irq_percpu_is_enabled(virq)) 571 550 continue; 572 551 573 - data = irq_get_irq_data(virq); 574 - 575 - if (!irq_percpu_is_enabled(virq)) 576 - continue; 577 - 578 - armada_370_xp_irq_unmask(data); 552 + d = irq_get_irq_data(virq); 553 + mpic_irq_unmask(d); 579 554 } 580 555 581 - if (is_ipi_available()) 582 - ipi_resume(); 556 + if (mpic_is_ipi_available(mpic)) 557 + mpic_ipi_resume(mpic); 583 558 584 - armada_370_xp_msi_reenable_percpu(); 559 + mpic_msi_reenable_percpu(mpic); 585 560 } 586 561 587 - static int armada_xp_mpic_starting_cpu(unsigned int cpu) 562 + static int mpic_starting_cpu(unsigned int cpu) 588 563 { 589 - armada_xp_mpic_perf_init(); 590 - armada_xp_mpic_smp_cpu_init(); 591 - armada_xp_mpic_reenable_percpu(); 564 + struct mpic *mpic = irq_get_default_host()->host_data; 565 + 566 + mpic_perf_init(mpic); 567 + mpic_smp_cpu_init(mpic); 568 + mpic_reenable_percpu(mpic); 569 + 592 570 return 0; 593 571 } 594 572 595 573 static int mpic_cascaded_starting_cpu(unsigned int cpu) 596 574 { 597 - armada_xp_mpic_perf_init(); 598 - armada_xp_mpic_reenable_percpu(); 599 - enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); 575 + struct mpic *mpic = mpic_data; 576 + 577 + mpic_perf_init(mpic); 578 + mpic_reenable_percpu(mpic); 579 + enable_percpu_irq(mpic->parent_irq, IRQ_TYPE_NONE); 580 + 600 581 return 0; 601 582 } 602 583 #else 603 - static void armada_xp_mpic_smp_cpu_init(void) {} 604 - static void ipi_resume(void) {} 584 + static void mpic_smp_cpu_init(struct mpic *mpic) {} 585 + static void mpic_ipi_resume(struct mpic *mpic) {} 605 586 #endif 606 587 607 - static struct irq_chip armada_370_xp_irq_chip = { 588 + static struct irq_chip mpic_irq_chip = { 608 589 .name = "MPIC", 609 - .irq_mask = armada_370_xp_irq_mask, 610 - .irq_mask_ack = armada_370_xp_irq_mask, 611 - .irq_unmask = armada_370_xp_irq_unmask, 590 + .irq_mask = mpic_irq_mask, 591 + .irq_mask_ack = mpic_irq_mask, 592 + .irq_unmask = mpic_irq_unmask, 612 593 #ifdef CONFIG_SMP 613 - .irq_set_affinity = armada_xp_set_affinity, 594 + .irq_set_affinity = mpic_set_affinity, 614 595 #endif 615 596 .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, 616 597 }; 617 598 618 - static int armada_370_xp_mpic_irq_map(struct irq_domain *h, 619 - unsigned int virq, irq_hw_number_t hw) 599 + static int mpic_irq_map(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) 620 600 { 601 + struct mpic *mpic = domain->host_data; 602 + 621 603 /* IRQs 0 and 1 cannot be mapped, they are handled internally */ 622 - if (hw <= 1) 604 + if (hwirq <= 1) 623 605 return -EINVAL; 624 606 625 - armada_370_xp_irq_mask(irq_get_irq_data(virq)); 626 - if (!is_percpu_irq(hw)) 627 - writel(hw, per_cpu_int_base + 628 - ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 607 + irq_set_chip_data(virq, mpic); 608 + 609 + mpic_irq_mask(irq_get_irq_data(virq)); 610 + if (!mpic_is_percpu_irq(hwirq)) 611 + writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 629 612 else 630 - writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); 613 + writel(hwirq, mpic->base + MPIC_INT_SET_ENABLE); 631 614 irq_set_status_flags(virq, IRQ_LEVEL); 632 615 633 - if (is_percpu_irq(hw)) { 616 + if (mpic_is_percpu_irq(hwirq)) { 634 617 irq_set_percpu_devid(virq); 635 - irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, 636 - handle_percpu_devid_irq); 618 + irq_set_chip_and_handler(virq, &mpic_irq_chip, handle_percpu_devid_irq); 637 619 } else { 638 - irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, 639 - handle_level_irq); 620 + irq_set_chip_and_handler(virq, &mpic_irq_chip, handle_level_irq); 640 621 irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq))); 641 622 } 642 623 irq_set_probe(virq); 643 - 644 624 return 0; 645 625 } 646 626 647 - static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = { 648 - .map = armada_370_xp_mpic_irq_map, 649 - .xlate = irq_domain_xlate_onecell, 627 + static const struct irq_domain_ops mpic_irq_ops = { 628 + .map = mpic_irq_map, 629 + .xlate = irq_domain_xlate_onecell, 650 630 }; 651 631 652 632 #ifdef CONFIG_PCI_MSI 653 - static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) 633 + static void mpic_handle_msi_irq(struct mpic *mpic) 654 634 { 655 - u32 msimask, msinr; 635 + unsigned long cause; 636 + unsigned int i; 656 637 657 - msimask = readl_relaxed(per_cpu_int_base + 658 - ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 659 - msimask &= msi_doorbell_mask(); 638 + cause = readl_relaxed(mpic->per_cpu + MPIC_IN_DRBEL_CAUSE); 639 + cause &= mpic->msi_doorbell_mask; 640 + writel(~cause, mpic->per_cpu + MPIC_IN_DRBEL_CAUSE); 660 641 661 - writel(~msimask, per_cpu_int_base + 662 - ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 663 - 664 - for (msinr = msi_doorbell_start(); 665 - msinr < msi_doorbell_end(); msinr++) { 666 - unsigned int irq; 667 - 668 - if (!(msimask & BIT(msinr))) 669 - continue; 670 - 671 - irq = msinr - msi_doorbell_start(); 672 - 673 - generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq); 674 - } 642 + for_each_set_bit(i, &cause, BITS_PER_LONG) 643 + generic_handle_domain_irq(mpic->msi_inner_domain, i - mpic->msi_doorbell_start); 675 644 } 676 645 #else 677 - static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} 646 + static void mpic_handle_msi_irq(struct mpic *mpic) {} 678 647 #endif 679 648 680 - static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc) 649 + #ifdef CONFIG_SMP 650 + static void mpic_handle_ipi_irq(struct mpic *mpic) 681 651 { 652 + unsigned long cause; 653 + irq_hw_number_t i; 654 + 655 + cause = readl_relaxed(mpic->per_cpu + MPIC_IN_DRBEL_CAUSE); 656 + cause &= IPI_DOORBELL_MASK; 657 + 658 + for_each_set_bit(i, &cause, IPI_DOORBELL_NR) 659 + generic_handle_domain_irq(mpic->ipi_domain, i); 660 + } 661 + #else 662 + static inline void mpic_handle_ipi_irq(struct mpic *mpic) {} 663 + #endif 664 + 665 + static void mpic_handle_cascade_irq(struct irq_desc *desc) 666 + { 667 + struct mpic *mpic = irq_desc_get_handler_data(desc); 682 668 struct irq_chip *chip = irq_desc_get_chip(desc); 683 - unsigned long irqmap, irqn, irqsrc, cpuid; 669 + unsigned long cause; 670 + u32 irqsrc, cpuid; 671 + irq_hw_number_t i; 684 672 685 673 chained_irq_enter(chip, desc); 686 674 687 - irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE); 675 + cause = readl_relaxed(mpic->per_cpu + MPIC_PPI_CAUSE); 688 676 cpuid = cpu_logical_map(smp_processor_id()); 689 677 690 - for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) { 691 - irqsrc = readl_relaxed(main_int_base + 692 - ARMADA_370_XP_INT_SOURCE_CTL(irqn)); 678 + for_each_set_bit(i, &cause, MPIC_PER_CPU_IRQS_NR) { 679 + irqsrc = readl_relaxed(mpic->base + MPIC_INT_SOURCE_CTL(i)); 693 680 694 681 /* Check if the interrupt is not masked on current CPU. 695 682 * Test IRQ (0-1) and FIQ (8-9) mask bits. 696 683 */ 697 - if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid))) 684 + if (!(irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid))) 698 685 continue; 699 686 700 - if (irqn == 0 || irqn == 1) { 701 - armada_370_xp_handle_msi_irq(NULL, true); 687 + if (i == 0 || i == 1) { 688 + mpic_handle_msi_irq(mpic); 702 689 continue; 703 690 } 704 691 705 - generic_handle_domain_irq(armada_370_xp_mpic_domain, irqn); 692 + generic_handle_domain_irq(mpic->domain, i); 706 693 } 707 694 708 695 chained_irq_exit(chip, desc); 709 696 } 710 697 711 - static void __exception_irq_entry 712 - armada_370_xp_handle_irq(struct pt_regs *regs) 698 + static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs) 713 699 { 714 - u32 irqstat, irqnr; 700 + struct mpic *mpic = irq_get_default_host()->host_data; 701 + irq_hw_number_t i; 702 + u32 irqstat; 715 703 716 704 do { 717 - irqstat = readl_relaxed(per_cpu_int_base + 718 - ARMADA_370_XP_CPU_INTACK_OFFS); 719 - irqnr = irqstat & 0x3FF; 705 + irqstat = readl_relaxed(mpic->per_cpu + MPIC_CPU_INTACK); 706 + i = FIELD_GET(MPIC_CPU_INTACK_IID_MASK, irqstat); 720 707 721 - if (irqnr > 1022) 708 + if (i > 1022) 722 709 break; 723 710 724 - if (irqnr > 1) { 725 - generic_handle_domain_irq(armada_370_xp_mpic_domain, 726 - irqnr); 727 - continue; 728 - } 711 + if (i > 1) 712 + generic_handle_domain_irq(mpic->domain, i); 729 713 730 714 /* MSI handling */ 731 - if (irqnr == 1) 732 - armada_370_xp_handle_msi_irq(regs, false); 715 + if (i == 1) 716 + mpic_handle_msi_irq(mpic); 733 717 734 - #ifdef CONFIG_SMP 735 718 /* IPI Handling */ 736 - if (irqnr == 0) { 737 - unsigned long ipimask; 738 - int ipi; 739 - 740 - ipimask = readl_relaxed(per_cpu_int_base + 741 - ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) 742 - & IPI_DOORBELL_MASK; 743 - 744 - for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END) 745 - generic_handle_domain_irq(ipi_domain, ipi); 746 - } 747 - #endif 748 - 719 + if (i == 0) 720 + mpic_handle_ipi_irq(mpic); 749 721 } while (1); 750 722 } 751 723 752 - static int armada_370_xp_mpic_suspend(void) 724 + static int mpic_suspend(void) 753 725 { 754 - doorbell_mask_reg = readl(per_cpu_int_base + 755 - ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 726 + struct mpic *mpic = mpic_data; 727 + 728 + mpic->doorbell_mask = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK); 729 + 756 730 return 0; 757 731 } 758 732 759 - static void armada_370_xp_mpic_resume(void) 733 + static void mpic_resume(void) 760 734 { 735 + struct mpic *mpic = mpic_data; 761 736 bool src0, src1; 762 - int nirqs; 763 - irq_hw_number_t irq; 764 737 765 738 /* Re-enable interrupts */ 766 - nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff; 767 - for (irq = 0; irq < nirqs; irq++) { 768 - struct irq_data *data; 769 - int virq; 739 + for (irq_hw_number_t i = 0; i < mpic->domain->hwirq_max; i++) { 740 + unsigned int virq = irq_linear_revmap(mpic->domain, i); 741 + struct irq_data *d; 770 742 771 - virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq); 772 - if (virq == 0) 743 + if (!virq) 773 744 continue; 774 745 775 - data = irq_get_irq_data(virq); 746 + d = irq_get_irq_data(virq); 776 747 777 - if (!is_percpu_irq(irq)) { 748 + if (!mpic_is_percpu_irq(i)) { 778 749 /* Non per-CPU interrupts */ 779 - writel(irq, per_cpu_int_base + 780 - ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 781 - if (!irqd_irq_disabled(data)) 782 - armada_370_xp_irq_unmask(data); 750 + writel(i, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 751 + if (!irqd_irq_disabled(d)) 752 + mpic_irq_unmask(d); 783 753 } else { 784 754 /* Per-CPU interrupts */ 785 - writel(irq, main_int_base + 786 - ARMADA_370_XP_INT_SET_ENABLE_OFFS); 755 + writel(i, mpic->base + MPIC_INT_SET_ENABLE); 787 756 788 757 /* 789 - * Re-enable on the current CPU, 790 - * armada_xp_mpic_reenable_percpu() will take 791 - * care of secondary CPUs when they come up. 758 + * Re-enable on the current CPU, mpic_reenable_percpu() 759 + * will take care of secondary CPUs when they come up. 792 760 */ 793 761 if (irq_percpu_is_enabled(virq)) 794 - armada_370_xp_irq_unmask(data); 762 + mpic_irq_unmask(d); 795 763 } 796 764 } 797 765 798 766 /* Reconfigure doorbells for IPIs and MSIs */ 799 - writel(doorbell_mask_reg, 800 - per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 767 + writel(mpic->doorbell_mask, mpic->per_cpu + MPIC_IN_DRBEL_MASK); 801 768 802 - if (is_ipi_available()) { 803 - src0 = doorbell_mask_reg & IPI_DOORBELL_MASK; 804 - src1 = doorbell_mask_reg & PCI_MSI_DOORBELL_MASK; 769 + if (mpic_is_ipi_available(mpic)) { 770 + src0 = mpic->doorbell_mask & IPI_DOORBELL_MASK; 771 + src1 = mpic->doorbell_mask & PCI_MSI_DOORBELL_MASK; 805 772 } else { 806 - src0 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC0_MASK; 807 - src1 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC1_MASK; 773 + src0 = mpic->doorbell_mask & PCI_MSI_FULL_DOORBELL_SRC0_MASK; 774 + src1 = mpic->doorbell_mask & PCI_MSI_FULL_DOORBELL_SRC1_MASK; 808 775 } 809 776 810 777 if (src0) 811 - writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 778 + writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 812 779 if (src1) 813 - writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 780 + writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK); 814 781 815 - if (is_ipi_available()) 816 - ipi_resume(); 782 + if (mpic_is_ipi_available(mpic)) 783 + mpic_ipi_resume(mpic); 817 784 } 818 785 819 - static struct syscore_ops armada_370_xp_mpic_syscore_ops = { 820 - .suspend = armada_370_xp_mpic_suspend, 821 - .resume = armada_370_xp_mpic_resume, 786 + static struct syscore_ops mpic_syscore_ops = { 787 + .suspend = mpic_suspend, 788 + .resume = mpic_resume, 822 789 }; 823 790 824 - static int __init armada_370_xp_mpic_of_init(struct device_node *node, 825 - struct device_node *parent) 791 + static int __init mpic_map_region(struct device_node *np, int index, 792 + void __iomem **base, phys_addr_t *phys_base) 826 793 { 827 - struct resource main_int_res, per_cpu_int_res; 828 - int nr_irqs, i; 829 - u32 control; 794 + struct resource res; 795 + int err; 830 796 831 - BUG_ON(of_address_to_resource(node, 0, &main_int_res)); 832 - BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res)); 797 + err = of_address_to_resource(np, index, &res); 798 + if (WARN_ON(err)) 799 + goto fail; 833 800 834 - BUG_ON(!request_mem_region(main_int_res.start, 835 - resource_size(&main_int_res), 836 - node->full_name)); 837 - BUG_ON(!request_mem_region(per_cpu_int_res.start, 838 - resource_size(&per_cpu_int_res), 839 - node->full_name)); 801 + if (WARN_ON(!request_mem_region(res.start, resource_size(&res), np->full_name))) { 802 + err = -EBUSY; 803 + goto fail; 804 + } 840 805 841 - main_int_base = ioremap(main_int_res.start, 842 - resource_size(&main_int_res)); 843 - BUG_ON(!main_int_base); 806 + *base = ioremap(res.start, resource_size(&res)); 807 + if (WARN_ON(!*base)) { 808 + err = -ENOMEM; 809 + goto fail; 810 + } 844 811 845 - per_cpu_int_base = ioremap(per_cpu_int_res.start, 846 - resource_size(&per_cpu_int_res)); 847 - BUG_ON(!per_cpu_int_base); 812 + if (phys_base) 813 + *phys_base = res.start; 848 814 849 - control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); 850 - nr_irqs = (control >> 2) & 0x3ff; 815 + return 0; 851 816 852 - for (i = 0; i < nr_irqs; i++) 853 - writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); 817 + fail: 818 + pr_err("%pOF: Unable to map resource %d: %pE\n", np, index, ERR_PTR(err)); 819 + return err; 820 + } 854 821 855 - armada_370_xp_mpic_domain = 856 - irq_domain_add_linear(node, nr_irqs, 857 - &armada_370_xp_mpic_irq_ops, NULL); 858 - BUG_ON(!armada_370_xp_mpic_domain); 859 - irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED); 822 + static int __init mpic_of_init(struct device_node *node, struct device_node *parent) 823 + { 824 + phys_addr_t phys_base; 825 + unsigned int nr_irqs; 826 + struct mpic *mpic; 827 + int err; 828 + 829 + mpic = kzalloc(sizeof(*mpic), GFP_KERNEL); 830 + if (WARN_ON(!mpic)) 831 + return -ENOMEM; 832 + 833 + mpic_data = mpic; 834 + 835 + err = mpic_map_region(node, 0, &mpic->base, &phys_base); 836 + if (err) 837 + return err; 838 + 839 + err = mpic_map_region(node, 1, &mpic->per_cpu, NULL); 840 + if (err) 841 + return err; 842 + 843 + nr_irqs = FIELD_GET(MPIC_INT_CONTROL_NUMINT_MASK, readl(mpic->base + MPIC_INT_CONTROL)); 844 + 845 + for (irq_hw_number_t i = 0; i < nr_irqs; i++) 846 + writel(i, mpic->base + MPIC_INT_CLEAR_ENABLE); 860 847 861 848 /* 862 - * Initialize parent_irq before calling any other functions, since it is 863 - * used to distinguish between IPI and non-IPI platforms. 849 + * Initialize mpic->parent_irq before calling any other functions, since 850 + * it is used to distinguish between IPI and non-IPI platforms. 864 851 */ 865 - parent_irq = irq_of_parse_and_map(node, 0); 852 + mpic->parent_irq = irq_of_parse_and_map(node, 0); 853 + 854 + /* 855 + * On non-IPI platforms the driver currently supports only the per-CPU 856 + * interrupts (the first 29 interrupts). See mpic_handle_cascade_irq(). 857 + */ 858 + if (!mpic_is_ipi_available(mpic)) 859 + nr_irqs = MPIC_PER_CPU_IRQS_NR; 860 + 861 + mpic->domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, mpic); 862 + if (!mpic->domain) { 863 + pr_err("%pOF: Unable to add IRQ domain\n", node); 864 + return -ENOMEM; 865 + } 866 + 867 + irq_domain_update_bus_token(mpic->domain, DOMAIN_BUS_WIRED); 866 868 867 869 /* Setup for the boot CPU */ 868 - armada_xp_mpic_perf_init(); 869 - armada_xp_mpic_smp_cpu_init(); 870 + mpic_perf_init(mpic); 871 + mpic_smp_cpu_init(mpic); 870 872 871 - armada_370_xp_msi_init(node, main_int_res.start); 873 + err = mpic_msi_init(mpic, node, phys_base); 874 + if (err) { 875 + pr_err("%pOF: Unable to initialize MSI domain\n", node); 876 + return err; 877 + } 872 878 873 - if (parent_irq <= 0) { 874 - irq_set_default_host(armada_370_xp_mpic_domain); 875 - set_handle_irq(armada_370_xp_handle_irq); 879 + if (mpic_is_ipi_available(mpic)) { 880 + irq_set_default_host(mpic->domain); 881 + set_handle_irq(mpic_handle_irq); 876 882 #ifdef CONFIG_SMP 877 - armada_xp_ipi_init(node); 883 + err = mpic_ipi_init(mpic, node); 884 + if (err) { 885 + pr_err("%pOF: Unable to initialize IPI domain\n", node); 886 + return err; 887 + } 888 + 878 889 cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING, 879 890 "irqchip/armada/ipi:starting", 880 - armada_xp_mpic_starting_cpu, NULL); 891 + mpic_starting_cpu, NULL); 881 892 #endif 882 893 } else { 883 894 #ifdef CONFIG_SMP ··· 899 882 "irqchip/armada/cascade:starting", 900 883 mpic_cascaded_starting_cpu, NULL); 901 884 #endif 902 - irq_set_chained_handler(parent_irq, 903 - armada_370_xp_mpic_handle_cascade_irq); 885 + irq_set_chained_handler_and_data(mpic->parent_irq, 886 + mpic_handle_cascade_irq, mpic); 904 887 } 905 888 906 - register_syscore_ops(&armada_370_xp_mpic_syscore_ops); 889 + register_syscore_ops(&mpic_syscore_ops); 907 890 908 891 return 0; 909 892 } 910 893 911 - IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init); 894 + IRQCHIP_DECLARE(marvell_mpic, "marvell,mpic", mpic_of_init);
+1 -2
drivers/irqchip/irq-atmel-aic.c
··· 57 57 58 58 static struct irq_domain *aic_domain; 59 59 60 - static asmlinkage void __exception_irq_entry 61 - aic_handle(struct pt_regs *regs) 60 + static void __exception_irq_entry aic_handle(struct pt_regs *regs) 62 61 { 63 62 struct irq_domain_chip_generic *dgc = aic_domain->gc; 64 63 struct irq_chip_generic *gc = dgc->gc[0];
+1 -2
drivers/irqchip/irq-atmel-aic5.c
··· 67 67 68 68 static struct irq_domain *aic5_domain; 69 69 70 - static asmlinkage void __exception_irq_entry 71 - aic5_handle(struct pt_regs *regs) 70 + static void __exception_irq_entry aic5_handle(struct pt_regs *regs) 72 71 { 73 72 struct irq_chip_generic *bgc = irq_get_domain_generic_chip(aic5_domain, 0); 74 73 u32 irqnr;
+1 -1
drivers/irqchip/irq-clps711x.c
··· 69 69 struct irq_domain_ops ops; 70 70 } *clps711x_intc; 71 71 72 - static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs) 72 + static void __exception_irq_entry clps711x_irqh(struct pt_regs *regs) 73 73 { 74 74 u32 irqstat; 75 75
+1 -2
drivers/irqchip/irq-davinci-cp-intc.c
··· 116 116 .flags = IRQCHIP_SKIP_SET_WAKE, 117 117 }; 118 118 119 - static asmlinkage void __exception_irq_entry 120 - davinci_cp_intc_handle_irq(struct pt_regs *regs) 119 + static void __exception_irq_entry davinci_cp_intc_handle_irq(struct pt_regs *regs) 121 120 { 122 121 int gpir, irqnr, none; 123 122
+1 -1
drivers/irqchip/irq-ftintc010.c
··· 125 125 /* Local static for the IRQ entry call */ 126 126 static struct ft010_irq_data firq; 127 127 128 - static asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs) 128 + static void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs) 129 129 { 130 130 struct ft010_irq_data *f = &firq; 131 131 int irq;
+1 -1
drivers/irqchip/irq-gic-v3.c
··· 930 930 __gic_handle_nmi(irqnr, regs); 931 931 } 932 932 933 - static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) 933 + static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) 934 934 { 935 935 if (unlikely(gic_supports_nmi() && !interrupts_enabled(regs))) 936 936 __gic_handle_irq_from_irqsoff(regs);
+1 -1
drivers/irqchip/irq-gic-v4.c
··· 97 97 98 98 fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_EL1_GIC_SHIFT); 99 99 100 - return fld >= 0x3; 100 + return fld >= ID_AA64PFR0_EL1_GIC_V4P1; 101 101 } 102 102 #else 103 103 bool gic_cpuif_has_vsgi(void)
+1 -2
drivers/irqchip/irq-ixp4xx.c
··· 105 105 } 106 106 } 107 107 108 - static asmlinkage void __exception_irq_entry 109 - ixp4xx_handle_irq(struct pt_regs *regs) 108 + static void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs) 110 109 { 111 110 struct ixp4xx_irq *ixi = &ixirq; 112 111 unsigned long status;
+425
drivers/irqchip/irq-loongarch-avec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020-2024 Loongson Technologies, Inc. 4 + */ 5 + 6 + #include <linux/cpuhotplug.h> 7 + #include <linux/init.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/irq.h> 10 + #include <linux/irqchip.h> 11 + #include <linux/irqchip/chained_irq.h> 12 + #include <linux/irqdomain.h> 13 + #include <linux/kernel.h> 14 + #include <linux/msi.h> 15 + #include <linux/radix-tree.h> 16 + #include <linux/spinlock.h> 17 + 18 + #include <asm/loongarch.h> 19 + #include <asm/setup.h> 20 + 21 + #include "irq-msi-lib.h" 22 + #include "irq-loongson.h" 23 + 24 + #define VECTORS_PER_REG 64 25 + #define IRR_VECTOR_MASK 0xffUL 26 + #define IRR_INVALID_MASK 0x80000000UL 27 + #define AVEC_MSG_OFFSET 0x100000 28 + 29 + #ifdef CONFIG_SMP 30 + struct pending_list { 31 + struct list_head head; 32 + }; 33 + 34 + static struct cpumask intersect_mask; 35 + static DEFINE_PER_CPU(struct pending_list, pending_list); 36 + #endif 37 + 38 + static DEFINE_PER_CPU(struct irq_desc * [NR_VECTORS], irq_map); 39 + 40 + struct avecintc_chip { 41 + raw_spinlock_t lock; 42 + struct fwnode_handle *fwnode; 43 + struct irq_domain *domain; 44 + struct irq_matrix *vector_matrix; 45 + phys_addr_t msi_base_addr; 46 + }; 47 + 48 + static struct avecintc_chip loongarch_avec; 49 + 50 + struct avecintc_data { 51 + struct list_head entry; 52 + unsigned int cpu; 53 + unsigned int vec; 54 + unsigned int prev_cpu; 55 + unsigned int prev_vec; 56 + unsigned int moving; 57 + }; 58 + 59 + static inline void avecintc_ack_irq(struct irq_data *d) 60 + { 61 + } 62 + 63 + static inline void avecintc_mask_irq(struct irq_data *d) 64 + { 65 + } 66 + 67 + static inline void avecintc_unmask_irq(struct irq_data *d) 68 + { 69 + } 70 + 71 + #ifdef CONFIG_SMP 72 + static inline void pending_list_init(int cpu) 73 + { 74 + struct pending_list *plist = per_cpu_ptr(&pending_list, cpu); 75 + 76 + INIT_LIST_HEAD(&plist->head); 77 + } 78 + 79 + static void avecintc_sync(struct avecintc_data *adata) 80 + { 81 + struct pending_list *plist; 82 + 83 + if (cpu_online(adata->prev_cpu)) { 84 + plist = per_cpu_ptr(&pending_list, adata->prev_cpu); 85 + list_add_tail(&adata->entry, &plist->head); 86 + adata->moving = 1; 87 + mp_ops.send_ipi_single(adata->prev_cpu, ACTION_CLEAR_VECTOR); 88 + } 89 + } 90 + 91 + static int avecintc_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force) 92 + { 93 + int cpu, ret, vector; 94 + struct avecintc_data *adata; 95 + 96 + scoped_guard(raw_spinlock, &loongarch_avec.lock) { 97 + adata = irq_data_get_irq_chip_data(data); 98 + 99 + if (adata->moving) 100 + return -EBUSY; 101 + 102 + if (cpu_online(adata->cpu) && cpumask_test_cpu(adata->cpu, dest)) 103 + return 0; 104 + 105 + cpumask_and(&intersect_mask, dest, cpu_online_mask); 106 + 107 + ret = irq_matrix_alloc(loongarch_avec.vector_matrix, &intersect_mask, false, &cpu); 108 + if (ret < 0) 109 + return ret; 110 + 111 + vector = ret; 112 + adata->cpu = cpu; 113 + adata->vec = vector; 114 + per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(data); 115 + avecintc_sync(adata); 116 + } 117 + 118 + irq_data_update_effective_affinity(data, cpumask_of(cpu)); 119 + 120 + return IRQ_SET_MASK_OK; 121 + } 122 + 123 + static int avecintc_cpu_online(unsigned int cpu) 124 + { 125 + if (!loongarch_avec.vector_matrix) 126 + return 0; 127 + 128 + guard(raw_spinlock)(&loongarch_avec.lock); 129 + 130 + irq_matrix_online(loongarch_avec.vector_matrix); 131 + 132 + pending_list_init(cpu); 133 + 134 + return 0; 135 + } 136 + 137 + static int avecintc_cpu_offline(unsigned int cpu) 138 + { 139 + struct pending_list *plist = per_cpu_ptr(&pending_list, cpu); 140 + 141 + if (!loongarch_avec.vector_matrix) 142 + return 0; 143 + 144 + guard(raw_spinlock)(&loongarch_avec.lock); 145 + 146 + if (!list_empty(&plist->head)) 147 + pr_warn("CPU#%d vector is busy\n", cpu); 148 + 149 + irq_matrix_offline(loongarch_avec.vector_matrix); 150 + 151 + return 0; 152 + } 153 + 154 + void complete_irq_moving(void) 155 + { 156 + struct pending_list *plist = this_cpu_ptr(&pending_list); 157 + struct avecintc_data *adata, *tdata; 158 + int cpu, vector, bias; 159 + uint64_t isr; 160 + 161 + guard(raw_spinlock)(&loongarch_avec.lock); 162 + 163 + list_for_each_entry_safe(adata, tdata, &plist->head, entry) { 164 + cpu = adata->prev_cpu; 165 + vector = adata->prev_vec; 166 + bias = vector / VECTORS_PER_REG; 167 + switch (bias) { 168 + case 0: 169 + isr = csr_read64(LOONGARCH_CSR_ISR0); 170 + break; 171 + case 1: 172 + isr = csr_read64(LOONGARCH_CSR_ISR1); 173 + break; 174 + case 2: 175 + isr = csr_read64(LOONGARCH_CSR_ISR2); 176 + break; 177 + case 3: 178 + isr = csr_read64(LOONGARCH_CSR_ISR3); 179 + break; 180 + } 181 + 182 + if (isr & (1UL << (vector % VECTORS_PER_REG))) { 183 + mp_ops.send_ipi_single(cpu, ACTION_CLEAR_VECTOR); 184 + continue; 185 + } 186 + list_del(&adata->entry); 187 + irq_matrix_free(loongarch_avec.vector_matrix, cpu, vector, false); 188 + this_cpu_write(irq_map[vector], NULL); 189 + adata->moving = 0; 190 + adata->prev_cpu = adata->cpu; 191 + adata->prev_vec = adata->vec; 192 + } 193 + } 194 + #endif 195 + 196 + static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) 197 + { 198 + struct avecintc_data *adata = irq_data_get_irq_chip_data(d); 199 + 200 + msg->address_hi = 0x0; 201 + msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4) 202 + | ((cpu_logical_map(adata->cpu & 0xffff)) << 12); 203 + msg->data = 0x0; 204 + } 205 + 206 + static struct irq_chip avec_irq_controller = { 207 + .name = "AVECINTC", 208 + .irq_ack = avecintc_ack_irq, 209 + .irq_mask = avecintc_mask_irq, 210 + .irq_unmask = avecintc_unmask_irq, 211 + #ifdef CONFIG_SMP 212 + .irq_set_affinity = avecintc_set_affinity, 213 + #endif 214 + .irq_compose_msi_msg = avecintc_compose_msi_msg, 215 + }; 216 + 217 + static void avecintc_irq_dispatch(struct irq_desc *desc) 218 + { 219 + struct irq_chip *chip = irq_desc_get_chip(desc); 220 + struct irq_desc *d; 221 + 222 + chained_irq_enter(chip, desc); 223 + 224 + while (true) { 225 + unsigned long vector = csr_read64(LOONGARCH_CSR_IRR); 226 + if (vector & IRR_INVALID_MASK) 227 + break; 228 + 229 + vector &= IRR_VECTOR_MASK; 230 + 231 + d = this_cpu_read(irq_map[vector]); 232 + if (d) { 233 + generic_handle_irq_desc(d); 234 + } else { 235 + spurious_interrupt(); 236 + pr_warn("Unexpected IRQ occurs on CPU#%d [vector %ld]\n", smp_processor_id(), vector); 237 + } 238 + } 239 + 240 + chained_irq_exit(chip, desc); 241 + } 242 + 243 + static int avecintc_alloc_vector(struct irq_data *irqd, struct avecintc_data *adata) 244 + { 245 + int cpu, ret; 246 + 247 + guard(raw_spinlock_irqsave)(&loongarch_avec.lock); 248 + 249 + ret = irq_matrix_alloc(loongarch_avec.vector_matrix, cpu_online_mask, false, &cpu); 250 + if (ret < 0) 251 + return ret; 252 + 253 + adata->prev_cpu = adata->cpu = cpu; 254 + adata->prev_vec = adata->vec = ret; 255 + per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(irqd); 256 + 257 + return 0; 258 + } 259 + 260 + static int avecintc_domain_alloc(struct irq_domain *domain, unsigned int virq, 261 + unsigned int nr_irqs, void *arg) 262 + { 263 + for (unsigned int i = 0; i < nr_irqs; i++) { 264 + struct irq_data *irqd = irq_domain_get_irq_data(domain, virq + i); 265 + struct avecintc_data *adata = kzalloc(sizeof(*adata), GFP_KERNEL); 266 + int ret; 267 + 268 + if (!adata) 269 + return -ENOMEM; 270 + 271 + ret = avecintc_alloc_vector(irqd, adata); 272 + if (ret < 0) { 273 + kfree(adata); 274 + return ret; 275 + } 276 + 277 + irq_domain_set_info(domain, virq + i, virq + i, &avec_irq_controller, 278 + adata, handle_edge_irq, NULL, NULL); 279 + irqd_set_single_target(irqd); 280 + irqd_set_affinity_on_activate(irqd); 281 + } 282 + 283 + return 0; 284 + } 285 + 286 + static void avecintc_free_vector(struct irq_data *irqd, struct avecintc_data *adata) 287 + { 288 + guard(raw_spinlock_irqsave)(&loongarch_avec.lock); 289 + 290 + per_cpu(irq_map, adata->cpu)[adata->vec] = NULL; 291 + irq_matrix_free(loongarch_avec.vector_matrix, adata->cpu, adata->vec, false); 292 + 293 + #ifdef CONFIG_SMP 294 + if (!adata->moving) 295 + return; 296 + 297 + per_cpu(irq_map, adata->prev_cpu)[adata->prev_vec] = NULL; 298 + irq_matrix_free(loongarch_avec.vector_matrix, adata->prev_cpu, adata->prev_vec, false); 299 + list_del_init(&adata->entry); 300 + #endif 301 + } 302 + 303 + static void avecintc_domain_free(struct irq_domain *domain, unsigned int virq, 304 + unsigned int nr_irqs) 305 + { 306 + for (unsigned int i = 0; i < nr_irqs; i++) { 307 + struct irq_data *d = irq_domain_get_irq_data(domain, virq + i); 308 + 309 + if (d) { 310 + struct avecintc_data *adata = irq_data_get_irq_chip_data(d); 311 + 312 + avecintc_free_vector(d, adata); 313 + irq_domain_reset_irq_data(d); 314 + kfree(adata); 315 + } 316 + } 317 + } 318 + 319 + static const struct irq_domain_ops avecintc_domain_ops = { 320 + .alloc = avecintc_domain_alloc, 321 + .free = avecintc_domain_free, 322 + .select = msi_lib_irq_domain_select, 323 + }; 324 + 325 + static int __init irq_matrix_init(void) 326 + { 327 + loongarch_avec.vector_matrix = irq_alloc_matrix(NR_VECTORS, 0, NR_VECTORS); 328 + if (!loongarch_avec.vector_matrix) 329 + return -ENOMEM; 330 + 331 + for (int i = 0; i < NR_LEGACY_VECTORS; i++) 332 + irq_matrix_assign_system(loongarch_avec.vector_matrix, i, false); 333 + 334 + irq_matrix_online(loongarch_avec.vector_matrix); 335 + 336 + return 0; 337 + } 338 + 339 + static int __init avecintc_init(struct irq_domain *parent) 340 + { 341 + int ret, parent_irq; 342 + unsigned long value; 343 + 344 + raw_spin_lock_init(&loongarch_avec.lock); 345 + 346 + loongarch_avec.fwnode = irq_domain_alloc_named_fwnode("AVECINTC"); 347 + if (!loongarch_avec.fwnode) { 348 + pr_err("Unable to allocate domain handle\n"); 349 + ret = -ENOMEM; 350 + goto out; 351 + } 352 + 353 + loongarch_avec.domain = irq_domain_create_tree(loongarch_avec.fwnode, 354 + &avecintc_domain_ops, NULL); 355 + if (!loongarch_avec.domain) { 356 + pr_err("Unable to create IRQ domain\n"); 357 + ret = -ENOMEM; 358 + goto out_free_handle; 359 + } 360 + 361 + parent_irq = irq_create_mapping(parent, INT_AVEC); 362 + if (!parent_irq) { 363 + pr_err("Failed to mapping hwirq\n"); 364 + ret = -EINVAL; 365 + goto out_remove_domain; 366 + } 367 + 368 + ret = irq_matrix_init(); 369 + if (ret < 0) { 370 + pr_err("Failed to init irq matrix\n"); 371 + goto out_remove_domain; 372 + } 373 + irq_set_chained_handler_and_data(parent_irq, avecintc_irq_dispatch, NULL); 374 + 375 + #ifdef CONFIG_SMP 376 + pending_list_init(0); 377 + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_AVECINTC_STARTING, 378 + "irqchip/loongarch/avecintc:starting", 379 + avecintc_cpu_online, avecintc_cpu_offline); 380 + #endif 381 + value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); 382 + value |= IOCSR_MISC_FUNC_AVEC_EN; 383 + iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC); 384 + 385 + return ret; 386 + 387 + out_remove_domain: 388 + irq_domain_remove(loongarch_avec.domain); 389 + out_free_handle: 390 + irq_domain_free_fwnode(loongarch_avec.fwnode); 391 + out: 392 + return ret; 393 + } 394 + 395 + static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, 396 + const unsigned long end) 397 + { 398 + struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; 399 + 400 + loongarch_avec.msi_base_addr = pchmsi_entry->msg_address - AVEC_MSG_OFFSET; 401 + 402 + return pch_msi_acpi_init_avec(loongarch_avec.domain); 403 + } 404 + 405 + static inline int __init acpi_cascade_irqdomain_init(void) 406 + { 407 + return acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); 408 + } 409 + 410 + int __init avecintc_acpi_init(struct irq_domain *parent) 411 + { 412 + int ret = avecintc_init(parent); 413 + if (ret < 0) { 414 + pr_err("Failed to init IRQ domain\n"); 415 + return ret; 416 + } 417 + 418 + ret = acpi_cascade_irqdomain_init(); 419 + if (ret < 0) { 420 + pr_err("Failed to init cascade IRQ domain\n"); 421 + return ret; 422 + } 423 + 424 + return ret; 425 + }
+6 -1
drivers/irqchip/irq-loongarch-cpu.c
··· 13 13 #include <asm/loongarch.h> 14 14 #include <asm/setup.h> 15 15 16 + #include "irq-loongson.h" 17 + 16 18 static struct irq_domain *irq_domain; 17 19 struct fwnode_handle *cpuintc_handle; 18 20 ··· 142 140 if (r < 0) 143 141 return r; 144 142 145 - return 0; 143 + if (cpu_has_avecint) 144 + r = avecintc_acpi_init(irq_domain); 145 + 146 + return r; 146 147 } 147 148 148 149 static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
+7 -2
drivers/irqchip/irq-loongson-eiointc.c
··· 17 17 #include <linux/syscore_ops.h> 18 18 #include <asm/numa.h> 19 19 20 + #include "irq-loongson.h" 21 + 20 22 #define EIOINTC_REG_NODEMAP 0x14a0 21 23 #define EIOINTC_REG_IPMAP 0x14c0 22 24 #define EIOINTC_REG_ENABLE 0x1600 ··· 362 360 if (r < 0) 363 361 return r; 364 362 363 + if (cpu_has_avecint) 364 + return 0; 365 + 365 366 r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); 366 367 if (r < 0) 367 368 return r; ··· 401 396 402 397 if (nr_pics == 1) { 403 398 register_syscore_ops(&eiointc_syscore_ops); 404 - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, 405 - "irqchip/loongarch/intc:starting", 399 + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_EIOINTC_STARTING, 400 + "irqchip/loongarch/eiointc:starting", 406 401 eiointc_router_init, NULL); 407 402 } 408 403
+2
drivers/irqchip/irq-loongson-htvec.c
··· 17 17 #include <linux/of_irq.h> 18 18 #include <linux/syscore_ops.h> 19 19 20 + #include "irq-loongson.h" 21 + 20 22 /* Registers */ 21 23 #define HTVEC_EN_OFF 0x20 22 24 #define HTVEC_MAX_PARENT_IRQ 8
+2
drivers/irqchip/irq-loongson-liointc.c
··· 22 22 #include <asm/loongson.h> 23 23 #endif 24 24 25 + #include "irq-loongson.h" 26 + 25 27 #define LIOINTC_CHIP_IRQ 32 26 28 #define LIOINTC_NUM_PARENT 4 27 29 #define LIOINTC_NUM_CORES 4
+2
drivers/irqchip/irq-loongson-pch-lpc.c
··· 15 15 #include <linux/kernel.h> 16 16 #include <linux/syscore_ops.h> 17 17 18 + #include "irq-loongson.h" 19 + 18 20 /* Registers */ 19 21 #define LPC_INT_CTL 0x00 20 22 #define LPC_INT_ENA 0x04
+43 -40
drivers/irqchip/irq-loongson-pch-msi.c
··· 15 15 #include <linux/pci.h> 16 16 #include <linux/slab.h> 17 17 18 + #include "irq-msi-lib.h" 19 + #include "irq-loongson.h" 20 + 18 21 static int nr_pics; 19 22 20 23 struct pch_msi_data { ··· 29 26 }; 30 27 31 28 static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS]; 32 - 33 - static void pch_msi_mask_msi_irq(struct irq_data *d) 34 - { 35 - pci_msi_mask_irq(d); 36 - irq_chip_mask_parent(d); 37 - } 38 - 39 - static void pch_msi_unmask_msi_irq(struct irq_data *d) 40 - { 41 - irq_chip_unmask_parent(d); 42 - pci_msi_unmask_irq(d); 43 - } 44 - 45 - static struct irq_chip pch_msi_irq_chip = { 46 - .name = "PCH PCI MSI", 47 - .irq_mask = pch_msi_mask_msi_irq, 48 - .irq_unmask = pch_msi_unmask_msi_irq, 49 - .irq_ack = irq_chip_ack_parent, 50 - .irq_set_affinity = irq_chip_set_affinity_parent, 51 - }; 52 29 53 30 static int pch_msi_allocate_hwirq(struct pch_msi_data *priv, int num_req) 54 31 { ··· 67 84 msg->address_lo = lower_32_bits(priv->doorbell); 68 85 msg->data = data->hwirq; 69 86 } 70 - 71 - static struct msi_domain_info pch_msi_domain_info = { 72 - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 73 - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, 74 - .chip = &pch_msi_irq_chip, 75 - }; 76 87 77 88 static struct irq_chip middle_irq_chip = { 78 89 .name = "PCH MSI", ··· 132 155 static const struct irq_domain_ops pch_msi_middle_domain_ops = { 133 156 .alloc = pch_msi_middle_domain_alloc, 134 157 .free = pch_msi_middle_domain_free, 158 + .select = msi_lib_irq_domain_select, 159 + }; 160 + 161 + #define PCH_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 162 + MSI_FLAG_USE_DEF_CHIP_OPS | \ 163 + MSI_FLAG_PCI_MSI_MASK_PARENT) 164 + 165 + #define PCH_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 166 + MSI_FLAG_PCI_MSIX | \ 167 + MSI_FLAG_MULTI_PCI_MSI) 168 + 169 + static struct msi_parent_ops pch_msi_parent_ops = { 170 + .required_flags = PCH_MSI_FLAGS_REQUIRED, 171 + .supported_flags = PCH_MSI_FLAGS_SUPPORTED, 172 + .bus_select_mask = MATCH_PCI_MSI, 173 + .bus_select_token = DOMAIN_BUS_NEXUS, 174 + .prefix = "PCH-", 175 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 135 176 }; 136 177 137 178 static int pch_msi_init_domains(struct pch_msi_data *priv, 138 179 struct irq_domain *parent, 139 180 struct fwnode_handle *domain_handle) 140 181 { 141 - struct irq_domain *middle_domain, *msi_domain; 182 + struct irq_domain *middle_domain; 142 183 143 184 middle_domain = irq_domain_create_hierarchy(parent, 0, priv->num_irqs, 144 185 domain_handle, ··· 169 174 170 175 irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); 171 176 172 - msi_domain = pci_msi_create_irq_domain(domain_handle, 173 - &pch_msi_domain_info, 174 - middle_domain); 175 - if (!msi_domain) { 176 - pr_err("Failed to create PCI MSI domain\n"); 177 - irq_domain_remove(middle_domain); 178 - return -ENOMEM; 179 - } 177 + middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 178 + middle_domain->msi_parent_ops = &pch_msi_parent_ops; 180 179 181 180 return 0; 182 181 } ··· 255 266 #ifdef CONFIG_ACPI 256 267 struct fwnode_handle *get_pch_msi_handle(int pci_segment) 257 268 { 258 - int i; 269 + if (cpu_has_avecint) 270 + return pch_msi_handle[0]; 259 271 260 - for (i = 0; i < MAX_IO_PICS; i++) { 272 + for (int i = 0; i < MAX_IO_PICS; i++) { 261 273 if (msi_group[i].pci_segment == pci_segment) 262 274 return pch_msi_handle[i]; 263 275 } 264 - return NULL; 276 + return pch_msi_handle[0]; 265 277 } 266 278 267 - int __init pch_msi_acpi_init(struct irq_domain *parent, 268 - struct acpi_madt_msi_pic *acpi_pchmsi) 279 + int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_msi_pic *acpi_pchmsi) 269 280 { 270 281 int ret; 271 282 struct fwnode_handle *domain_handle; ··· 277 288 irq_domain_free_fwnode(domain_handle); 278 289 279 290 return ret; 291 + } 292 + 293 + int __init pch_msi_acpi_init_avec(struct irq_domain *parent) 294 + { 295 + if (pch_msi_handle[0]) 296 + return 0; 297 + 298 + pch_msi_handle[0] = parent->fwnode; 299 + irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); 300 + 301 + parent->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 302 + parent->msi_parent_ops = &pch_msi_parent_ops; 303 + 304 + return 0; 280 305 } 281 306 #endif
+2
drivers/irqchip/irq-loongson-pch-pic.c
··· 17 17 #include <linux/of_irq.h> 18 18 #include <linux/syscore_ops.h> 19 19 20 + #include "irq-loongson.h" 21 + 20 22 /* Registers */ 21 23 #define PCH_PIC_MASK 0x20 22 24 #define PCH_PIC_HTMSI_EN 0x40
+27
drivers/irqchip/irq-loongson.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2024 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #ifndef _DRIVERS_IRQCHIP_IRQ_LOONGSON_H 7 + #define _DRIVERS_IRQCHIP_IRQ_LOONGSON_H 8 + 9 + int find_pch_pic(u32 gsi); 10 + 11 + int liointc_acpi_init(struct irq_domain *parent, 12 + struct acpi_madt_lio_pic *acpi_liointc); 13 + int eiointc_acpi_init(struct irq_domain *parent, 14 + struct acpi_madt_eio_pic *acpi_eiointc); 15 + int avecintc_acpi_init(struct irq_domain *parent); 16 + 17 + int htvec_acpi_init(struct irq_domain *parent, 18 + struct acpi_madt_ht_pic *acpi_htvec); 19 + int pch_lpc_acpi_init(struct irq_domain *parent, 20 + struct acpi_madt_lpc_pic *acpi_pchlpc); 21 + int pch_pic_acpi_init(struct irq_domain *parent, 22 + struct acpi_madt_bio_pic *acpi_pchpic); 23 + int pch_msi_acpi_init(struct irq_domain *parent, 24 + struct acpi_madt_msi_pic *acpi_pchmsi); 25 + int pch_msi_acpi_init_avec(struct irq_domain *parent); 26 + 27 + #endif /* _DRIVERS_IRQCHIP_IRQ_LOONGSON_H */
+7 -17
drivers/irqchip/irq-mbigen.c
··· 234 234 struct mbigen_device *mgn_chip) 235 235 { 236 236 struct platform_device *child; 237 - struct device_node *np; 238 237 u32 num_pins; 239 - int ret = 0; 240 238 241 - for_each_child_of_node(pdev->dev.of_node, np) { 239 + for_each_child_of_node_scoped(pdev->dev.of_node, np) { 242 240 if (!of_property_read_bool(np, "interrupt-controller")) 243 241 continue; 244 242 245 243 child = of_platform_device_create(np, NULL, NULL); 246 - if (!child) { 247 - ret = -ENOMEM; 248 - break; 249 - } 244 + if (!child) 245 + return -ENOMEM; 250 246 251 247 if (of_property_read_u32(child->dev.of_node, "num-pins", 252 248 &num_pins) < 0) { 253 249 dev_err(&pdev->dev, "No num-pins property\n"); 254 - ret = -EINVAL; 255 - break; 250 + return -EINVAL; 256 251 } 257 252 258 - if (!mbigen_create_device_domain(&child->dev, num_pins, mgn_chip)) { 259 - ret = -ENOMEM; 260 - break; 261 - } 253 + if (!mbigen_create_device_domain(&child->dev, num_pins, mgn_chip)) 254 + return -ENOMEM; 262 255 } 263 256 264 - if (ret) 265 - of_node_put(np); 266 - 267 - return ret; 257 + return 0; 268 258 } 269 259 270 260 #ifdef CONFIG_ACPI
+1 -2
drivers/irqchip/irq-omap-intc.c
··· 325 325 return ret; 326 326 } 327 327 328 - static asmlinkage void __exception_irq_entry 329 - omap_intc_handle_irq(struct pt_regs *regs) 328 + static void __exception_irq_entry omap_intc_handle_irq(struct pt_regs *regs) 330 329 { 331 330 extern unsigned long irq_err_count; 332 331 u32 irqnr;
+1 -2
drivers/irqchip/irq-sa11x0.c
··· 127 127 128 128 device_initcall(sa1100irq_init_devicefs); 129 129 130 - static asmlinkage void __exception_irq_entry 131 - sa1100_handle_irq(struct pt_regs *regs) 130 + static void __exception_irq_entry sa1100_handle_irq(struct pt_regs *regs) 132 131 { 133 132 uint32_t icip, icmr, mask; 134 133
+1 -1
drivers/irqchip/irq-versatile-fpga.c
··· 128 128 * Keep iterating over all registered FPGA IRQ controllers until there are 129 129 * no pending interrupts. 130 130 */ 131 - static asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs) 131 + static void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs) 132 132 { 133 133 int i, handled; 134 134
+2 -1
include/linux/cpuhotplug.h
··· 144 144 CPUHP_AP_IRQ_ARMADA_XP_STARTING, 145 145 CPUHP_AP_IRQ_BCM2836_STARTING, 146 146 CPUHP_AP_IRQ_MIPS_GIC_STARTING, 147 - CPUHP_AP_IRQ_LOONGARCH_STARTING, 147 + CPUHP_AP_IRQ_EIOINTC_STARTING, 148 + CPUHP_AP_IRQ_AVECINTC_STARTING, 148 149 CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, 149 150 CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, 150 151 CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING,
+3 -3
include/linux/interrupt.h
··· 276 276 #define IRQ_AFFINITY_MAX_SETS 4 277 277 278 278 /** 279 - * struct irq_affinity - Description for automatic irq affinity assignements 279 + * struct irq_affinity - Description for automatic irq affinity assignments 280 280 * @pre_vectors: Don't apply affinity to @pre_vectors at beginning of 281 281 * the MSI(-X) vector space 282 282 * @post_vectors: Don't apply affinity to @post_vectors at end of ··· 594 594 595 595 struct softirq_action 596 596 { 597 - void (*action)(struct softirq_action *); 597 + void (*action)(void); 598 598 }; 599 599 600 600 asmlinkage void do_softirq(void); ··· 609 609 } 610 610 #endif 611 611 612 - extern void open_softirq(int nr, void (*action)(struct softirq_action *)); 612 + extern void open_softirq(int nr, void (*action)(void)); 613 613 extern void softirq_init(void); 614 614 extern void __raise_softirq_irqoff(unsigned int nr); 615 615
-6
include/linux/irq.h
··· 991 991 * @ack: Ack register offset to reg_base 992 992 * @eoi: Eoi register offset to reg_base 993 993 * @type: Type configuration register offset to reg_base 994 - * @polarity: Polarity configuration register offset to reg_base 995 994 */ 996 995 struct irq_chip_regs { 997 996 unsigned long enable; ··· 999 1000 unsigned long ack; 1000 1001 unsigned long eoi; 1001 1002 unsigned long type; 1002 - unsigned long polarity; 1003 1003 }; 1004 1004 1005 1005 /** ··· 1038 1040 * @irq_base: Interrupt base nr for this chip 1039 1041 * @irq_cnt: Number of interrupts handled by this chip 1040 1042 * @mask_cache: Cached mask register shared between all chip types 1041 - * @type_cache: Cached type register 1042 - * @polarity_cache: Cached polarity register 1043 1043 * @wake_enabled: Interrupt can wakeup from suspend 1044 1044 * @wake_active: Interrupt is marked as an wakeup from suspend source 1045 1045 * @num_ct: Number of available irq_chip_type instances (usually 1) ··· 1064 1068 unsigned int irq_base; 1065 1069 unsigned int irq_cnt; 1066 1070 u32 mask_cache; 1067 - u32 type_cache; 1068 - u32 polarity_cache; 1069 1071 u32 wake_enabled; 1070 1072 u32 wake_active; 1071 1073 unsigned int num_ct;
+8
include/linux/irqdomain.h
··· 291 291 * @hwirq_max: Maximum number of interrupts supported by controller 292 292 * @direct_max: Maximum value of direct maps; 293 293 * Use ~0 for no limit; 0 for no direct mapping 294 + * @hwirq_base: The first hardware interrupt number (legacy domains only) 295 + * @virq_base: The first Linux interrupt number for legacy domains to 296 + * immediately associate the interrupts after domain creation 294 297 * @bus_token: Domain bus token 298 + * @name_suffix: Optional name suffix to avoid collisions when multiple 299 + * domains are added using same fwnode 295 300 * @ops: Domain operation callbacks 296 301 * @host_data: Controller private data pointer 297 302 * @dgc_info: Geneneric chip information structure pointer used to ··· 312 307 unsigned int size; 313 308 irq_hw_number_t hwirq_max; 314 309 int direct_max; 310 + unsigned int hwirq_base; 311 + unsigned int virq_base; 315 312 enum irq_domain_bus_token bus_token; 313 + const char *name_suffix; 316 314 const struct irq_domain_ops *ops; 317 315 void *host_data; 318 316 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+1 -1
kernel/irq/chip.c
··· 198 198 199 199 irqd_clr_managed_shutdown(d); 200 200 201 - if (cpumask_any_and(aff, cpu_online_mask) >= nr_cpu_ids) { 201 + if (!cpumask_intersects(aff, cpu_online_mask)) { 202 202 /* 203 203 * Catch code which fiddles with enable_irq() on a managed 204 204 * and potentially shutdown IRQ. Chained interrupt
+2 -2
kernel/irq/cpuhotplug.c
··· 37 37 * has been removed from the online mask already. 38 38 */ 39 39 if (cpumask_any_but(m, cpu) < nr_cpu_ids && 40 - cpumask_any_and(m, cpu_online_mask) >= nr_cpu_ids) { 40 + !cpumask_intersects(m, cpu_online_mask)) { 41 41 /* 42 42 * If this happens then there was a missed IRQ fixup at some 43 43 * point. Warn about it and enforce fixup. ··· 110 110 if (maskchip && chip->irq_mask) 111 111 chip->irq_mask(d); 112 112 113 - if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { 113 + if (!cpumask_intersects(affinity, cpu_online_mask)) { 114 114 /* 115 115 * If the interrupt is managed, then shut it down and leave 116 116 * the affinity untouched.
-1
kernel/irq/irq_sim.c
··· 13 13 14 14 struct irq_sim_work_ctx { 15 15 struct irq_work work; 16 - int irq_base; 17 16 unsigned int irq_count; 18 17 unsigned long *pending; 19 18 struct irq_domain *domain;
+124 -86
kernel/irq/irqdomain.c
··· 128 128 } 129 129 EXPORT_SYMBOL_GPL(irq_domain_free_fwnode); 130 130 131 - static int irq_domain_set_name(struct irq_domain *domain, 132 - const struct fwnode_handle *fwnode, 133 - enum irq_domain_bus_token bus_token) 131 + static int alloc_name(struct irq_domain *domain, char *base, enum irq_domain_bus_token bus_token) 132 + { 133 + if (bus_token == DOMAIN_BUS_ANY) 134 + domain->name = kasprintf(GFP_KERNEL, "%s", base); 135 + else 136 + domain->name = kasprintf(GFP_KERNEL, "%s-%d", base, bus_token); 137 + if (!domain->name) 138 + return -ENOMEM; 139 + 140 + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 141 + return 0; 142 + } 143 + 144 + static int alloc_fwnode_name(struct irq_domain *domain, const struct fwnode_handle *fwnode, 145 + enum irq_domain_bus_token bus_token, const char *suffix) 146 + { 147 + const char *sep = suffix ? "-" : ""; 148 + const char *suf = suffix ? : ""; 149 + char *name; 150 + 151 + if (bus_token == DOMAIN_BUS_ANY) 152 + name = kasprintf(GFP_KERNEL, "%pfw%s%s", fwnode, sep, suf); 153 + else 154 + name = kasprintf(GFP_KERNEL, "%pfw%s%s-%d", fwnode, sep, suf, bus_token); 155 + if (!name) 156 + return -ENOMEM; 157 + 158 + /* 159 + * fwnode paths contain '/', which debugfs is legitimately unhappy 160 + * about. Replace them with ':', which does the trick and is not as 161 + * offensive as '\'... 162 + */ 163 + domain->name = strreplace(name, '/', ':'); 164 + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 165 + return 0; 166 + } 167 + 168 + static int alloc_unknown_name(struct irq_domain *domain, enum irq_domain_bus_token bus_token) 134 169 { 135 170 static atomic_t unknown_domains; 136 - struct irqchip_fwid *fwid; 171 + int id = atomic_inc_return(&unknown_domains); 172 + 173 + if (bus_token == DOMAIN_BUS_ANY) 174 + domain->name = kasprintf(GFP_KERNEL, "unknown-%d", id); 175 + else 176 + domain->name = kasprintf(GFP_KERNEL, "unknown-%d-%d", id, bus_token); 177 + if (!domain->name) 178 + return -ENOMEM; 179 + 180 + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 181 + return 0; 182 + } 183 + 184 + static int irq_domain_set_name(struct irq_domain *domain, const struct irq_domain_info *info) 185 + { 186 + enum irq_domain_bus_token bus_token = info->bus_token; 187 + const struct fwnode_handle *fwnode = info->fwnode; 137 188 138 189 if (is_fwnode_irqchip(fwnode)) { 139 - fwid = container_of(fwnode, struct irqchip_fwid, fwnode); 190 + struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode); 191 + 192 + /* 193 + * The name_suffix is only intended to be used to avoid a name 194 + * collision when multiple domains are created for a single 195 + * device and the name is picked using a real device node. 196 + * (Typical use-case is regmap-IRQ controllers for devices 197 + * providing more than one physical IRQ.) There should be no 198 + * need to use name_suffix with irqchip-fwnode. 199 + */ 200 + if (info->name_suffix) 201 + return -EINVAL; 140 202 141 203 switch (fwid->type) { 142 204 case IRQCHIP_FWNODE_NAMED: 143 205 case IRQCHIP_FWNODE_NAMED_ID: 144 - domain->name = bus_token ? 145 - kasprintf(GFP_KERNEL, "%s-%d", 146 - fwid->name, bus_token) : 147 - kstrdup(fwid->name, GFP_KERNEL); 148 - if (!domain->name) 149 - return -ENOMEM; 150 - domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 151 - break; 206 + return alloc_name(domain, fwid->name, bus_token); 152 207 default: 153 208 domain->name = fwid->name; 154 - if (bus_token) { 155 - domain->name = kasprintf(GFP_KERNEL, "%s-%d", 156 - fwid->name, bus_token); 157 - if (!domain->name) 158 - return -ENOMEM; 159 - domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 160 - } 161 - break; 209 + if (bus_token != DOMAIN_BUS_ANY) 210 + return alloc_name(domain, fwid->name, bus_token); 162 211 } 163 - } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || 164 - is_software_node(fwnode)) { 165 - char *name; 166 212 167 - /* 168 - * fwnode paths contain '/', which debugfs is legitimately 169 - * unhappy about. Replace them with ':', which does 170 - * the trick and is not as offensive as '\'... 171 - */ 172 - name = bus_token ? 173 - kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) : 174 - kasprintf(GFP_KERNEL, "%pfw", fwnode); 175 - if (!name) 176 - return -ENOMEM; 177 - 178 - domain->name = strreplace(name, '/', ':'); 179 - domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 213 + } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || is_software_node(fwnode)) { 214 + return alloc_fwnode_name(domain, fwnode, bus_token, info->name_suffix); 180 215 } 181 216 182 - if (!domain->name) { 183 - if (fwnode) 184 - pr_err("Invalid fwnode type for irqdomain\n"); 185 - domain->name = bus_token ? 186 - kasprintf(GFP_KERNEL, "unknown-%d-%d", 187 - atomic_inc_return(&unknown_domains), 188 - bus_token) : 189 - kasprintf(GFP_KERNEL, "unknown-%d", 190 - atomic_inc_return(&unknown_domains)); 191 - if (!domain->name) 192 - return -ENOMEM; 193 - domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 194 - } 217 + if (domain->name) 218 + return 0; 195 219 196 - return 0; 220 + if (fwnode) 221 + pr_err("Invalid fwnode type for irqdomain\n"); 222 + return alloc_unknown_name(domain, bus_token); 197 223 } 198 224 199 225 static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info) ··· 237 211 if (!domain) 238 212 return ERR_PTR(-ENOMEM); 239 213 240 - err = irq_domain_set_name(domain, info->fwnode, info->bus_token); 214 + err = irq_domain_set_name(domain, info); 241 215 if (err) { 242 216 kfree(domain); 243 217 return ERR_PTR(err); ··· 293 267 kfree(domain); 294 268 } 295 269 296 - /** 297 - * irq_domain_instantiate() - Instantiate a new irq domain data structure 298 - * @info: Domain information pointer pointing to the information for this domain 299 - * 300 - * Return: A pointer to the instantiated irq domain or an ERR_PTR value. 301 - */ 302 - struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info) 270 + static void irq_domain_instantiate_descs(const struct irq_domain_info *info) 271 + { 272 + if (!IS_ENABLED(CONFIG_SPARSE_IRQ)) 273 + return; 274 + 275 + if (irq_alloc_descs(info->virq_base, info->virq_base, info->size, 276 + of_node_to_nid(to_of_node(info->fwnode))) < 0) { 277 + pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 278 + info->virq_base); 279 + } 280 + } 281 + 282 + static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info *info, 283 + bool cond_alloc_descs, bool force_associate) 303 284 { 304 285 struct irq_domain *domain; 305 286 int err; ··· 339 306 340 307 __irq_domain_publish(domain); 341 308 309 + if (cond_alloc_descs && info->virq_base > 0) 310 + irq_domain_instantiate_descs(info); 311 + 312 + /* 313 + * Legacy interrupt domains have a fixed Linux interrupt number 314 + * associated. Other interrupt domains can request association by 315 + * providing a Linux interrupt number > 0. 316 + */ 317 + if (force_associate || info->virq_base > 0) { 318 + irq_domain_associate_many(domain, info->virq_base, info->hwirq_base, 319 + info->size - info->hwirq_base); 320 + } 321 + 342 322 return domain; 343 323 344 324 err_domain_gc_remove: ··· 360 314 err_domain_free: 361 315 irq_domain_free(domain); 362 316 return ERR_PTR(err); 317 + } 318 + 319 + /** 320 + * irq_domain_instantiate() - Instantiate a new irq domain data structure 321 + * @info: Domain information pointer pointing to the information for this domain 322 + * 323 + * Return: A pointer to the instantiated irq domain or an ERR_PTR value. 324 + */ 325 + struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info) 326 + { 327 + return __irq_domain_instantiate(info, false, false); 363 328 } 364 329 EXPORT_SYMBOL_GPL(irq_domain_instantiate); 365 330 ··· 470 413 .fwnode = fwnode, 471 414 .size = size, 472 415 .hwirq_max = size, 416 + .virq_base = first_irq, 473 417 .ops = ops, 474 418 .host_data = host_data, 475 419 }; 476 - struct irq_domain *domain; 420 + struct irq_domain *domain = __irq_domain_instantiate(&info, true, false); 477 421 478 - domain = irq_domain_instantiate(&info); 479 - if (IS_ERR(domain)) 480 - return NULL; 481 - 482 - if (first_irq > 0) { 483 - if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { 484 - /* attempt to allocated irq_descs */ 485 - int rc = irq_alloc_descs(first_irq, first_irq, size, 486 - of_node_to_nid(to_of_node(fwnode))); 487 - if (rc < 0) 488 - pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 489 - first_irq); 490 - } 491 - irq_domain_associate_many(domain, first_irq, 0, size); 492 - } 493 - 494 - return domain; 422 + return IS_ERR(domain) ? NULL : domain; 495 423 } 496 424 EXPORT_SYMBOL_GPL(irq_domain_create_simple); 497 425 ··· 518 476 .fwnode = fwnode, 519 477 .size = first_hwirq + size, 520 478 .hwirq_max = first_hwirq + size, 479 + .hwirq_base = first_hwirq, 480 + .virq_base = first_irq, 521 481 .ops = ops, 522 482 .host_data = host_data, 523 483 }; 524 - struct irq_domain *domain; 484 + struct irq_domain *domain = __irq_domain_instantiate(&info, false, true); 525 485 526 - domain = irq_domain_instantiate(&info); 527 - if (IS_ERR(domain)) 528 - return NULL; 529 - 530 - irq_domain_associate_many(domain, first_irq, first_hwirq, size); 531 - 532 - return domain; 486 + return IS_ERR(domain) ? NULL : domain; 533 487 } 534 488 EXPORT_SYMBOL_GPL(irq_domain_create_legacy); 535 489 ··· 1403 1365 tail = NULL; 1404 1366 1405 1367 /* The first entry must have a valid irqchip */ 1406 - if (!irq_data->chip || IS_ERR(irq_data->chip)) 1368 + if (IS_ERR_OR_NULL(irq_data->chip)) 1407 1369 return -EINVAL; 1408 1370 1409 1371 /*
+9 -12
kernel/irq/manage.c
··· 218 218 static inline void irq_validate_effective_affinity(struct irq_data *data) { } 219 219 #endif 220 220 221 + static DEFINE_PER_CPU(struct cpumask, __tmp_mask); 222 + 221 223 int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, 222 224 bool force) 223 225 { 226 + struct cpumask *tmp_mask = this_cpu_ptr(&__tmp_mask); 224 227 struct irq_desc *desc = irq_data_to_desc(data); 225 228 struct irq_chip *chip = irq_data_get_irq_chip(data); 226 229 const struct cpumask *prog_mask; 227 230 int ret; 228 231 229 - static DEFINE_RAW_SPINLOCK(tmp_mask_lock); 230 - static struct cpumask tmp_mask; 231 - 232 232 if (!chip || !chip->irq_set_affinity) 233 233 return -EINVAL; 234 234 235 - raw_spin_lock(&tmp_mask_lock); 236 235 /* 237 236 * If this is a managed interrupt and housekeeping is enabled on 238 237 * it check whether the requested affinity mask intersects with ··· 257 258 258 259 hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ); 259 260 260 - cpumask_and(&tmp_mask, mask, hk_mask); 261 - if (!cpumask_intersects(&tmp_mask, cpu_online_mask)) 261 + cpumask_and(tmp_mask, mask, hk_mask); 262 + if (!cpumask_intersects(tmp_mask, cpu_online_mask)) 262 263 prog_mask = mask; 263 264 else 264 - prog_mask = &tmp_mask; 265 + prog_mask = tmp_mask; 265 266 } else { 266 267 prog_mask = mask; 267 268 } ··· 271 272 * unless we are being asked to force the affinity (in which 272 273 * case we do as we are told). 273 274 */ 274 - cpumask_and(&tmp_mask, prog_mask, cpu_online_mask); 275 - if (!force && !cpumask_empty(&tmp_mask)) 276 - ret = chip->irq_set_affinity(data, &tmp_mask, force); 275 + cpumask_and(tmp_mask, prog_mask, cpu_online_mask); 276 + if (!force && !cpumask_empty(tmp_mask)) 277 + ret = chip->irq_set_affinity(data, tmp_mask, force); 277 278 else if (force) 278 279 ret = chip->irq_set_affinity(data, mask, force); 279 280 else 280 281 ret = -EINVAL; 281 - 282 - raw_spin_unlock(&tmp_mask_lock); 283 282 284 283 switch (ret) { 285 284 case IRQ_SET_MASK_OK:
+2 -2
kernel/irq/migration.c
··· 26 26 * The outgoing CPU might be the last online target in a pending 27 27 * interrupt move. If that's the case clear the pending move bit. 28 28 */ 29 - if (cpumask_any_and(desc->pending_mask, cpu_online_mask) >= nr_cpu_ids) { 29 + if (!cpumask_intersects(desc->pending_mask, cpu_online_mask)) { 30 30 irqd_clr_move_pending(data); 31 31 return false; 32 32 } ··· 74 74 * For correct operation this depends on the caller 75 75 * masking the irqs. 76 76 */ 77 - if (cpumask_any_and(desc->pending_mask, cpu_online_mask) < nr_cpu_ids) { 77 + if (cpumask_intersects(desc->pending_mask, cpu_online_mask)) { 78 78 int ret; 79 79 80 80 ret = irq_do_set_affinity(data, desc->pending_mask, false);
+1 -1
kernel/irq/msi.c
··· 82 82 desc->dev = dev; 83 83 desc->nvec_used = nvec; 84 84 if (affinity) { 85 - desc->affinity = kmemdup(affinity, nvec * sizeof(*desc->affinity), GFP_KERNEL); 85 + desc->affinity = kmemdup_array(affinity, nvec, sizeof(*desc->affinity), GFP_KERNEL); 86 86 if (!desc->affinity) { 87 87 kfree(desc); 88 88 return NULL;
+10 -7
kernel/irq/proc.c
··· 52 52 case AFFINITY: 53 53 case AFFINITY_LIST: 54 54 mask = desc->irq_common_data.affinity; 55 - #ifdef CONFIG_GENERIC_PENDING_IRQ 56 - if (irqd_is_setaffinity_pending(&desc->irq_data)) 57 - mask = desc->pending_mask; 58 - #endif 55 + if (irq_move_pending(&desc->irq_data)) 56 + mask = irq_desc_get_pending_mask(desc); 59 57 break; 60 58 case EFFECTIVE: 61 59 case EFFECTIVE_LIST: ··· 140 142 int err; 141 143 142 144 if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) 143 - return -EIO; 145 + return -EPERM; 144 146 145 147 if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) 146 148 return -ENOMEM; ··· 360 362 goto out_unlock; 361 363 362 364 #ifdef CONFIG_SMP 365 + umode_t umode = S_IRUGO; 366 + 367 + if (irq_can_set_affinity_usr(desc->irq_data.irq)) 368 + umode |= S_IWUSR; 369 + 363 370 /* create /proc/irq/<irq>/smp_affinity */ 364 - proc_create_data("smp_affinity", 0644, desc->dir, 371 + proc_create_data("smp_affinity", umode, desc->dir, 365 372 &irq_affinity_proc_ops, irqp); 366 373 367 374 /* create /proc/irq/<irq>/affinity_hint */ ··· 374 371 irq_affinity_hint_proc_show, irqp); 375 372 376 373 /* create /proc/irq/<irq>/smp_affinity_list */ 377 - proc_create_data("smp_affinity_list", 0644, desc->dir, 374 + proc_create_data("smp_affinity_list", umode, desc->dir, 378 375 &irq_affinity_list_proc_ops, irqp); 379 376 380 377 proc_create_single_data("node", 0444, desc->dir, irq_node_proc_show,
+1 -1
kernel/rcu/tiny.c
··· 105 105 } 106 106 107 107 /* Invoke the RCU callbacks whose grace period has elapsed. */ 108 - static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) 108 + static __latent_entropy void rcu_process_callbacks(void) 109 109 { 110 110 struct rcu_head *next, *list; 111 111 unsigned long flags;
+1 -1
kernel/rcu/tree.c
··· 2855 2855 queue_work_on(rdp->cpu, rcu_gp_wq, &rdp->strict_work); 2856 2856 } 2857 2857 2858 - static void rcu_core_si(struct softirq_action *h) 2858 + static void rcu_core_si(void) 2859 2859 { 2860 2860 rcu_core(); 2861 2861 }
+1 -1
kernel/sched/fair.c
··· 12483 12483 * - indirectly from a remote scheduler_tick() for NOHZ idle balancing 12484 12484 * through the SMP cross-call nohz_csd_func() 12485 12485 */ 12486 - static __latent_entropy void sched_balance_softirq(struct softirq_action *h) 12486 + static __latent_entropy void sched_balance_softirq(void) 12487 12487 { 12488 12488 struct rq *this_rq = this_rq(); 12489 12489 enum cpu_idle_type idle = this_rq->idle_balance;
+7 -8
kernel/softirq.c
··· 551 551 kstat_incr_softirqs_this_cpu(vec_nr); 552 552 553 553 trace_softirq_entry(vec_nr); 554 - h->action(h); 554 + h->action(); 555 555 trace_softirq_exit(vec_nr); 556 556 if (unlikely(prev_count != preempt_count())) { 557 557 pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", ··· 700 700 or_softirq_pending(1UL << nr); 701 701 } 702 702 703 - void open_softirq(int nr, void (*action)(struct softirq_action *)) 703 + void open_softirq(int nr, void (*action)(void)) 704 704 { 705 705 softirq_vec[nr].action = action; 706 706 } ··· 760 760 return false; 761 761 } 762 762 763 - static void tasklet_action_common(struct softirq_action *a, 764 - struct tasklet_head *tl_head, 763 + static void tasklet_action_common(struct tasklet_head *tl_head, 765 764 unsigned int softirq_nr) 766 765 { 767 766 struct tasklet_struct *list; ··· 804 805 } 805 806 } 806 807 807 - static __latent_entropy void tasklet_action(struct softirq_action *a) 808 + static __latent_entropy void tasklet_action(void) 808 809 { 809 810 workqueue_softirq_action(false); 810 - tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); 811 + tasklet_action_common(this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); 811 812 } 812 813 813 - static __latent_entropy void tasklet_hi_action(struct softirq_action *a) 814 + static __latent_entropy void tasklet_hi_action(void) 814 815 { 815 816 workqueue_softirq_action(true); 816 - tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); 817 + tasklet_action_common(this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); 817 818 } 818 819 819 820 void tasklet_setup(struct tasklet_struct *t,
+1 -1
kernel/time/hrtimer.c
··· 1757 1757 } 1758 1758 } 1759 1759 1760 - static __latent_entropy void hrtimer_run_softirq(struct softirq_action *h) 1760 + static __latent_entropy void hrtimer_run_softirq(void) 1761 1761 { 1762 1762 struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); 1763 1763 unsigned long flags;
+1 -1
kernel/time/timer.c
··· 2440 2440 /* 2441 2441 * This function runs timers and the timer-tq in bottom half context. 2442 2442 */ 2443 - static __latent_entropy void run_timer_softirq(struct softirq_action *h) 2443 + static __latent_entropy void run_timer_softirq(void) 2444 2444 { 2445 2445 run_timer_base(BASE_LOCAL); 2446 2446 if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) {
+1 -1
lib/irq_poll.c
··· 75 75 } 76 76 EXPORT_SYMBOL(irq_poll_complete); 77 77 78 - static void __latent_entropy irq_poll_softirq(struct softirq_action *h) 78 + static void __latent_entropy irq_poll_softirq(void) 79 79 { 80 80 struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); 81 81 int rearm = 0, budget = irq_poll_budget;
+2 -2
net/core/dev.c
··· 5248 5248 } 5249 5249 EXPORT_SYMBOL(netif_rx); 5250 5250 5251 - static __latent_entropy void net_tx_action(struct softirq_action *h) 5251 + static __latent_entropy void net_tx_action(void) 5252 5252 { 5253 5253 struct softnet_data *sd = this_cpu_ptr(&softnet_data); 5254 5254 ··· 6921 6921 return 0; 6922 6922 } 6923 6923 6924 - static __latent_entropy void net_rx_action(struct softirq_action *h) 6924 + static __latent_entropy void net_rx_action(void) 6925 6925 { 6926 6926 struct softnet_data *sd = this_cpu_ptr(&softnet_data); 6927 6927 unsigned long time_limit = jiffies +