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/barrier.h> 9 #include <asm/ptrace.h> 10 #include <asm/sysreg.h> 11 12 /* 13 * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and 14 * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif' 15 * order: 16 * Masking debug exceptions causes all other exceptions to be masked too/ 17 * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are 18 * always masked and unmasked together, and have no side effects for other 19 * flags. Keeping to this order makes it easier for entry.S to know which 20 * exceptions should be unmasked. 21 */ 22 23 static __always_inline void __daif_local_irq_enable(void) 24 { 25 barrier(); 26 asm volatile("msr daifclr, #3"); 27 barrier(); 28 } 29 30 static __always_inline void __pmr_local_irq_enable(void) 31 { 32 if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) { 33 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1); 34 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF); 35 } 36 37 barrier(); 38 write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1); 39 pmr_sync(); 40 barrier(); 41 } 42 43 static inline void arch_local_irq_enable(void) 44 { 45 if (system_uses_irq_prio_masking()) { 46 __pmr_local_irq_enable(); 47 } else { 48 __daif_local_irq_enable(); 49 } 50 } 51 52 static __always_inline void __daif_local_irq_disable(void) 53 { 54 barrier(); 55 asm volatile("msr daifset, #3"); 56 barrier(); 57 } 58 59 static __always_inline void __pmr_local_irq_disable(void) 60 { 61 if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) { 62 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1); 63 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF); 64 } 65 66 barrier(); 67 write_sysreg_s(GIC_PRIO_IRQOFF, SYS_ICC_PMR_EL1); 68 barrier(); 69 } 70 71 static inline void arch_local_irq_disable(void) 72 { 73 if (system_uses_irq_prio_masking()) { 74 __pmr_local_irq_disable(); 75 } else { 76 __daif_local_irq_disable(); 77 } 78 } 79 80 static __always_inline unsigned long __daif_local_save_flags(void) 81 { 82 return read_sysreg(daif); 83 } 84 85 static __always_inline unsigned long __pmr_local_save_flags(void) 86 { 87 return read_sysreg_s(SYS_ICC_PMR_EL1); 88 } 89 90 /* 91 * Save the current interrupt enable state. 92 */ 93 static inline unsigned long arch_local_save_flags(void) 94 { 95 if (system_uses_irq_prio_masking()) { 96 return __pmr_local_save_flags(); 97 } else { 98 return __daif_local_save_flags(); 99 } 100 } 101 102 static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags) 103 { 104 return flags & PSR_I_BIT; 105 } 106 107 static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags) 108 { 109 return flags != GIC_PRIO_IRQON; 110 } 111 112 static inline bool arch_irqs_disabled_flags(unsigned long flags) 113 { 114 if (system_uses_irq_prio_masking()) { 115 return __pmr_irqs_disabled_flags(flags); 116 } else { 117 return __daif_irqs_disabled_flags(flags); 118 } 119 } 120 121 static __always_inline bool __daif_irqs_disabled(void) 122 { 123 return __daif_irqs_disabled_flags(__daif_local_save_flags()); 124 } 125 126 static __always_inline bool __pmr_irqs_disabled(void) 127 { 128 return __pmr_irqs_disabled_flags(__pmr_local_save_flags()); 129 } 130 131 static inline bool arch_irqs_disabled(void) 132 { 133 if (system_uses_irq_prio_masking()) { 134 return __pmr_irqs_disabled(); 135 } else { 136 return __daif_irqs_disabled(); 137 } 138 } 139 140 static __always_inline unsigned long __daif_local_irq_save(void) 141 { 142 unsigned long flags = __daif_local_save_flags(); 143 144 __daif_local_irq_disable(); 145 146 return flags; 147 } 148 149 static __always_inline unsigned long __pmr_local_irq_save(void) 150 { 151 unsigned long flags = __pmr_local_save_flags(); 152 153 /* 154 * There are too many states with IRQs disabled, just keep the current 155 * state if interrupts are already disabled/masked. 156 */ 157 if (!__pmr_irqs_disabled_flags(flags)) 158 __pmr_local_irq_disable(); 159 160 return flags; 161 } 162 163 static inline unsigned long arch_local_irq_save(void) 164 { 165 if (system_uses_irq_prio_masking()) { 166 return __pmr_local_irq_save(); 167 } else { 168 return __daif_local_irq_save(); 169 } 170 } 171 172 static __always_inline void __daif_local_irq_restore(unsigned long flags) 173 { 174 barrier(); 175 write_sysreg(flags, daif); 176 barrier(); 177 } 178 179 static __always_inline void __pmr_local_irq_restore(unsigned long flags) 180 { 181 barrier(); 182 write_sysreg_s(flags, SYS_ICC_PMR_EL1); 183 pmr_sync(); 184 barrier(); 185 } 186 187 /* 188 * restore saved IRQ state 189 */ 190 static inline void arch_local_irq_restore(unsigned long flags) 191 { 192 if (system_uses_irq_prio_masking()) { 193 __pmr_local_irq_restore(flags); 194 } else { 195 __daif_local_irq_restore(flags); 196 } 197 } 198 199 #endif /* __ASM_IRQFLAGS_H */ 200