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

Merge remote-tracking branch 'arm64/for-next/fiq'

The FIQ support series, already merged into arm64, is a dependency
of the M1 bring-up series and was split off after the first few
versions.

Signed-off-by: Hector Martin <marcan@marcan.st>

+125 -70
-1
arch/arm64/Kconfig
··· 110 110 select GENERIC_EARLY_IOREMAP 111 111 select GENERIC_IDLE_POLL_SETUP 112 112 select GENERIC_IRQ_IPI 113 - select GENERIC_IRQ_MULTI_HANDLER 114 113 select GENERIC_IRQ_PROBE 115 114 select GENERIC_IRQ_SHOW 116 115 select GENERIC_IRQ_SHOW_LEVEL
+1 -1
arch/arm64/include/asm/arch_gicv3.h
··· 173 173 174 174 static inline void gic_arch_enable_irqs(void) 175 175 { 176 - asm volatile ("msr daifclr, #2" : : : "memory"); 176 + asm volatile ("msr daifclr, #3" : : : "memory"); 177 177 } 178 178 179 179 #endif /* __ASSEMBLY__ */
+4 -4
arch/arm64/include/asm/assembler.h
··· 40 40 msr daif, \flags 41 41 .endm 42 42 43 - /* IRQ is the lowest priority flag, unconditionally unmask the rest. */ 44 - .macro enable_da_f 45 - msr daifclr, #(8 | 4 | 1) 43 + /* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */ 44 + .macro enable_da 45 + msr daifclr, #(8 | 4) 46 46 .endm 47 47 48 48 /* ··· 50 50 */ 51 51 .macro save_and_disable_irq, flags 52 52 mrs \flags, daif 53 - msr daifset, #2 53 + msr daifset, #3 54 54 .endm 55 55 56 56 .macro restore_irq, flags
+5 -5
arch/arm64/include/asm/daifflags.h
··· 13 13 #include <asm/ptrace.h> 14 14 15 15 #define DAIF_PROCCTX 0 16 - #define DAIF_PROCCTX_NOIRQ PSR_I_BIT 17 - #define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) 16 + #define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT) 17 + #define DAIF_ERRCTX (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) 18 18 #define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) 19 19 20 20 ··· 47 47 if (system_uses_irq_prio_masking()) { 48 48 /* If IRQs are masked with PMR, reflect it in the flags */ 49 49 if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) 50 - flags |= PSR_I_BIT; 50 + flags |= PSR_I_BIT | PSR_F_BIT; 51 51 } 52 52 53 53 return flags; ··· 69 69 bool irq_disabled = flags & PSR_I_BIT; 70 70 71 71 WARN_ON(system_has_prio_mask_debugging() && 72 - !(read_sysreg(daif) & PSR_I_BIT)); 72 + (read_sysreg(daif) & (PSR_I_BIT | PSR_F_BIT)) != (PSR_I_BIT | PSR_F_BIT)); 73 73 74 74 if (!irq_disabled) { 75 75 trace_hardirqs_on(); ··· 86 86 * If interrupts are disabled but we can take 87 87 * asynchronous errors, we can take NMIs 88 88 */ 89 - flags &= ~PSR_I_BIT; 89 + flags &= ~(PSR_I_BIT | PSR_F_BIT); 90 90 pmr = GIC_PRIO_IRQOFF; 91 91 } else { 92 92 pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET;
+4
arch/arm64/include/asm/irq.h
··· 8 8 9 9 struct pt_regs; 10 10 11 + int set_handle_irq(void (*handle_irq)(struct pt_regs *)); 12 + #define set_handle_irq set_handle_irq 13 + int set_handle_fiq(void (*handle_fiq)(struct pt_regs *)); 14 + 11 15 static inline int nr_legacy_irqs(void) 12 16 { 13 17 return 0;
+7 -9
arch/arm64/include/asm/irqflags.h
··· 12 12 13 13 /* 14 14 * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and 15 - * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'dai' 15 + * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif' 16 16 * order: 17 17 * Masking debug exceptions causes all other exceptions to be masked too/ 18 - * Masking SError masks irq, but not debug exceptions. Masking irqs has no 19 - * side effects for other flags. Keeping to this order makes it easier for 20 - * entry.S to know which exceptions should be unmasked. 21 - * 22 - * FIQ is never expected, but we mask it when we disable debug exceptions, and 23 - * unmask it at all other times. 18 + * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are 19 + * always masked and unmasked together, and have no side effects for other 20 + * flags. Keeping to this order makes it easier for entry.S to know which 21 + * exceptions should be unmasked. 24 22 */ 25 23 26 24 /* ··· 33 35 } 34 36 35 37 asm volatile(ALTERNATIVE( 36 - "msr daifclr, #2 // arch_local_irq_enable", 38 + "msr daifclr, #3 // arch_local_irq_enable", 37 39 __msr_s(SYS_ICC_PMR_EL1, "%0"), 38 40 ARM64_HAS_IRQ_PRIO_MASKING) 39 41 : ··· 52 54 } 53 55 54 56 asm volatile(ALTERNATIVE( 55 - "msr daifset, #2 // arch_local_irq_disable", 57 + "msr daifset, #3 // arch_local_irq_disable", 56 58 __msr_s(SYS_ICC_PMR_EL1, "%0"), 57 59 ARM64_HAS_IRQ_PRIO_MASKING) 58 60 :
+67 -47
arch/arm64/kernel/entry.S
··· 491 491 /* 492 492 * Interrupt handling. 493 493 */ 494 - .macro irq_handler 495 - ldr_l x1, handle_arch_irq 494 + .macro irq_handler, handler:req 495 + ldr_l x1, \handler 496 496 mov x0, sp 497 497 irq_stack_entry 498 498 blr x1 ··· 531 531 #endif 532 532 .endm 533 533 534 + .macro el1_interrupt_handler, handler:req 535 + gic_prio_irq_setup pmr=x20, tmp=x1 536 + enable_da 537 + 538 + mov x0, sp 539 + bl enter_el1_irq_or_nmi 540 + 541 + irq_handler \handler 542 + 543 + #ifdef CONFIG_PREEMPTION 544 + ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count 545 + alternative_if ARM64_HAS_IRQ_PRIO_MASKING 546 + /* 547 + * DA were cleared at start of handling, and IF are cleared by 548 + * the GIC irqchip driver using gic_arch_enable_irqs() for 549 + * normal IRQs. If anything is set, it means we come back from 550 + * an NMI instead of a normal IRQ, so skip preemption 551 + */ 552 + mrs x0, daif 553 + orr x24, x24, x0 554 + alternative_else_nop_endif 555 + cbnz x24, 1f // preempt count != 0 || NMI return path 556 + bl arm64_preempt_schedule_irq // irq en/disable is done inside 557 + 1: 558 + #endif 559 + 560 + mov x0, sp 561 + bl exit_el1_irq_or_nmi 562 + .endm 563 + 564 + .macro el0_interrupt_handler, handler:req 565 + gic_prio_irq_setup pmr=x20, tmp=x0 566 + user_exit_irqoff 567 + enable_da 568 + 569 + tbz x22, #55, 1f 570 + bl do_el0_irq_bp_hardening 571 + 1: 572 + irq_handler \handler 573 + .endm 574 + 534 575 .text 535 576 536 577 /* ··· 588 547 589 548 kernel_ventry 1, sync // Synchronous EL1h 590 549 kernel_ventry 1, irq // IRQ EL1h 591 - kernel_ventry 1, fiq_invalid // FIQ EL1h 550 + kernel_ventry 1, fiq // FIQ EL1h 592 551 kernel_ventry 1, error // Error EL1h 593 552 594 553 kernel_ventry 0, sync // Synchronous 64-bit EL0 595 554 kernel_ventry 0, irq // IRQ 64-bit EL0 596 - kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 555 + kernel_ventry 0, fiq // FIQ 64-bit EL0 597 556 kernel_ventry 0, error // Error 64-bit EL0 598 557 599 558 #ifdef CONFIG_COMPAT 600 559 kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 601 560 kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 602 - kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 561 + kernel_ventry 0, fiq_compat, 32 // FIQ 32-bit EL0 603 562 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0 604 563 #else 605 564 kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 ··· 665 624 inv_entry 0, BAD_ERROR 666 625 SYM_CODE_END(el0_error_invalid) 667 626 668 - #ifdef CONFIG_COMPAT 669 - SYM_CODE_START_LOCAL(el0_fiq_invalid_compat) 670 - inv_entry 0, BAD_FIQ, 32 671 - SYM_CODE_END(el0_fiq_invalid_compat) 672 - #endif 673 - 674 627 SYM_CODE_START_LOCAL(el1_sync_invalid) 675 628 inv_entry 1, BAD_SYNC 676 629 SYM_CODE_END(el1_sync_invalid) ··· 695 660 .align 6 696 661 SYM_CODE_START_LOCAL_NOALIGN(el1_irq) 697 662 kernel_entry 1 698 - gic_prio_irq_setup pmr=x20, tmp=x1 699 - enable_da_f 700 - 701 - mov x0, sp 702 - bl enter_el1_irq_or_nmi 703 - 704 - irq_handler 705 - 706 - #ifdef CONFIG_PREEMPTION 707 - ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count 708 - alternative_if ARM64_HAS_IRQ_PRIO_MASKING 709 - /* 710 - * DA_F were cleared at start of handling. If anything is set in DAIF, 711 - * we come back from an NMI, so skip preemption 712 - */ 713 - mrs x0, daif 714 - orr x24, x24, x0 715 - alternative_else_nop_endif 716 - cbnz x24, 1f // preempt count != 0 || NMI return path 717 - bl arm64_preempt_schedule_irq // irq en/disable is done inside 718 - 1: 719 - #endif 720 - 721 - mov x0, sp 722 - bl exit_el1_irq_or_nmi 723 - 663 + el1_interrupt_handler handle_arch_irq 724 664 kernel_exit 1 725 665 SYM_CODE_END(el1_irq) 666 + 667 + SYM_CODE_START_LOCAL_NOALIGN(el1_fiq) 668 + kernel_entry 1 669 + el1_interrupt_handler handle_arch_fiq 670 + kernel_exit 1 671 + SYM_CODE_END(el1_fiq) 726 672 727 673 /* 728 674 * EL0 mode handlers. ··· 731 715 b el0_irq_naked 732 716 SYM_CODE_END(el0_irq_compat) 733 717 718 + SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat) 719 + kernel_entry 0, 32 720 + b el0_fiq_naked 721 + SYM_CODE_END(el0_fiq_compat) 722 + 734 723 SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat) 735 724 kernel_entry 0, 32 736 725 b el0_error_naked ··· 746 725 SYM_CODE_START_LOCAL_NOALIGN(el0_irq) 747 726 kernel_entry 0 748 727 el0_irq_naked: 749 - gic_prio_irq_setup pmr=x20, tmp=x0 750 - user_exit_irqoff 751 - enable_da_f 752 - 753 - tbz x22, #55, 1f 754 - bl do_el0_irq_bp_hardening 755 - 1: 756 - irq_handler 757 - 728 + el0_interrupt_handler handle_arch_irq 758 729 b ret_to_user 759 730 SYM_CODE_END(el0_irq) 731 + 732 + SYM_CODE_START_LOCAL_NOALIGN(el0_fiq) 733 + kernel_entry 0 734 + el0_fiq_naked: 735 + el0_interrupt_handler handle_arch_fiq 736 + b ret_to_user 737 + SYM_CODE_END(el0_fiq) 760 738 761 739 SYM_CODE_START_LOCAL(el1_error) 762 740 kernel_entry 1 ··· 777 757 mov x0, sp 778 758 mov x1, x25 779 759 bl do_serror 780 - enable_da_f 760 + enable_da 781 761 b ret_to_user 782 762 SYM_CODE_END(el0_error) 783 763
+33 -2
arch/arm64/kernel/irq.c
··· 71 71 } 72 72 #endif 73 73 74 + static void default_handle_irq(struct pt_regs *regs) 75 + { 76 + panic("IRQ taken without a root IRQ handler\n"); 77 + } 78 + 79 + static void default_handle_fiq(struct pt_regs *regs) 80 + { 81 + panic("FIQ taken without a root FIQ handler\n"); 82 + } 83 + 84 + void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq; 85 + void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq; 86 + 87 + int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) 88 + { 89 + if (handle_arch_irq != default_handle_irq) 90 + return -EBUSY; 91 + 92 + handle_arch_irq = handle_irq; 93 + pr_info("Root IRQ handler: %ps\n", handle_irq); 94 + return 0; 95 + } 96 + 97 + int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *)) 98 + { 99 + if (handle_arch_fiq != default_handle_fiq) 100 + return -EBUSY; 101 + 102 + handle_arch_fiq = handle_fiq; 103 + pr_info("Root FIQ handler: %ps\n", handle_fiq); 104 + return 0; 105 + } 106 + 74 107 void __init init_IRQ(void) 75 108 { 76 109 init_irq_stacks(); 77 110 init_irq_scs(); 78 111 irqchip_init(); 79 - if (!handle_arch_irq) 80 - panic("No interrupt controller found."); 81 112 82 113 if (system_uses_irq_prio_masking()) { 83 114 /*
+1 -1
arch/arm64/kernel/process.c
··· 84 84 unsigned long daif_bits; 85 85 86 86 daif_bits = read_sysreg(daif); 87 - write_sysreg(daif_bits | PSR_I_BIT, daif); 87 + write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif); 88 88 89 89 /* 90 90 * Unmask PMR before going idle to make sure interrupts can
+1
arch/arm64/kernel/smp.c
··· 188 188 cpuflags = read_sysreg(daif); 189 189 190 190 WARN_ON(!(cpuflags & PSR_I_BIT)); 191 + WARN_ON(!(cpuflags & PSR_F_BIT)); 191 192 192 193 gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); 193 194 }
+2
include/linux/irq.h
··· 1258 1258 */ 1259 1259 extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init; 1260 1260 #else 1261 + #ifndef set_handle_irq 1261 1262 #define set_handle_irq(handle_irq) \ 1262 1263 do { \ 1263 1264 (void)handle_irq; \ 1264 1265 WARN_ON(1); \ 1265 1266 } while (0) 1267 + #endif 1266 1268 #endif 1267 1269 1268 1270 #endif /* _LINUX_IRQ_H */