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