irqflags.h (2933B)
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Copyright (C) 2012 ARM Ltd. 4 */ 5#ifndef __ASM_IRQFLAGS_H 6#define __ASM_IRQFLAGS_H 7 8#include <asm/alternative.h> 9#include <asm/barrier.h> 10#include <asm/ptrace.h> 11#include <asm/sysreg.h> 12 13/* 14 * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and 15 * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif' 16 * order: 17 * Masking debug exceptions causes all other exceptions to be masked too/ 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. 22 */ 23 24/* 25 * CPU interrupt mask handling. 26 */ 27static inline void arch_local_irq_enable(void) 28{ 29 if (system_has_prio_mask_debugging()) { 30 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1); 31 32 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF); 33 } 34 35 asm volatile(ALTERNATIVE( 36 "msr daifclr, #3 // arch_local_irq_enable", 37 __msr_s(SYS_ICC_PMR_EL1, "%0"), 38 ARM64_HAS_IRQ_PRIO_MASKING) 39 : 40 : "r" ((unsigned long) GIC_PRIO_IRQON) 41 : "memory"); 42 43 pmr_sync(); 44} 45 46static inline void arch_local_irq_disable(void) 47{ 48 if (system_has_prio_mask_debugging()) { 49 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1); 50 51 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF); 52 } 53 54 asm volatile(ALTERNATIVE( 55 "msr daifset, #3 // arch_local_irq_disable", 56 __msr_s(SYS_ICC_PMR_EL1, "%0"), 57 ARM64_HAS_IRQ_PRIO_MASKING) 58 : 59 : "r" ((unsigned long) GIC_PRIO_IRQOFF) 60 : "memory"); 61} 62 63/* 64 * Save the current interrupt enable state. 65 */ 66static inline unsigned long arch_local_save_flags(void) 67{ 68 unsigned long flags; 69 70 asm volatile(ALTERNATIVE( 71 "mrs %0, daif", 72 __mrs_s("%0", SYS_ICC_PMR_EL1), 73 ARM64_HAS_IRQ_PRIO_MASKING) 74 : "=&r" (flags) 75 : 76 : "memory"); 77 78 return flags; 79} 80 81static inline int arch_irqs_disabled_flags(unsigned long flags) 82{ 83 int res; 84 85 asm volatile(ALTERNATIVE( 86 "and %w0, %w1, #" __stringify(PSR_I_BIT), 87 "eor %w0, %w1, #" __stringify(GIC_PRIO_IRQON), 88 ARM64_HAS_IRQ_PRIO_MASKING) 89 : "=&r" (res) 90 : "r" ((int) flags) 91 : "memory"); 92 93 return res; 94} 95 96static inline int arch_irqs_disabled(void) 97{ 98 return arch_irqs_disabled_flags(arch_local_save_flags()); 99} 100 101static inline unsigned long arch_local_irq_save(void) 102{ 103 unsigned long flags; 104 105 flags = arch_local_save_flags(); 106 107 /* 108 * There are too many states with IRQs disabled, just keep the current 109 * state if interrupts are already disabled/masked. 110 */ 111 if (!arch_irqs_disabled_flags(flags)) 112 arch_local_irq_disable(); 113 114 return flags; 115} 116 117/* 118 * restore saved IRQ state 119 */ 120static inline void arch_local_irq_restore(unsigned long flags) 121{ 122 asm volatile(ALTERNATIVE( 123 "msr daif, %0", 124 __msr_s(SYS_ICC_PMR_EL1, "%0"), 125 ARM64_HAS_IRQ_PRIO_MASKING) 126 : 127 : "r" (flags) 128 : "memory"); 129 130 pmr_sync(); 131} 132 133#endif /* __ASM_IRQFLAGS_H */