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 Zyngierstatic 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