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