xref: /openbmc/linux/arch/arm64/include/asm/irqflags.h (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2fb9bd7d6SMarc Zyngier /*
3fb9bd7d6SMarc Zyngier  * Copyright (C) 2012 ARM Ltd.
4fb9bd7d6SMarc Zyngier  */
5fb9bd7d6SMarc Zyngier #ifndef __ASM_IRQFLAGS_H
6fb9bd7d6SMarc Zyngier #define __ASM_IRQFLAGS_H
7fb9bd7d6SMarc Zyngier 
84a503217SJulien Thierry #include <asm/alternative.h>
9f2266504SMarc Zyngier #include <asm/barrier.h>
10fb9bd7d6SMarc Zyngier #include <asm/ptrace.h>
114a503217SJulien Thierry #include <asm/sysreg.h>
12fb9bd7d6SMarc Zyngier 
13fb9bd7d6SMarc Zyngier /*
1465be7a1bSJames Morse  * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and
15f0098155SHector Martin  * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif'
1665be7a1bSJames Morse  * order:
1765be7a1bSJames Morse  * Masking debug exceptions causes all other exceptions to be masked too/
18f0098155SHector Martin  * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are
19f0098155SHector Martin  * always masked and unmasked together, and have no side effects for other
20f0098155SHector Martin  * flags. Keeping to this order makes it easier for entry.S to know which
21f0098155SHector Martin  * exceptions should be unmasked.
2265be7a1bSJames Morse  */
2365be7a1bSJames Morse 
__irqflags_uses_pmr(void)24a5f61cc6SMark Rutland static __always_inline bool __irqflags_uses_pmr(void)
25fb9bd7d6SMarc Zyngier {
26a5f61cc6SMark Rutland 	return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
27*5235c7e2SMark Rutland 	       alternative_has_cap_unlikely(ARM64_HAS_GIC_PRIO_MASKING);
28a5f61cc6SMark Rutland }
2948ce8f80SJulien Thierry 
__daif_local_irq_enable(void)30a5f61cc6SMark Rutland static __always_inline void __daif_local_irq_enable(void)
31a5f61cc6SMark Rutland {
32a5f61cc6SMark Rutland 	barrier();
33a5f61cc6SMark Rutland 	asm volatile("msr daifclr, #3");
34a5f61cc6SMark Rutland 	barrier();
35a5f61cc6SMark Rutland }
36a5f61cc6SMark Rutland 
__pmr_local_irq_enable(void)37a5f61cc6SMark Rutland static __always_inline void __pmr_local_irq_enable(void)
38a5f61cc6SMark Rutland {
39a5f61cc6SMark Rutland 	if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
40a5f61cc6SMark Rutland 		u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
4148ce8f80SJulien Thierry 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
4248ce8f80SJulien Thierry 	}
4348ce8f80SJulien Thierry 
44a5f61cc6SMark Rutland 	barrier();
45a5f61cc6SMark Rutland 	write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1);
46f2266504SMarc Zyngier 	pmr_sync();
47a5f61cc6SMark Rutland 	barrier();
48a5f61cc6SMark Rutland }
49a5f61cc6SMark Rutland 
arch_local_irq_enable(void)50a5f61cc6SMark Rutland static inline void arch_local_irq_enable(void)
51a5f61cc6SMark Rutland {
52a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
53a5f61cc6SMark Rutland 		__pmr_local_irq_enable();
54a5f61cc6SMark Rutland 	} else {
55a5f61cc6SMark Rutland 		__daif_local_irq_enable();
56a5f61cc6SMark Rutland 	}
57a5f61cc6SMark Rutland }
58a5f61cc6SMark Rutland 
__daif_local_irq_disable(void)59a5f61cc6SMark Rutland static __always_inline void __daif_local_irq_disable(void)
60a5f61cc6SMark Rutland {
61a5f61cc6SMark Rutland 	barrier();
62a5f61cc6SMark Rutland 	asm volatile("msr daifset, #3");
63a5f61cc6SMark Rutland 	barrier();
64a5f61cc6SMark Rutland }
65a5f61cc6SMark Rutland 
__pmr_local_irq_disable(void)66a5f61cc6SMark Rutland static __always_inline void __pmr_local_irq_disable(void)
67a5f61cc6SMark Rutland {
68a5f61cc6SMark Rutland 	if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
69a5f61cc6SMark Rutland 		u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
70a5f61cc6SMark Rutland 		WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
71a5f61cc6SMark Rutland 	}
72a5f61cc6SMark Rutland 
73a5f61cc6SMark Rutland 	barrier();
74a5f61cc6SMark Rutland 	write_sysreg_s(GIC_PRIO_IRQOFF, SYS_ICC_PMR_EL1);
75a5f61cc6SMark Rutland 	barrier();
76fb9bd7d6SMarc Zyngier }
77fb9bd7d6SMarc Zyngier 
arch_local_irq_disable(void)78fb9bd7d6SMarc Zyngier static inline void arch_local_irq_disable(void)
79fb9bd7d6SMarc Zyngier {
80a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
81a5f61cc6SMark Rutland 		__pmr_local_irq_disable();
82a5f61cc6SMark Rutland 	} else {
83a5f61cc6SMark Rutland 		__daif_local_irq_disable();
84a5f61cc6SMark Rutland 	}
8548ce8f80SJulien Thierry }
8648ce8f80SJulien Thierry 
__daif_local_save_flags(void)87a5f61cc6SMark Rutland static __always_inline unsigned long __daif_local_save_flags(void)
88a5f61cc6SMark Rutland {
89a5f61cc6SMark Rutland 	return read_sysreg(daif);
90a5f61cc6SMark Rutland }
91a5f61cc6SMark Rutland 
__pmr_local_save_flags(void)92a5f61cc6SMark Rutland static __always_inline unsigned long __pmr_local_save_flags(void)
93a5f61cc6SMark Rutland {
94a5f61cc6SMark Rutland 	return read_sysreg_s(SYS_ICC_PMR_EL1);
95fb9bd7d6SMarc Zyngier }
96fb9bd7d6SMarc Zyngier 
97fb9bd7d6SMarc Zyngier /*
98fb9bd7d6SMarc Zyngier  * Save the current interrupt enable state.
99fb9bd7d6SMarc Zyngier  */
arch_local_save_flags(void)100fb9bd7d6SMarc Zyngier static inline unsigned long arch_local_save_flags(void)
101fb9bd7d6SMarc Zyngier {
102a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
103a5f61cc6SMark Rutland 		return __pmr_local_save_flags();
104a5f61cc6SMark Rutland 	} else {
105a5f61cc6SMark Rutland 		return __daif_local_save_flags();
106a5f61cc6SMark Rutland 	}
107a5f61cc6SMark Rutland }
1084a503217SJulien Thierry 
__daif_irqs_disabled_flags(unsigned long flags)109a5f61cc6SMark Rutland static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags)
110a5f61cc6SMark Rutland {
111a5f61cc6SMark Rutland 	return flags & PSR_I_BIT;
112a5f61cc6SMark Rutland }
113a5f61cc6SMark Rutland 
__pmr_irqs_disabled_flags(unsigned long flags)114a5f61cc6SMark Rutland static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags)
115a5f61cc6SMark Rutland {
116a5f61cc6SMark Rutland 	return flags != GIC_PRIO_IRQON;
117a5f61cc6SMark Rutland }
118a5f61cc6SMark Rutland 
arch_irqs_disabled_flags(unsigned long flags)119a5f61cc6SMark Rutland static inline bool arch_irqs_disabled_flags(unsigned long flags)
120a5f61cc6SMark Rutland {
121a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
122a5f61cc6SMark Rutland 		return __pmr_irqs_disabled_flags(flags);
123a5f61cc6SMark Rutland 	} else {
124a5f61cc6SMark Rutland 		return __daif_irqs_disabled_flags(flags);
125a5f61cc6SMark Rutland 	}
126a5f61cc6SMark Rutland }
127a5f61cc6SMark Rutland 
__daif_irqs_disabled(void)128a5f61cc6SMark Rutland static __always_inline bool __daif_irqs_disabled(void)
129a5f61cc6SMark Rutland {
130a5f61cc6SMark Rutland 	return __daif_irqs_disabled_flags(__daif_local_save_flags());
131a5f61cc6SMark Rutland }
132a5f61cc6SMark Rutland 
__pmr_irqs_disabled(void)133a5f61cc6SMark Rutland static __always_inline bool __pmr_irqs_disabled(void)
134a5f61cc6SMark Rutland {
135a5f61cc6SMark Rutland 	return __pmr_irqs_disabled_flags(__pmr_local_save_flags());
136a5f61cc6SMark Rutland }
137a5f61cc6SMark Rutland 
arch_irqs_disabled(void)138a5f61cc6SMark Rutland static inline bool arch_irqs_disabled(void)
139a5f61cc6SMark Rutland {
140a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
141a5f61cc6SMark Rutland 		return __pmr_irqs_disabled();
142a5f61cc6SMark Rutland 	} else {
143a5f61cc6SMark Rutland 		return __daif_irqs_disabled();
144a5f61cc6SMark Rutland 	}
145a5f61cc6SMark Rutland }
146a5f61cc6SMark Rutland 
__daif_local_irq_save(void)147a5f61cc6SMark Rutland static __always_inline unsigned long __daif_local_irq_save(void)
148a5f61cc6SMark Rutland {
149a5f61cc6SMark Rutland 	unsigned long flags = __daif_local_save_flags();
150a5f61cc6SMark Rutland 
151a5f61cc6SMark Rutland 	__daif_local_irq_disable();
1524a503217SJulien Thierry 
1534a503217SJulien Thierry 	return flags;
1544a503217SJulien Thierry }
1554a503217SJulien Thierry 
__pmr_local_irq_save(void)156a5f61cc6SMark Rutland static __always_inline unsigned long __pmr_local_irq_save(void)
157bd82d4bdSJulien Thierry {
158a5f61cc6SMark Rutland 	unsigned long flags = __pmr_local_save_flags();
1594a503217SJulien Thierry 
160bd82d4bdSJulien Thierry 	/*
161bd82d4bdSJulien Thierry 	 * There are too many states with IRQs disabled, just keep the current
162bd82d4bdSJulien Thierry 	 * state if interrupts are already disabled/masked.
163bd82d4bdSJulien Thierry 	 */
164a5f61cc6SMark Rutland 	if (!__pmr_irqs_disabled_flags(flags))
165a5f61cc6SMark Rutland 		__pmr_local_irq_disable();
1664a503217SJulien Thierry 
167fb9bd7d6SMarc Zyngier 	return flags;
168fb9bd7d6SMarc Zyngier }
169fb9bd7d6SMarc Zyngier 
arch_local_irq_save(void)170a5f61cc6SMark Rutland static inline unsigned long arch_local_irq_save(void)
171a5f61cc6SMark Rutland {
172a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
173a5f61cc6SMark Rutland 		return __pmr_local_irq_save();
174a5f61cc6SMark Rutland 	} else {
175a5f61cc6SMark Rutland 		return __daif_local_irq_save();
176a5f61cc6SMark Rutland 	}
177a5f61cc6SMark Rutland }
178a5f61cc6SMark Rutland 
__daif_local_irq_restore(unsigned long flags)179a5f61cc6SMark Rutland static __always_inline void __daif_local_irq_restore(unsigned long flags)
180a5f61cc6SMark Rutland {
181a5f61cc6SMark Rutland 	barrier();
182a5f61cc6SMark Rutland 	write_sysreg(flags, daif);
183a5f61cc6SMark Rutland 	barrier();
184a5f61cc6SMark Rutland }
185a5f61cc6SMark Rutland 
__pmr_local_irq_restore(unsigned long flags)186a5f61cc6SMark Rutland static __always_inline void __pmr_local_irq_restore(unsigned long flags)
187a5f61cc6SMark Rutland {
188a5f61cc6SMark Rutland 	barrier();
189a5f61cc6SMark Rutland 	write_sysreg_s(flags, SYS_ICC_PMR_EL1);
190a5f61cc6SMark Rutland 	pmr_sync();
191a5f61cc6SMark Rutland 	barrier();
192a5f61cc6SMark Rutland }
193a5f61cc6SMark Rutland 
194fb9bd7d6SMarc Zyngier /*
195fb9bd7d6SMarc Zyngier  * restore saved IRQ state
196fb9bd7d6SMarc Zyngier  */
arch_local_irq_restore(unsigned long flags)197fb9bd7d6SMarc Zyngier static inline void arch_local_irq_restore(unsigned long flags)
198fb9bd7d6SMarc Zyngier {
199a5f61cc6SMark Rutland 	if (__irqflags_uses_pmr()) {
200a5f61cc6SMark Rutland 		__pmr_local_irq_restore(flags);
201a5f61cc6SMark Rutland 	} else {
202a5f61cc6SMark Rutland 		__daif_local_irq_restore(flags);
203a5f61cc6SMark Rutland 	}
204fb9bd7d6SMarc Zyngier }
205fb9bd7d6SMarc Zyngier 
206b907b80dSMark Rutland #endif /* __ASM_IRQFLAGS_H */
207