summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChris Dearman <chris@mips.com>2007-03-26 14:48:50 +0100
committerRalf Baechle <ralf@linux-mips.org>2007-03-29 23:46:35 +0100
commitfe99f1b184efb75c50dd8cbdfff99b559c2cb3b3 (patch)
tree7baefefa620815b1d585af092e87c03a5ffdda17 /arch
parentcbde5ebc972c0577741a69c85d5e5afad19d813b (diff)
[MIPS] lockdep: Deal with interrupt disable hazard in TRACE_IRQFLAGS
Between the mtc0 or di instruction that disables interrupts and the following hazard barrier a processor may still take interrupts. If an interrupt is taken after interrupts are disabled but before the state is updated it will appear to restore_all that it is incorrectly returning with interrupts disabled. Signed-off-by: Chris Dearman <chris@mips.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/kernel/genex.S31
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 83843a229be..297bd56c234 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -128,6 +128,37 @@ handle_vcei:
.align 5
NESTED(handle_int, PT_SIZE, sp)
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /*
+ * Check to see if the interrupted code has just disabled
+ * interrupts and ignore this interrupt for now if so.
+ *
+ * local_irq_disable() disables interrupts and then calls
+ * trace_hardirqs_off() to track the state. If an interrupt is taken
+ * after interrupts are disabled but before the state is updated
+ * it will appear to restore_all that it is incorrectly returning with
+ * interrupts disabled
+ */
+ .set push
+ .set noat
+ mfc0 k0, CP0_STATUS
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+ and k0, ST0_IEP
+ bnez k0, 1f
+
+ mfc0 k0, EP0_EPC
+ .set noreorder
+ j k0
+ rfe
+#else
+ and k0, ST0_IE
+ bnez k0, 1f
+
+ eret
+#endif
+1:
+ .set pop
+#endif
SAVE_ALL
CLI
TRACE_IRQS_OFF