Linux Audio

Check our new training course

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