1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Copyright (C) 2012 ARM Ltd.
5 #ifndef __ASM_IRQFLAGS_H
6 #define __ASM_IRQFLAGS_H
8 #include <asm/alternative.h>
9 #include <asm/barrier.h>
10 #include <asm/ptrace.h>
11 #include <asm/sysreg.h>
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'
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.
24 static __always_inline void __daif_local_irq_enable(void)
27 asm volatile("msr daifclr, #3");
31 static __always_inline void __pmr_local_irq_enable(void)
33 if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
34 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
35 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
39 write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1);
44 static inline void arch_local_irq_enable(void)
46 if (system_uses_irq_prio_masking()) {
47 __pmr_local_irq_enable();
49 __daif_local_irq_enable();
53 static __always_inline void __daif_local_irq_disable(void)
56 asm volatile("msr daifset, #3");
60 static __always_inline void __pmr_local_irq_disable(void)
62 if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
63 u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
64 WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
68 write_sysreg_s(GIC_PRIO_IRQOFF, SYS_ICC_PMR_EL1);
72 static inline void arch_local_irq_disable(void)
74 if (system_uses_irq_prio_masking()) {
75 __pmr_local_irq_disable();
77 __daif_local_irq_disable();
81 static __always_inline unsigned long __daif_local_save_flags(void)
83 return read_sysreg(daif);
86 static __always_inline unsigned long __pmr_local_save_flags(void)
88 return read_sysreg_s(SYS_ICC_PMR_EL1);
92 * Save the current interrupt enable state.
94 static inline unsigned long arch_local_save_flags(void)
96 if (system_uses_irq_prio_masking()) {
97 return __pmr_local_save_flags();
99 return __daif_local_save_flags();
103 static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags)
105 return flags & PSR_I_BIT;
108 static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags)
110 return flags != GIC_PRIO_IRQON;
113 static inline bool arch_irqs_disabled_flags(unsigned long flags)
115 if (system_uses_irq_prio_masking()) {
116 return __pmr_irqs_disabled_flags(flags);
118 return __daif_irqs_disabled_flags(flags);
122 static __always_inline bool __daif_irqs_disabled(void)
124 return __daif_irqs_disabled_flags(__daif_local_save_flags());
127 static __always_inline bool __pmr_irqs_disabled(void)
129 return __pmr_irqs_disabled_flags(__pmr_local_save_flags());
132 static inline bool arch_irqs_disabled(void)
134 if (system_uses_irq_prio_masking()) {
135 return __pmr_irqs_disabled();
137 return __daif_irqs_disabled();
141 static __always_inline unsigned long __daif_local_irq_save(void)
143 unsigned long flags = __daif_local_save_flags();
145 __daif_local_irq_disable();
150 static __always_inline unsigned long __pmr_local_irq_save(void)
152 unsigned long flags = __pmr_local_save_flags();
155 * There are too many states with IRQs disabled, just keep the current
156 * state if interrupts are already disabled/masked.
158 if (!__pmr_irqs_disabled_flags(flags))
159 __pmr_local_irq_disable();
164 static inline unsigned long arch_local_irq_save(void)
166 if (system_uses_irq_prio_masking()) {
167 return __pmr_local_irq_save();
169 return __daif_local_irq_save();
173 static __always_inline void __daif_local_irq_restore(unsigned long flags)
176 write_sysreg(flags, daif);
180 static __always_inline void __pmr_local_irq_restore(unsigned long flags)
183 write_sysreg_s(flags, SYS_ICC_PMR_EL1);
189 * restore saved IRQ state
191 static inline void arch_local_irq_restore(unsigned long flags)
193 if (system_uses_irq_prio_masking()) {
194 __pmr_local_irq_restore(flags);
196 __daif_local_irq_restore(flags);
200 #endif /* __ASM_IRQFLAGS_H */