summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2019-11-11 23:50:03 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2019-11-12 00:00:14 +0100
commit097f9cf735ffa1212b828682ad92f0f6c5f1c552 (patch)
tree69c228c18d9c813d83e685bcccc91b87b9e2a6ef
parent1fc9b4b56e8425f5f68c019b511189f25c82c122 (diff)
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.
-rw-r--r--linux/dev/arch/i386/kernel/irq.c55
-rw-r--r--linux/src/include/asm-i386/irq.h2
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);