irqflags.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * include/linux/irqflags.h
  4. *
  5. * IRQ flags tracing: follow the state of the hardirq and softirq flags and
  6. * provide callbacks for transitions between ON and OFF states.
  7. *
  8. * This file gets included from lowlevel asm headers too, to provide
  9. * wrapped versions of the local_irq_*() APIs, based on the
  10. * raw_local_irq_*() macros from the lowlevel headers.
  11. */
  12. #ifndef _LINUX_TRACE_IRQFLAGS_H
  13. #define _LINUX_TRACE_IRQFLAGS_H
  14. #include <linux/typecheck.h>
  15. #include <asm/irqflags.h>
  16. #include <asm/percpu.h>
  17. /* Currently lockdep_softirqs_on/off is used only by lockdep */
  18. #ifdef CONFIG_PROVE_LOCKING
  19. extern void lockdep_softirqs_on(unsigned long ip);
  20. extern void lockdep_softirqs_off(unsigned long ip);
  21. extern void lockdep_hardirqs_on_prepare(void);
  22. extern void lockdep_hardirqs_on(unsigned long ip);
  23. extern void lockdep_hardirqs_off(unsigned long ip);
  24. #else
  25. static inline void lockdep_softirqs_on(unsigned long ip) { }
  26. static inline void lockdep_softirqs_off(unsigned long ip) { }
  27. static inline void lockdep_hardirqs_on_prepare(void) { }
  28. static inline void lockdep_hardirqs_on(unsigned long ip) { }
  29. static inline void lockdep_hardirqs_off(unsigned long ip) { }
  30. #endif
  31. #ifdef CONFIG_TRACE_IRQFLAGS
  32. /* Per-task IRQ trace events information. */
  33. struct irqtrace_events {
  34. unsigned int irq_events;
  35. unsigned long hardirq_enable_ip;
  36. unsigned long hardirq_disable_ip;
  37. unsigned int hardirq_enable_event;
  38. unsigned int hardirq_disable_event;
  39. unsigned long softirq_disable_ip;
  40. unsigned long softirq_enable_ip;
  41. unsigned int softirq_disable_event;
  42. unsigned int softirq_enable_event;
  43. };
  44. DECLARE_PER_CPU(int, hardirqs_enabled);
  45. DECLARE_PER_CPU(int, hardirq_context);
  46. extern void trace_hardirqs_on_prepare(void);
  47. extern void trace_hardirqs_off_finish(void);
  48. extern void trace_hardirqs_on(void);
  49. extern void trace_hardirqs_off(void);
  50. # define lockdep_hardirq_context() (raw_cpu_read(hardirq_context))
  51. # define lockdep_softirq_context(p) ((p)->softirq_context)
  52. # define lockdep_hardirqs_enabled() (this_cpu_read(hardirqs_enabled))
  53. # define lockdep_softirqs_enabled(p) ((p)->softirqs_enabled)
  54. # define lockdep_hardirq_enter() \
  55. do { \
  56. if (__this_cpu_inc_return(hardirq_context) == 1)\
  57. current->hardirq_threaded = 0; \
  58. } while (0)
  59. # define lockdep_hardirq_threaded() \
  60. do { \
  61. current->hardirq_threaded = 1; \
  62. } while (0)
  63. # define lockdep_hardirq_exit() \
  64. do { \
  65. __this_cpu_dec(hardirq_context); \
  66. } while (0)
  67. # define lockdep_hrtimer_enter(__hrtimer) \
  68. ({ \
  69. bool __expires_hardirq = true; \
  70. \
  71. if (!__hrtimer->is_hard) { \
  72. current->irq_config = 1; \
  73. __expires_hardirq = false; \
  74. } \
  75. __expires_hardirq; \
  76. })
  77. # define lockdep_hrtimer_exit(__expires_hardirq) \
  78. do { \
  79. if (!__expires_hardirq) \
  80. current->irq_config = 0; \
  81. } while (0)
  82. # define lockdep_posixtimer_enter() \
  83. do { \
  84. current->irq_config = 1; \
  85. } while (0)
  86. # define lockdep_posixtimer_exit() \
  87. do { \
  88. current->irq_config = 0; \
  89. } while (0)
  90. # define lockdep_irq_work_enter(_flags) \
  91. do { \
  92. if (!((_flags) & IRQ_WORK_HARD_IRQ)) \
  93. current->irq_config = 1; \
  94. } while (0)
  95. # define lockdep_irq_work_exit(_flags) \
  96. do { \
  97. if (!((_flags) & IRQ_WORK_HARD_IRQ)) \
  98. current->irq_config = 0; \
  99. } while (0)
  100. #else
  101. # define trace_hardirqs_on_prepare() do { } while (0)
  102. # define trace_hardirqs_off_finish() do { } while (0)
  103. # define trace_hardirqs_on() do { } while (0)
  104. # define trace_hardirqs_off() do { } while (0)
  105. # define lockdep_hardirq_context() 0
  106. # define lockdep_softirq_context(p) 0
  107. # define lockdep_hardirqs_enabled() 0
  108. # define lockdep_softirqs_enabled(p) 0
  109. # define lockdep_hardirq_enter() do { } while (0)
  110. # define lockdep_hardirq_threaded() do { } while (0)
  111. # define lockdep_hardirq_exit() do { } while (0)
  112. # define lockdep_softirq_enter() do { } while (0)
  113. # define lockdep_softirq_exit() do { } while (0)
  114. # define lockdep_hrtimer_enter(__hrtimer) false
  115. # define lockdep_hrtimer_exit(__context) do { } while (0)
  116. # define lockdep_posixtimer_enter() do { } while (0)
  117. # define lockdep_posixtimer_exit() do { } while (0)
  118. # define lockdep_irq_work_enter(__work) do { } while (0)
  119. # define lockdep_irq_work_exit(__work) do { } while (0)
  120. #endif
  121. #if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PREEMPT_RT)
  122. # define lockdep_softirq_enter() \
  123. do { \
  124. current->softirq_context++; \
  125. } while (0)
  126. # define lockdep_softirq_exit() \
  127. do { \
  128. current->softirq_context--; \
  129. } while (0)
  130. #else
  131. # define lockdep_softirq_enter() do { } while (0)
  132. # define lockdep_softirq_exit() do { } while (0)
  133. #endif
  134. #if defined(CONFIG_IRQSOFF_TRACER) || \
  135. defined(CONFIG_PREEMPT_TRACER)
  136. extern void stop_critical_timings(void);
  137. extern void start_critical_timings(void);
  138. #else
  139. # define stop_critical_timings() do { } while (0)
  140. # define start_critical_timings() do { } while (0)
  141. #endif
  142. #ifdef CONFIG_DEBUG_IRQFLAGS
  143. extern void warn_bogus_irq_restore(void);
  144. #define raw_check_bogus_irq_restore() \
  145. do { \
  146. if (unlikely(!arch_irqs_disabled())) \
  147. warn_bogus_irq_restore(); \
  148. } while (0)
  149. #else
  150. #define raw_check_bogus_irq_restore() do { } while (0)
  151. #endif
  152. /*
  153. * Wrap the arch provided IRQ routines to provide appropriate checks.
  154. */
  155. #define raw_local_irq_disable() arch_local_irq_disable()
  156. #define raw_local_irq_enable() arch_local_irq_enable()
  157. #define raw_local_irq_save(flags) \
  158. do { \
  159. typecheck(unsigned long, flags); \
  160. flags = arch_local_irq_save(); \
  161. } while (0)
  162. #define raw_local_irq_restore(flags) \
  163. do { \
  164. typecheck(unsigned long, flags); \
  165. raw_check_bogus_irq_restore(); \
  166. arch_local_irq_restore(flags); \
  167. } while (0)
  168. #define raw_local_save_flags(flags) \
  169. do { \
  170. typecheck(unsigned long, flags); \
  171. flags = arch_local_save_flags(); \
  172. } while (0)
  173. #define raw_irqs_disabled_flags(flags) \
  174. ({ \
  175. typecheck(unsigned long, flags); \
  176. arch_irqs_disabled_flags(flags); \
  177. })
  178. #define raw_irqs_disabled() (arch_irqs_disabled())
  179. #define raw_safe_halt() arch_safe_halt()
  180. /*
  181. * The local_irq_*() APIs are equal to the raw_local_irq*()
  182. * if !TRACE_IRQFLAGS.
  183. */
  184. #ifdef CONFIG_TRACE_IRQFLAGS
  185. #define local_irq_enable() \
  186. do { \
  187. trace_hardirqs_on(); \
  188. raw_local_irq_enable(); \
  189. } while (0)
  190. #define local_irq_disable() \
  191. do { \
  192. bool was_disabled = raw_irqs_disabled();\
  193. raw_local_irq_disable(); \
  194. if (!was_disabled) \
  195. trace_hardirqs_off(); \
  196. } while (0)
  197. #define local_irq_save(flags) \
  198. do { \
  199. raw_local_irq_save(flags); \
  200. if (!raw_irqs_disabled_flags(flags)) \
  201. trace_hardirqs_off(); \
  202. } while (0)
  203. #define local_irq_restore(flags) \
  204. do { \
  205. if (!raw_irqs_disabled_flags(flags)) \
  206. trace_hardirqs_on(); \
  207. raw_local_irq_restore(flags); \
  208. } while (0)
  209. #define safe_halt() \
  210. do { \
  211. trace_hardirqs_on(); \
  212. raw_safe_halt(); \
  213. } while (0)
  214. #else /* !CONFIG_TRACE_IRQFLAGS */
  215. #define local_irq_enable() do { raw_local_irq_enable(); } while (0)
  216. #define local_irq_disable() do { raw_local_irq_disable(); } while (0)
  217. #define local_irq_save(flags) do { raw_local_irq_save(flags); } while (0)
  218. #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)
  219. #define safe_halt() do { raw_safe_halt(); } while (0)
  220. #endif /* CONFIG_TRACE_IRQFLAGS */
  221. #define local_save_flags(flags) raw_local_save_flags(flags)
  222. /*
  223. * Some architectures don't define arch_irqs_disabled(), so even if either
  224. * definition would be fine we need to use different ones for the time being
  225. * to avoid build issues.
  226. */
  227. #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
  228. #define irqs_disabled() \
  229. ({ \
  230. unsigned long _flags; \
  231. raw_local_save_flags(_flags); \
  232. raw_irqs_disabled_flags(_flags); \
  233. })
  234. #else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */
  235. #define irqs_disabled() raw_irqs_disabled()
  236. #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */
  237. #define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags)
  238. #endif