From 097f9cf735ffa1212b828682ad92f0f6c5f1c552 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 11 Nov 2019 23:50:03 +0100 Subject: irq: Add disabling counter * linux/dev/arch/i386/kernel/irq.c (ndisabled_irq): New array. (__disable_irq, __enable_irq): New functions, count with ndisabled_irq before really calling mask_irq/unmask_irq. (linux_pic_mask): New variable. (disable_irq, enable_irq): Manage linux_pic_mask and call __disable_irq/__enable_irq instead of calling mask_irq/unmask_irq. * linux/src/include/asm-i386/irq.h (__disable_irq, __enable_irq): New prototypes. --- linux/dev/arch/i386/kernel/irq.c | 55 +++++++++++++++++++++++++++++++++++++--- linux/src/include/asm-i386/irq.h | 2 ++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c index 75f8f812..18448638 100644 --- a/linux/dev/arch/i386/kernel/irq.c +++ b/linux/dev/arch/i386/kernel/irq.c @@ -158,8 +158,13 @@ unmask_irq (unsigned int irq_nr) } } +/* Count how many subsystems requested to disable each IRQ */ +static unsigned ndisabled_irq[NR_IRQS]; + +/* These disable/enable IRQs for real after counting how many subsystems + * requested that */ void -disable_irq (unsigned int irq_nr) +__disable_irq (unsigned int irq_nr) { unsigned long flags; @@ -167,12 +172,15 @@ disable_irq (unsigned int irq_nr) save_flags (flags); cli (); - mask_irq (irq_nr); + ndisabled_irq[irq_nr]++; + assert (ndisabled_irq[irq_nr] > 0); + if (ndisabled_irq[irq_nr] == 1) + mask_irq (irq_nr); restore_flags (flags); } void -enable_irq (unsigned int irq_nr) +__enable_irq (unsigned int irq_nr) { unsigned long flags; @@ -180,7 +188,46 @@ enable_irq (unsigned int irq_nr) save_flags (flags); cli (); - unmask_irq (irq_nr); + assert (ndisabled_irq[irq_nr] > 0); + ndisabled_irq[irq_nr]--; + if (ndisabled_irq[irq_nr] == 0) + unmask_irq (irq_nr); + restore_flags (flags); +} + +/* IRQ mask according to Linux drivers */ +static unsigned linux_pic_mask; + +/* These only record that Linux requested to mask IRQs */ +void +disable_irq (unsigned int irq_nr) +{ + unsigned long flags; + unsigned mask = 1U << irq_nr; + + save_flags (flags); + cli (); + if (!(linux_pic_mask & mask)) + { + linux_pic_mask |= mask; + __disable_irq(irq_nr); + } + restore_flags (flags); +} + +void +enable_irq (unsigned int irq_nr) +{ + unsigned long flags; + unsigned mask = 1U << irq_nr; + + save_flags (flags); + cli (); + if (linux_pic_mask & mask) + { + linux_pic_mask &= ~mask; + __enable_irq(irq_nr); + } restore_flags (flags); } diff --git a/linux/src/include/asm-i386/irq.h b/linux/src/include/asm-i386/irq.h index c75744a5..d7d1e3c5 100644 --- a/linux/src/include/asm-i386/irq.h +++ b/linux/src/include/asm-i386/irq.h @@ -16,6 +16,8 @@ #define TIMER_IRQ 0 +extern void __disable_irq(unsigned int); +extern void __enable_irq(unsigned int); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -- cgit v1.2.3