1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 2de30a2b3SIngo Molnar /* 3de30a2b3SIngo Molnar * include/linux/irqflags.h 4de30a2b3SIngo Molnar * 5de30a2b3SIngo Molnar * IRQ flags tracing: follow the state of the hardirq and softirq flags and 6de30a2b3SIngo Molnar * provide callbacks for transitions between ON and OFF states. 7de30a2b3SIngo Molnar * 8de30a2b3SIngo Molnar * This file gets included from lowlevel asm headers too, to provide 9de30a2b3SIngo Molnar * wrapped versions of the local_irq_*() APIs, based on the 10de30a2b3SIngo Molnar * raw_local_irq_*() macros from the lowlevel headers. 11de30a2b3SIngo Molnar */ 12de30a2b3SIngo Molnar #ifndef _LINUX_TRACE_IRQFLAGS_H 13de30a2b3SIngo Molnar #define _LINUX_TRACE_IRQFLAGS_H 14de30a2b3SIngo Molnar 159983deb2SKent Overstreet #include <linux/irqflags_types.h> 163f307891SSteven Rostedt #include <linux/typecheck.h> 1754da6a09SPeter Zijlstra #include <linux/cleanup.h> 18df9ee292SDavid Howells #include <asm/irqflags.h> 19a21ee605SPeter Zijlstra #include <asm/percpu.h> 203f307891SSteven Rostedt 21*0784181bSDavid Woodhouse struct task_struct; 22*0784181bSDavid Woodhouse 230d38453cSPeter Zijlstra /* Currently lockdep_softirqs_on/off is used only by lockdep */ 24c3bc8fd6SJoel Fernandes (Google) #ifdef CONFIG_PROVE_LOCKING 250d38453cSPeter Zijlstra extern void lockdep_softirqs_on(unsigned long ip); 260d38453cSPeter Zijlstra extern void lockdep_softirqs_off(unsigned long ip); 278b023accSNick Desaulniers extern void lockdep_hardirqs_on_prepare(void); 28bff1b208SSteven Rostedt (VMware) extern void lockdep_hardirqs_on(unsigned long ip); 29bff1b208SSteven Rostedt (VMware) extern void lockdep_hardirqs_off(unsigned long ip); 30*0784181bSDavid Woodhouse extern void lockdep_cleanup_dead_cpu(unsigned int cpu, 31*0784181bSDavid Woodhouse struct task_struct *idle); 32c3bc8fd6SJoel Fernandes (Google) #else lockdep_softirqs_on(unsigned long ip)330d38453cSPeter Zijlstra static inline void lockdep_softirqs_on(unsigned long ip) { } lockdep_softirqs_off(unsigned long ip)340d38453cSPeter Zijlstra static inline void lockdep_softirqs_off(unsigned long ip) { } lockdep_hardirqs_on_prepare(void)358b023accSNick Desaulniers static inline void lockdep_hardirqs_on_prepare(void) { } lockdep_hardirqs_on(unsigned long ip)36bff1b208SSteven Rostedt (VMware) static inline void lockdep_hardirqs_on(unsigned long ip) { } lockdep_hardirqs_off(unsigned long ip)37bff1b208SSteven Rostedt (VMware) static inline void lockdep_hardirqs_off(unsigned long ip) { } lockdep_cleanup_dead_cpu(unsigned int cpu,struct task_struct * idle)38*0784181bSDavid Woodhouse static inline void lockdep_cleanup_dead_cpu(unsigned int cpu, 39*0784181bSDavid Woodhouse struct task_struct *idle) {} 40c3bc8fd6SJoel Fernandes (Google) #endif 41c3bc8fd6SJoel Fernandes (Google) 42c3bc8fd6SJoel Fernandes (Google) #ifdef CONFIG_TRACE_IRQFLAGS 43a21ee605SPeter Zijlstra 44a21ee605SPeter Zijlstra DECLARE_PER_CPU(int, hardirqs_enabled); 45a21ee605SPeter Zijlstra DECLARE_PER_CPU(int, hardirq_context); 46a21ee605SPeter Zijlstra 470995a5dfSThomas Gleixner extern void trace_hardirqs_on_prepare(void); 48bf2b3008SPeter Zijlstra extern void trace_hardirqs_off_finish(void); 4981d68a96SSteven Rostedt extern void trace_hardirqs_on(void); 5081d68a96SSteven Rostedt extern void trace_hardirqs_off(void); 5100b0ed2dSPeter Zijlstra 52fddf9055SPeter Zijlstra # define lockdep_hardirq_context() (raw_cpu_read(hardirq_context)) 53ef996916SPeter Zijlstra # define lockdep_softirq_context(p) ((p)->softirq_context) 54f9ad4a5fSPeter Zijlstra # define lockdep_hardirqs_enabled() (this_cpu_read(hardirqs_enabled)) 55ef996916SPeter Zijlstra # define lockdep_softirqs_enabled(p) ((p)->softirqs_enabled) 562502ec37SThomas Gleixner # define lockdep_hardirq_enter() \ 57b09be676SByungchul Park do { \ 58fddf9055SPeter Zijlstra if (__this_cpu_inc_return(hardirq_context) == 1)\ 59de8f5e4fSPeter Zijlstra current->hardirq_threaded = 0; \ 60de8f5e4fSPeter Zijlstra } while (0) 61d5f744f9SLinus Torvalds # define lockdep_hardirq_threaded() \ 62de8f5e4fSPeter Zijlstra do { \ 63de8f5e4fSPeter Zijlstra current->hardirq_threaded = 1; \ 64b09be676SByungchul Park } while (0) 652502ec37SThomas Gleixner # define lockdep_hardirq_exit() \ 66b09be676SByungchul Park do { \ 67fddf9055SPeter Zijlstra __this_cpu_dec(hardirq_context); \ 68b09be676SByungchul Park } while (0) 6940db1739SSebastian Andrzej Siewior 7040db1739SSebastian Andrzej Siewior # define lockdep_hrtimer_enter(__hrtimer) \ 7173d20564SSebastian Andrzej Siewior ({ \ 7273d20564SSebastian Andrzej Siewior bool __expires_hardirq = true; \ 7373d20564SSebastian Andrzej Siewior \ 7473d20564SSebastian Andrzej Siewior if (!__hrtimer->is_hard) { \ 7540db1739SSebastian Andrzej Siewior current->irq_config = 1; \ 7673d20564SSebastian Andrzej Siewior __expires_hardirq = false; \ 7773d20564SSebastian Andrzej Siewior } \ 7873d20564SSebastian Andrzej Siewior __expires_hardirq; \ 7973d20564SSebastian Andrzej Siewior }) 8040db1739SSebastian Andrzej Siewior 8173d20564SSebastian Andrzej Siewior # define lockdep_hrtimer_exit(__expires_hardirq) \ 8240db1739SSebastian Andrzej Siewior do { \ 8373d20564SSebastian Andrzej Siewior if (!__expires_hardirq) \ 8440db1739SSebastian Andrzej Siewior current->irq_config = 0; \ 8540db1739SSebastian Andrzej Siewior } while (0) 8640db1739SSebastian Andrzej Siewior 87d53f2b62SSebastian Andrzej Siewior # define lockdep_posixtimer_enter() \ 88d53f2b62SSebastian Andrzej Siewior do { \ 89d53f2b62SSebastian Andrzej Siewior current->irq_config = 1; \ 90d53f2b62SSebastian Andrzej Siewior } while (0) 91d53f2b62SSebastian Andrzej Siewior 92d53f2b62SSebastian Andrzej Siewior # define lockdep_posixtimer_exit() \ 93d53f2b62SSebastian Andrzej Siewior do { \ 94d53f2b62SSebastian Andrzej Siewior current->irq_config = 0; \ 95d53f2b62SSebastian Andrzej Siewior } while (0) 96d53f2b62SSebastian Andrzej Siewior 972914b0baSPeter Zijlstra # define lockdep_irq_work_enter(_flags) \ 9849915ac3SSebastian Andrzej Siewior do { \ 992914b0baSPeter Zijlstra if (!((_flags) & IRQ_WORK_HARD_IRQ)) \ 10049915ac3SSebastian Andrzej Siewior current->irq_config = 1; \ 10149915ac3SSebastian Andrzej Siewior } while (0) 1022914b0baSPeter Zijlstra # define lockdep_irq_work_exit(_flags) \ 10349915ac3SSebastian Andrzej Siewior do { \ 1042914b0baSPeter Zijlstra if (!((_flags) & IRQ_WORK_HARD_IRQ)) \ 10549915ac3SSebastian Andrzej Siewior current->irq_config = 0; \ 10649915ac3SSebastian Andrzej Siewior } while (0) 10749915ac3SSebastian Andrzej Siewior 108de30a2b3SIngo Molnar #else 1090995a5dfSThomas Gleixner # define trace_hardirqs_on_prepare() do { } while (0) 110bf2b3008SPeter Zijlstra # define trace_hardirqs_off_finish() do { } while (0) 111de30a2b3SIngo Molnar # define trace_hardirqs_on() do { } while (0) 112de30a2b3SIngo Molnar # define trace_hardirqs_off() do { } while (0) 113f9ad4a5fSPeter Zijlstra # define lockdep_hardirq_context() 0 114ef996916SPeter Zijlstra # define lockdep_softirq_context(p) 0 115f9ad4a5fSPeter Zijlstra # define lockdep_hardirqs_enabled() 0 116ef996916SPeter Zijlstra # define lockdep_softirqs_enabled(p) 0 1172502ec37SThomas Gleixner # define lockdep_hardirq_enter() do { } while (0) 118d5f744f9SLinus Torvalds # define lockdep_hardirq_threaded() do { } while (0) 1192502ec37SThomas Gleixner # define lockdep_hardirq_exit() do { } while (0) 120d820ac4cSIngo Molnar # define lockdep_softirq_enter() do { } while (0) 121d820ac4cSIngo Molnar # define lockdep_softirq_exit() do { } while (0) 12273d20564SSebastian Andrzej Siewior # define lockdep_hrtimer_enter(__hrtimer) false 123c1d11fc2SArnd Bergmann # define lockdep_hrtimer_exit(__context) do { (void)(__context); } while (0) 124d53f2b62SSebastian Andrzej Siewior # define lockdep_posixtimer_enter() do { } while (0) 125d53f2b62SSebastian Andrzej Siewior # define lockdep_posixtimer_exit() do { } while (0) 12649915ac3SSebastian Andrzej Siewior # define lockdep_irq_work_enter(__work) do { } while (0) 12749915ac3SSebastian Andrzej Siewior # define lockdep_irq_work_exit(__work) do { } while (0) 128de30a2b3SIngo Molnar #endif 129de30a2b3SIngo Molnar 1300c1d7a2cSThomas Gleixner #if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PREEMPT_RT) 1310c1d7a2cSThomas Gleixner # define lockdep_softirq_enter() \ 1320c1d7a2cSThomas Gleixner do { \ 1330c1d7a2cSThomas Gleixner current->softirq_context++; \ 1340c1d7a2cSThomas Gleixner } while (0) 1350c1d7a2cSThomas Gleixner # define lockdep_softirq_exit() \ 1360c1d7a2cSThomas Gleixner do { \ 1370c1d7a2cSThomas Gleixner current->softirq_context--; \ 1380c1d7a2cSThomas Gleixner } while (0) 1390c1d7a2cSThomas Gleixner 1400c1d7a2cSThomas Gleixner #else 1410c1d7a2cSThomas Gleixner # define lockdep_softirq_enter() do { } while (0) 1420c1d7a2cSThomas Gleixner # define lockdep_softirq_exit() do { } while (0) 1430c1d7a2cSThomas Gleixner #endif 1440c1d7a2cSThomas Gleixner 1456cd8a4bbSSteven Rostedt #if defined(CONFIG_IRQSOFF_TRACER) || \ 1466cd8a4bbSSteven Rostedt defined(CONFIG_PREEMPT_TRACER) 14781d68a96SSteven Rostedt extern void stop_critical_timings(void); 14881d68a96SSteven Rostedt extern void start_critical_timings(void); 14981d68a96SSteven Rostedt #else 15081d68a96SSteven Rostedt # define stop_critical_timings() do { } while (0) 15181d68a96SSteven Rostedt # define start_critical_timings() do { } while (0) 15281d68a96SSteven Rostedt #endif 15381d68a96SSteven Rostedt 154997acaf6SMark Rutland #ifdef CONFIG_DEBUG_IRQFLAGS 155997acaf6SMark Rutland extern void warn_bogus_irq_restore(void); 156997acaf6SMark Rutland #define raw_check_bogus_irq_restore() \ 157997acaf6SMark Rutland do { \ 158997acaf6SMark Rutland if (unlikely(!arch_irqs_disabled())) \ 159997acaf6SMark Rutland warn_bogus_irq_restore(); \ 160997acaf6SMark Rutland } while (0) 161997acaf6SMark Rutland #else 162997acaf6SMark Rutland #define raw_check_bogus_irq_restore() do { } while (0) 163997acaf6SMark Rutland #endif 164997acaf6SMark Rutland 165df9ee292SDavid Howells /* 166df9ee292SDavid Howells * Wrap the arch provided IRQ routines to provide appropriate checks. 167df9ee292SDavid Howells */ 168df9ee292SDavid Howells #define raw_local_irq_disable() arch_local_irq_disable() 169df9ee292SDavid Howells #define raw_local_irq_enable() arch_local_irq_enable() 170df9ee292SDavid Howells #define raw_local_irq_save(flags) \ 171df9ee292SDavid Howells do { \ 172df9ee292SDavid Howells typecheck(unsigned long, flags); \ 173df9ee292SDavid Howells flags = arch_local_irq_save(); \ 174df9ee292SDavid Howells } while (0) 175df9ee292SDavid Howells #define raw_local_irq_restore(flags) \ 176df9ee292SDavid Howells do { \ 177df9ee292SDavid Howells typecheck(unsigned long, flags); \ 178997acaf6SMark Rutland raw_check_bogus_irq_restore(); \ 179df9ee292SDavid Howells arch_local_irq_restore(flags); \ 180df9ee292SDavid Howells } while (0) 181df9ee292SDavid Howells #define raw_local_save_flags(flags) \ 182df9ee292SDavid Howells do { \ 183df9ee292SDavid Howells typecheck(unsigned long, flags); \ 184df9ee292SDavid Howells flags = arch_local_save_flags(); \ 185df9ee292SDavid Howells } while (0) 186df9ee292SDavid Howells #define raw_irqs_disabled_flags(flags) \ 187df9ee292SDavid Howells ({ \ 188df9ee292SDavid Howells typecheck(unsigned long, flags); \ 189df9ee292SDavid Howells arch_irqs_disabled_flags(flags); \ 190df9ee292SDavid Howells }) 191df9ee292SDavid Howells #define raw_irqs_disabled() (arch_irqs_disabled()) 192df9ee292SDavid Howells #define raw_safe_halt() arch_safe_halt() 193df9ee292SDavid Howells 194df9ee292SDavid Howells /* 195df9ee292SDavid Howells * The local_irq_*() APIs are equal to the raw_local_irq*() 196df9ee292SDavid Howells * if !TRACE_IRQFLAGS. 197df9ee292SDavid Howells */ 198db2dcb4fSJan Beulich #ifdef CONFIG_TRACE_IRQFLAGS 19900b0ed2dSPeter Zijlstra 200de30a2b3SIngo Molnar #define local_irq_enable() \ 20100b0ed2dSPeter Zijlstra do { \ 20200b0ed2dSPeter Zijlstra trace_hardirqs_on(); \ 20300b0ed2dSPeter Zijlstra raw_local_irq_enable(); \ 20400b0ed2dSPeter Zijlstra } while (0) 20500b0ed2dSPeter Zijlstra 206de30a2b3SIngo Molnar #define local_irq_disable() \ 20700b0ed2dSPeter Zijlstra do { \ 208044d0d6dSNicholas Piggin bool was_disabled = raw_irqs_disabled();\ 20900b0ed2dSPeter Zijlstra raw_local_irq_disable(); \ 210044d0d6dSNicholas Piggin if (!was_disabled) \ 21100b0ed2dSPeter Zijlstra trace_hardirqs_off(); \ 21200b0ed2dSPeter Zijlstra } while (0) 21300b0ed2dSPeter Zijlstra 214de30a2b3SIngo Molnar #define local_irq_save(flags) \ 2153f307891SSteven Rostedt do { \ 2163f307891SSteven Rostedt raw_local_irq_save(flags); \ 217044d0d6dSNicholas Piggin if (!raw_irqs_disabled_flags(flags)) \ 2183f307891SSteven Rostedt trace_hardirqs_off(); \ 2193f307891SSteven Rostedt } while (0) 2203f307891SSteven Rostedt 221de30a2b3SIngo Molnar #define local_irq_restore(flags) \ 222de30a2b3SIngo Molnar do { \ 223044d0d6dSNicholas Piggin if (!raw_irqs_disabled_flags(flags)) \ 224de30a2b3SIngo Molnar trace_hardirqs_on(); \ 225de30a2b3SIngo Molnar raw_local_irq_restore(flags); \ 226de30a2b3SIngo Molnar } while (0) 227df9ee292SDavid Howells 228de30a2b3SIngo Molnar #define safe_halt() \ 229de30a2b3SIngo Molnar do { \ 230de30a2b3SIngo Molnar trace_hardirqs_on(); \ 231de30a2b3SIngo Molnar raw_safe_halt(); \ 232de30a2b3SIngo Molnar } while (0) 233de30a2b3SIngo Molnar 234df9ee292SDavid Howells 235db2dcb4fSJan Beulich #else /* !CONFIG_TRACE_IRQFLAGS */ 236df9ee292SDavid Howells 237df9ee292SDavid Howells #define local_irq_enable() do { raw_local_irq_enable(); } while (0) 238df9ee292SDavid Howells #define local_irq_disable() do { raw_local_irq_disable(); } while (0) 23900b0ed2dSPeter Zijlstra #define local_irq_save(flags) do { raw_local_irq_save(flags); } while (0) 240df9ee292SDavid Howells #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0) 241df9ee292SDavid Howells #define safe_halt() do { raw_safe_halt(); } while (0) 242de30a2b3SIngo Molnar 243db2dcb4fSJan Beulich #endif /* CONFIG_TRACE_IRQFLAGS */ 244db2dcb4fSJan Beulich 245db2dcb4fSJan Beulich #define local_save_flags(flags) raw_local_save_flags(flags) 246db2dcb4fSJan Beulich 247db2dcb4fSJan Beulich /* 248db2dcb4fSJan Beulich * Some architectures don't define arch_irqs_disabled(), so even if either 249db2dcb4fSJan Beulich * definition would be fine we need to use different ones for the time being 250db2dcb4fSJan Beulich * to avoid build issues. 251db2dcb4fSJan Beulich */ 252db2dcb4fSJan Beulich #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT 253db2dcb4fSJan Beulich #define irqs_disabled() \ 254db2dcb4fSJan Beulich ({ \ 255db2dcb4fSJan Beulich unsigned long _flags; \ 256db2dcb4fSJan Beulich raw_local_save_flags(_flags); \ 257db2dcb4fSJan Beulich raw_irqs_disabled_flags(_flags); \ 258db2dcb4fSJan Beulich }) 259db2dcb4fSJan Beulich #else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ 260db2dcb4fSJan Beulich #define irqs_disabled() raw_irqs_disabled() 26140b1f4e5SMichael Neuling #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ 262de30a2b3SIngo Molnar 263db2dcb4fSJan Beulich #define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) 264db2dcb4fSJan Beulich 26554da6a09SPeter Zijlstra DEFINE_LOCK_GUARD_0(irq, local_irq_disable(), local_irq_enable()) 26654da6a09SPeter Zijlstra DEFINE_LOCK_GUARD_0(irqsave, 26754da6a09SPeter Zijlstra local_irq_save(_T->flags), 26854da6a09SPeter Zijlstra local_irq_restore(_T->flags), 26954da6a09SPeter Zijlstra unsigned long flags) 27054da6a09SPeter Zijlstra 271de30a2b3SIngo Molnar #endif 272