Warning: That file was not part of the compilation database. It may have many parsing errors.
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/alternative.h> |
9 | #include <asm/barrier.h> |
10 | #include <asm/ptrace.h> |
11 | #include <asm/sysreg.h> |
12 | |
13 | /* |
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' |
16 | * order: |
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. |
22 | */ |
23 | |
24 | static __always_inline void __daif_local_irq_enable(void) |
25 | { |
26 | barrier(); |
27 | asm volatile("msr daifclr, #3"); |
28 | barrier(); |
29 | } |
30 | |
31 | static __always_inline void __pmr_local_irq_enable(void) |
32 | { |
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); |
36 | } |
37 | |
38 | barrier(); |
39 | write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1); |
40 | pmr_sync(); |
41 | barrier(); |
42 | } |
43 | |
44 | static inline void arch_local_irq_enable(void) |
45 | { |
46 | if (system_uses_irq_prio_masking()) { |
47 | __pmr_local_irq_enable(); |
48 | } else { |
49 | __daif_local_irq_enable(); |
50 | } |
51 | } |
52 | |
53 | static __always_inline void __daif_local_irq_disable(void) |
54 | { |
55 | barrier(); |
56 | asm volatile("msr daifset, #3"); |
57 | barrier(); |
58 | } |
59 | |
60 | static __always_inline void __pmr_local_irq_disable(void) |
61 | { |
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); |
65 | } |
66 | |
67 | barrier(); |
68 | write_sysreg_s(GIC_PRIO_IRQOFF, SYS_ICC_PMR_EL1); |
69 | barrier(); |
70 | } |
71 | |
72 | static inline void arch_local_irq_disable(void) |
73 | { |
74 | if (system_uses_irq_prio_masking()) { |
75 | __pmr_local_irq_disable(); |
76 | } else { |
77 | __daif_local_irq_disable(); |
78 | } |
79 | } |
80 | |
81 | static __always_inline unsigned long __daif_local_save_flags(void) |
82 | { |
83 | return read_sysreg(daif); |
84 | } |
85 | |
86 | static __always_inline unsigned long __pmr_local_save_flags(void) |
87 | { |
88 | return read_sysreg_s(SYS_ICC_PMR_EL1); |
89 | } |
90 | |
91 | /* |
92 | * Save the current interrupt enable state. |
93 | */ |
94 | static inline unsigned long arch_local_save_flags(void) |
95 | { |
96 | if (system_uses_irq_prio_masking()) { |
97 | return __pmr_local_save_flags(); |
98 | } else { |
99 | return __daif_local_save_flags(); |
100 | } |
101 | } |
102 | |
103 | static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags) |
104 | { |
105 | return flags & PSR_I_BIT; |
106 | } |
107 | |
108 | static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags) |
109 | { |
110 | return flags != GIC_PRIO_IRQON; |
111 | } |
112 | |
113 | static inline bool arch_irqs_disabled_flags(unsigned long flags) |
114 | { |
115 | if (system_uses_irq_prio_masking()) { |
116 | return __pmr_irqs_disabled_flags(flags); |
117 | } else { |
118 | return __daif_irqs_disabled_flags(flags); |
119 | } |
120 | } |
121 | |
122 | static __always_inline bool __daif_irqs_disabled(void) |
123 | { |
124 | return __daif_irqs_disabled_flags(__daif_local_save_flags()); |
125 | } |
126 | |
127 | static __always_inline bool __pmr_irqs_disabled(void) |
128 | { |
129 | return __pmr_irqs_disabled_flags(__pmr_local_save_flags()); |
130 | } |
131 | |
132 | static inline bool arch_irqs_disabled(void) |
133 | { |
134 | if (system_uses_irq_prio_masking()) { |
135 | return __pmr_irqs_disabled(); |
136 | } else { |
137 | return __daif_irqs_disabled(); |
138 | } |
139 | } |
140 | |
141 | static __always_inline unsigned long __daif_local_irq_save(void) |
142 | { |
143 | unsigned long flags = __daif_local_save_flags(); |
144 | |
145 | __daif_local_irq_disable(); |
146 | |
147 | return flags; |
148 | } |
149 | |
150 | static __always_inline unsigned long __pmr_local_irq_save(void) |
151 | { |
152 | unsigned long flags = __pmr_local_save_flags(); |
153 | |
154 | /* |
155 | * There are too many states with IRQs disabled, just keep the current |
156 | * state if interrupts are already disabled/masked. |
157 | */ |
158 | if (!__pmr_irqs_disabled_flags(flags)) |
159 | __pmr_local_irq_disable(); |
160 | |
161 | return flags; |
162 | } |
163 | |
164 | static inline unsigned long arch_local_irq_save(void) |
165 | { |
166 | if (system_uses_irq_prio_masking()) { |
167 | return __pmr_local_irq_save(); |
168 | } else { |
169 | return __daif_local_irq_save(); |
170 | } |
171 | } |
172 | |
173 | static __always_inline void __daif_local_irq_restore(unsigned long flags) |
174 | { |
175 | barrier(); |
176 | write_sysreg(flags, daif); |
177 | barrier(); |
178 | } |
179 | |
180 | static __always_inline void __pmr_local_irq_restore(unsigned long flags) |
181 | { |
182 | barrier(); |
183 | write_sysreg_s(flags, SYS_ICC_PMR_EL1); |
184 | pmr_sync(); |
185 | barrier(); |
186 | } |
187 | |
188 | /* |
189 | * restore saved IRQ state |
190 | */ |
191 | static inline void arch_local_irq_restore(unsigned long flags) |
192 | { |
193 | if (system_uses_irq_prio_masking()) { |
194 | __pmr_local_irq_restore(flags); |
195 | } else { |
196 | __daif_local_irq_restore(flags); |
197 | } |
198 | } |
199 | |
200 | #endif /* __ASM_IRQFLAGS_H */ |
201 |
Warning: That file was not part of the compilation database. It may have many parsing errors.