xref: /openbmc/linux/arch/arm64/include/asm/hardirq.h (revision f97769fd)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2012 ARM Ltd.
4  */
5 #ifndef __ASM_HARDIRQ_H
6 #define __ASM_HARDIRQ_H
7 
8 #include <linux/cache.h>
9 #include <linux/percpu.h>
10 #include <linux/threads.h>
11 #include <asm/barrier.h>
12 #include <asm/irq.h>
13 #include <asm/kvm_arm.h>
14 #include <asm/sysreg.h>
15 
16 #define NR_IPI	7
17 
18 typedef struct {
19 	unsigned int __softirq_pending;
20 	unsigned int ipi_irqs[NR_IPI];
21 } ____cacheline_aligned irq_cpustat_t;
22 
23 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
24 
25 #define __inc_irq_stat(cpu, member)	__IRQ_STAT(cpu, member)++
26 #define __get_irq_stat(cpu, member)	__IRQ_STAT(cpu, member)
27 
28 u64 smp_irq_stat_cpu(unsigned int cpu);
29 #define arch_irq_stat_cpu	smp_irq_stat_cpu
30 
31 #define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
32 
33 struct nmi_ctx {
34 	u64 hcr;
35 	unsigned int cnt;
36 };
37 
38 DECLARE_PER_CPU(struct nmi_ctx, nmi_contexts);
39 
40 #define arch_nmi_enter()						\
41 do {									\
42 	struct nmi_ctx *___ctx;						\
43 	u64 ___hcr;							\
44 									\
45 	if (!is_kernel_in_hyp_mode())					\
46 		break;							\
47 									\
48 	___ctx = this_cpu_ptr(&nmi_contexts);				\
49 	if (___ctx->cnt) {						\
50 		___ctx->cnt++;						\
51 		break;							\
52 	}								\
53 									\
54 	___hcr = read_sysreg(hcr_el2);					\
55 	if (!(___hcr & HCR_TGE)) {					\
56 		write_sysreg(___hcr | HCR_TGE, hcr_el2);		\
57 		isb();							\
58 	}								\
59 	/*								\
60 	 * Make sure the sysreg write is performed before ___ctx->cnt	\
61 	 * is set to 1. NMIs that see cnt == 1 will rely on us.		\
62 	 */								\
63 	barrier();							\
64 	___ctx->cnt = 1;                                                \
65 	/*								\
66 	 * Make sure ___ctx->cnt is set before we save ___hcr. We	\
67 	 * don't want ___ctx->hcr to be overwritten.			\
68 	 */								\
69 	barrier();							\
70 	___ctx->hcr = ___hcr;						\
71 } while (0)
72 
73 #define arch_nmi_exit()							\
74 do {									\
75 	struct nmi_ctx *___ctx;						\
76 	u64 ___hcr;							\
77 									\
78 	if (!is_kernel_in_hyp_mode())					\
79 		break;							\
80 									\
81 	___ctx = this_cpu_ptr(&nmi_contexts);				\
82 	___hcr = ___ctx->hcr;						\
83 	/*								\
84 	 * Make sure we read ___ctx->hcr before we release		\
85 	 * ___ctx->cnt as it makes ___ctx->hcr updatable again.		\
86 	 */								\
87 	barrier();							\
88 	___ctx->cnt--;							\
89 	/*								\
90 	 * Make sure ___ctx->cnt release is visible before we		\
91 	 * restore the sysreg. Otherwise a new NMI occurring		\
92 	 * right after write_sysreg() can be fooled and think		\
93 	 * we secured things for it.					\
94 	 */								\
95 	barrier();							\
96 	if (!___ctx->cnt && !(___hcr & HCR_TGE))			\
97 		write_sysreg(___hcr, hcr_el2);				\
98 } while (0)
99 
100 static inline void ack_bad_irq(unsigned int irq)
101 {
102 	extern unsigned long irq_err_count;
103 	irq_err_count++;
104 }
105 
106 #endif /* __ASM_HARDIRQ_H */
107