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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.14-rc6 199 lines 4.4 kB view raw
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 23static __always_inline void __daif_local_irq_enable(void) 24{ 25 barrier(); 26 asm volatile("msr daifclr, #3"); 27 barrier(); 28} 29 30static __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 43static 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 52static __always_inline void __daif_local_irq_disable(void) 53{ 54 barrier(); 55 asm volatile("msr daifset, #3"); 56 barrier(); 57} 58 59static __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 71static 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 80static __always_inline unsigned long __daif_local_save_flags(void) 81{ 82 return read_sysreg(daif); 83} 84 85static __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 */ 93static 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 102static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags) 103{ 104 return flags & PSR_I_BIT; 105} 106 107static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags) 108{ 109 return flags != GIC_PRIO_IRQON; 110} 111 112static 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 121static __always_inline bool __daif_irqs_disabled(void) 122{ 123 return __daif_irqs_disabled_flags(__daif_local_save_flags()); 124} 125 126static __always_inline bool __pmr_irqs_disabled(void) 127{ 128 return __pmr_irqs_disabled_flags(__pmr_local_save_flags()); 129} 130 131static 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 140static __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 149static __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 163static 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 172static __always_inline void __daif_local_irq_restore(unsigned long flags) 173{ 174 barrier(); 175 write_sysreg(flags, daif); 176 barrier(); 177} 178 179static __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 */ 190static 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 */