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/barrier.h>
9 #include <asm/ptrace.h>
10 #include <asm/sysreg.h>
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'
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.
23 static __always_inline
void __daif_local_irq_enable(void)
26 asm volatile("msr daifclr, #3");
30 static __always_inline
void __pmr_local_irq_enable(void)
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
);
38 write_sysreg_s(GIC_PRIO_IRQON
, SYS_ICC_PMR_EL1
);
43 static inline void arch_local_irq_enable(void)
45 if (system_uses_irq_prio_masking()) {
46 __pmr_local_irq_enable();
48 __daif_local_irq_enable();
52 static __always_inline
void __daif_local_irq_disable(void)
55 asm volatile("msr daifset, #3");
59 static __always_inline
void __pmr_local_irq_disable(void)
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
);
67 write_sysreg_s(GIC_PRIO_IRQOFF
, SYS_ICC_PMR_EL1
);
71 static inline void arch_local_irq_disable(void)
73 if (system_uses_irq_prio_masking()) {
74 __pmr_local_irq_disable();
76 __daif_local_irq_disable();
80 static __always_inline
unsigned long __daif_local_save_flags(void)
82 return read_sysreg(daif
);
85 static __always_inline
unsigned long __pmr_local_save_flags(void)
87 return read_sysreg_s(SYS_ICC_PMR_EL1
);
91 * Save the current interrupt enable state.
93 static inline unsigned long arch_local_save_flags(void)
95 if (system_uses_irq_prio_masking()) {
96 return __pmr_local_save_flags();
98 return __daif_local_save_flags();
102 static __always_inline
bool __daif_irqs_disabled_flags(unsigned long flags
)
104 return flags
& PSR_I_BIT
;
107 static __always_inline
bool __pmr_irqs_disabled_flags(unsigned long flags
)
109 return flags
!= GIC_PRIO_IRQON
;
112 static inline bool arch_irqs_disabled_flags(unsigned long flags
)
114 if (system_uses_irq_prio_masking()) {
115 return __pmr_irqs_disabled_flags(flags
);
117 return __daif_irqs_disabled_flags(flags
);
121 static __always_inline
bool __daif_irqs_disabled(void)
123 return __daif_irqs_disabled_flags(__daif_local_save_flags());
126 static __always_inline
bool __pmr_irqs_disabled(void)
128 return __pmr_irqs_disabled_flags(__pmr_local_save_flags());
131 static inline bool arch_irqs_disabled(void)
133 if (system_uses_irq_prio_masking()) {
134 return __pmr_irqs_disabled();
136 return __daif_irqs_disabled();
140 static __always_inline
unsigned long __daif_local_irq_save(void)
142 unsigned long flags
= __daif_local_save_flags();
144 __daif_local_irq_disable();
149 static __always_inline
unsigned long __pmr_local_irq_save(void)
151 unsigned long flags
= __pmr_local_save_flags();
154 * There are too many states with IRQs disabled, just keep the current
155 * state if interrupts are already disabled/masked.
157 if (!__pmr_irqs_disabled_flags(flags
))
158 __pmr_local_irq_disable();
163 static inline unsigned long arch_local_irq_save(void)
165 if (system_uses_irq_prio_masking()) {
166 return __pmr_local_irq_save();
168 return __daif_local_irq_save();
172 static __always_inline
void __daif_local_irq_restore(unsigned long flags
)
175 write_sysreg(flags
, daif
);
179 static __always_inline
void __pmr_local_irq_restore(unsigned long flags
)
182 write_sysreg_s(flags
, SYS_ICC_PMR_EL1
);
188 * restore saved IRQ state
190 static inline void arch_local_irq_restore(unsigned long flags
)
192 if (system_uses_irq_prio_masking()) {
193 __pmr_local_irq_restore(flags
);
195 __daif_local_irq_restore(flags
);
199 #endif /* __ASM_IRQFLAGS_H */