hardirq.h 2.3 KB

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