Merge tag 'icc-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov...
[linux-2.6-microblaze.git] / arch / arm64 / include / asm / hardirq.h
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 ack_bad_irq ack_bad_irq
17 #include <asm-generic/hardirq.h>
18
19 #define __ARCH_IRQ_EXIT_IRQS_DISABLED   1
20
21 struct nmi_ctx {
22         u64 hcr;
23         unsigned int cnt;
24 };
25
26 DECLARE_PER_CPU(struct nmi_ctx, nmi_contexts);
27
28 #define arch_nmi_enter()                                                \
29 do {                                                                    \
30         struct nmi_ctx *___ctx;                                         \
31         u64 ___hcr;                                                     \
32                                                                         \
33         if (!is_kernel_in_hyp_mode())                                   \
34                 break;                                                  \
35                                                                         \
36         ___ctx = this_cpu_ptr(&nmi_contexts);                           \
37         if (___ctx->cnt) {                                              \
38                 ___ctx->cnt++;                                          \
39                 break;                                                  \
40         }                                                               \
41                                                                         \
42         ___hcr = read_sysreg(hcr_el2);                                  \
43         if (!(___hcr & HCR_TGE)) {                                      \
44                 write_sysreg(___hcr | HCR_TGE, hcr_el2);                \
45                 isb();                                                  \
46         }                                                               \
47         /*                                                              \
48          * Make sure the sysreg write is performed before ___ctx->cnt   \
49          * is set to 1. NMIs that see cnt == 1 will rely on us.         \
50          */                                                             \
51         barrier();                                                      \
52         ___ctx->cnt = 1;                                                \
53         /*                                                              \
54          * Make sure ___ctx->cnt is set before we save ___hcr. We       \
55          * don't want ___ctx->hcr to be overwritten.                    \
56          */                                                             \
57         barrier();                                                      \
58         ___ctx->hcr = ___hcr;                                           \
59 } while (0)
60
61 #define arch_nmi_exit()                                                 \
62 do {                                                                    \
63         struct nmi_ctx *___ctx;                                         \
64         u64 ___hcr;                                                     \
65                                                                         \
66         if (!is_kernel_in_hyp_mode())                                   \
67                 break;                                                  \
68                                                                         \
69         ___ctx = this_cpu_ptr(&nmi_contexts);                           \
70         ___hcr = ___ctx->hcr;                                           \
71         /*                                                              \
72          * Make sure we read ___ctx->hcr before we release              \
73          * ___ctx->cnt as it makes ___ctx->hcr updatable again.         \
74          */                                                             \
75         barrier();                                                      \
76         ___ctx->cnt--;                                                  \
77         /*                                                              \
78          * Make sure ___ctx->cnt release is visible before we           \
79          * restore the sysreg. Otherwise a new NMI occurring            \
80          * right after write_sysreg() can be fooled and think           \
81          * we secured things for it.                                    \
82          */                                                             \
83         barrier();                                                      \
84         if (!___ctx->cnt && !(___hcr & HCR_TGE))                        \
85                 write_sysreg(___hcr, hcr_el2);                          \
86 } while (0)
87
88 static inline void ack_bad_irq(unsigned int irq)
89 {
90         extern unsigned long irq_err_count;
91         irq_err_count++;
92 }
93
94 #endif /* __ASM_HARDIRQ_H */