1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __LINUX_INTERRUPT_RC_H 3 #define __LINUX_INTERRUPT_RC_H 4 5 /* 6 * include/linux/interrupt_rc.h - refcounted local processor interrupt 7 * management. 8 * 9 * Since the implementation of this API currently depends on 10 * local_irq_save()/local_irq_restore(), we split this into its own header to 11 * make it easier to include without hitting circular header dependencies. 12 */ 13 14 #include <linux/irqflags.h> 15 #include <linux/preempt.h> 16 #include <linux/processor.h> 17 #include <linux/smp.h> 18 19 #ifndef MODULE 20 /* Per-CPU interrupt disabling state for local_interrupt_{disable,enable}(). */ 21 DECLARE_PER_CPU(unsigned long, local_interrupt_disable_state); 22 __local_interrupt_save_state(unsigned long flags)23static __always_inline void __local_interrupt_save_state(unsigned long flags) 24 { 25 raw_cpu_write(local_interrupt_disable_state, flags); 26 } 27 __local_interrupt_enable(void)28static __always_inline void __local_interrupt_enable(void) 29 { 30 unsigned long flags = raw_cpu_read(local_interrupt_disable_state); 31 32 local_irq_restore(flags); 33 } 34 35 #ifndef INSTANTIATE_EXPORTED_INTERRUPT_DISABLE _local_interrupt_save_state(unsigned long flags)36static __always_inline void _local_interrupt_save_state(unsigned long flags) 37 { 38 __local_interrupt_save_state(flags); 39 } 40 _local_interrupt_enable(void)41static __always_inline void _local_interrupt_enable(void) 42 { 43 __local_interrupt_enable(); 44 } 45 #else 46 extern void _local_interrupt_save_state(unsigned long flags); 47 extern void _local_interrupt_enable(void); 48 #endif 49 50 #else /* !MODULE */ 51 extern void _local_interrupt_save_state(unsigned long flags); 52 extern void _local_interrupt_enable(void); 53 #endif /* !MODULE */ 54 55 #define hardirq_disable_enter() __preempt_count_add_return(HARDIRQ_DISABLE_OFFSET) 56 #define hardirq_disable_exit() __preempt_count_sub_return(HARDIRQ_DISABLE_OFFSET) 57 local_interrupt_disable(void)58static inline void local_interrupt_disable(void) 59 { 60 int new_count; 61 unsigned long flags; 62 63 WARN_ON_ONCE(in_nmi()); 64 65 local_irq_save(flags); 66 new_count = hardirq_disable_enter(); 67 68 if ((new_count & HARDIRQ_DISABLE_MASK) == HARDIRQ_DISABLE_OFFSET) 69 _local_interrupt_save_state(flags); 70 } 71 local_interrupt_enable(void)72static inline void local_interrupt_enable(void) 73 { 74 int new_count; 75 76 new_count = hardirq_disable_exit(); 77 78 if ((new_count & HARDIRQ_DISABLE_MASK) == 0) 79 _local_interrupt_enable(); 80 } 81 82 #endif /* !__LINUX_INTERRUPT_RC_H */ 83