xref: /linux/arch/arm64/include/asm/hardirq.h (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2fb9bd7d6SMarc Zyngier /*
3fb9bd7d6SMarc Zyngier  * Copyright (C) 2012 ARM Ltd.
4fb9bd7d6SMarc Zyngier  */
5fb9bd7d6SMarc Zyngier #ifndef __ASM_HARDIRQ_H
6fb9bd7d6SMarc Zyngier #define __ASM_HARDIRQ_H
7fb9bd7d6SMarc Zyngier 
8fb9bd7d6SMarc Zyngier #include <linux/cache.h>
95870970bSJulien Thierry #include <linux/percpu.h>
10fb9bd7d6SMarc Zyngier #include <linux/threads.h>
115870970bSJulien Thierry #include <asm/barrier.h>
12fb9bd7d6SMarc Zyngier #include <asm/irq.h>
135870970bSJulien Thierry #include <asm/kvm_arm.h>
145870970bSJulien Thierry #include <asm/sysreg.h>
15fb9bd7d6SMarc Zyngier 
16*2cb0837eSThomas Gleixner #define ack_bad_irq ack_bad_irq
17*2cb0837eSThomas Gleixner #include <asm-generic/hardirq.h>
18fb9bd7d6SMarc Zyngier 
19fb9bd7d6SMarc Zyngier #define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
20fb9bd7d6SMarc Zyngier 
215870970bSJulien Thierry struct nmi_ctx {
225870970bSJulien Thierry 	u64 hcr;
2328f6bf9eSFrederic Weisbecker 	unsigned int cnt;
245870970bSJulien Thierry };
255870970bSJulien Thierry 
265870970bSJulien Thierry DECLARE_PER_CPU(struct nmi_ctx, nmi_contexts);
275870970bSJulien Thierry 
285870970bSJulien Thierry #define arch_nmi_enter()						\
295870970bSJulien Thierry do {									\
3028f6bf9eSFrederic Weisbecker 	struct nmi_ctx *___ctx;						\
3128f6bf9eSFrederic Weisbecker 	u64 ___hcr;							\
3228f6bf9eSFrederic Weisbecker 									\
3328f6bf9eSFrederic Weisbecker 	if (!is_kernel_in_hyp_mode())					\
3428f6bf9eSFrederic Weisbecker 		break;							\
3528f6bf9eSFrederic Weisbecker 									\
3628f6bf9eSFrederic Weisbecker 	___ctx = this_cpu_ptr(&nmi_contexts);				\
3728f6bf9eSFrederic Weisbecker 	if (___ctx->cnt) {						\
3828f6bf9eSFrederic Weisbecker 		___ctx->cnt++;						\
3928f6bf9eSFrederic Weisbecker 		break;							\
4028f6bf9eSFrederic Weisbecker 	}								\
4128f6bf9eSFrederic Weisbecker 									\
4228f6bf9eSFrederic Weisbecker 	___hcr = read_sysreg(hcr_el2);					\
4328f6bf9eSFrederic Weisbecker 	if (!(___hcr & HCR_TGE)) {					\
4428f6bf9eSFrederic Weisbecker 		write_sysreg(___hcr | HCR_TGE, hcr_el2);		\
455870970bSJulien Thierry 		isb();							\
465870970bSJulien Thierry 	}								\
4728f6bf9eSFrederic Weisbecker 	/*								\
4828f6bf9eSFrederic Weisbecker 	 * Make sure the sysreg write is performed before ___ctx->cnt	\
4928f6bf9eSFrederic Weisbecker 	 * is set to 1. NMIs that see cnt == 1 will rely on us.		\
5028f6bf9eSFrederic Weisbecker 	 */								\
5128f6bf9eSFrederic Weisbecker 	barrier();							\
5228f6bf9eSFrederic Weisbecker 	___ctx->cnt = 1;                                                \
5328f6bf9eSFrederic Weisbecker 	/*								\
5428f6bf9eSFrederic Weisbecker 	 * Make sure ___ctx->cnt is set before we save ___hcr. We	\
5528f6bf9eSFrederic Weisbecker 	 * don't want ___ctx->hcr to be overwritten.			\
5628f6bf9eSFrederic Weisbecker 	 */								\
5728f6bf9eSFrederic Weisbecker 	barrier();							\
5828f6bf9eSFrederic Weisbecker 	___ctx->hcr = ___hcr;						\
595870970bSJulien Thierry } while (0)
605870970bSJulien Thierry 
615870970bSJulien Thierry #define arch_nmi_exit()							\
625870970bSJulien Thierry do {									\
6328f6bf9eSFrederic Weisbecker 	struct nmi_ctx *___ctx;						\
6428f6bf9eSFrederic Weisbecker 	u64 ___hcr;							\
6528f6bf9eSFrederic Weisbecker 									\
6628f6bf9eSFrederic Weisbecker 	if (!is_kernel_in_hyp_mode())					\
6728f6bf9eSFrederic Weisbecker 		break;							\
6828f6bf9eSFrederic Weisbecker 									\
6928f6bf9eSFrederic Weisbecker 	___ctx = this_cpu_ptr(&nmi_contexts);				\
7028f6bf9eSFrederic Weisbecker 	___hcr = ___ctx->hcr;						\
7128f6bf9eSFrederic Weisbecker 	/*								\
7228f6bf9eSFrederic Weisbecker 	 * Make sure we read ___ctx->hcr before we release		\
7328f6bf9eSFrederic Weisbecker 	 * ___ctx->cnt as it makes ___ctx->hcr updatable again.		\
7428f6bf9eSFrederic Weisbecker 	 */								\
7528f6bf9eSFrederic Weisbecker 	barrier();							\
7628f6bf9eSFrederic Weisbecker 	___ctx->cnt--;							\
7728f6bf9eSFrederic Weisbecker 	/*								\
7828f6bf9eSFrederic Weisbecker 	 * Make sure ___ctx->cnt release is visible before we		\
7928f6bf9eSFrederic Weisbecker 	 * restore the sysreg. Otherwise a new NMI occurring		\
8028f6bf9eSFrederic Weisbecker 	 * right after write_sysreg() can be fooled and think		\
8128f6bf9eSFrederic Weisbecker 	 * we secured things for it.					\
8228f6bf9eSFrederic Weisbecker 	 */								\
8328f6bf9eSFrederic Weisbecker 	barrier();							\
8428f6bf9eSFrederic Weisbecker 	if (!___ctx->cnt && !(___hcr & HCR_TGE))			\
8528f6bf9eSFrederic Weisbecker 		write_sysreg(___hcr, hcr_el2);				\
865870970bSJulien Thierry } while (0)
875870970bSJulien Thierry 
ack_bad_irq(unsigned int irq)88fb9bd7d6SMarc Zyngier static inline void ack_bad_irq(unsigned int irq)
89fb9bd7d6SMarc Zyngier {
90fb9bd7d6SMarc Zyngier 	extern unsigned long irq_err_count;
91fb9bd7d6SMarc Zyngier 	irq_err_count++;
92fb9bd7d6SMarc Zyngier }
93fb9bd7d6SMarc Zyngier 
94fb9bd7d6SMarc Zyngier #endif /* __ASM_HARDIRQ_H */
95