aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2013-07-01 08:44:10 -0400
committerJames Hogan <james.hogan@imgtec.com>2013-07-02 09:12:08 -0400
commitf6b30d32d242243a967993789c4cf550d840727e (patch)
tree95369d42eb77261e5f31b7908ee97af9e2f6a73e
parent9649814432faa9016952895684120942da0d8481 (diff)
metag: kick: add missing irq_enter/exit to kick_handler()
kick_handler() doesn't have an irq_enter/exit pair, but it's used for handling SMP IPIs which require work to be done in softirqs, which are invoked from irq_exit() when the hard irq nest count reaches 0. The scheduler_ipi() callback in the IPI handler calls irq_enter/exit itself, but this is inside kick_handler()'s spin lock critical section, so if an invoked softirq issues an IPI the kick_handler() will be re-entered on the same CPU and will deadlock. This is easily fixed by adding the missing irq_enter/exit to kick_handler() so that the hard irq nest count doesn't reach 0 until after the spin lock has been released. Ideally the spin lock protected handler list will also be replaced by a lockless RCU protected list since it is certainly mostly read. That can be done in a later change though. Signed-off-by: James Hogan <james.hogan@imgtec.com> Acked-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/metag/kernel/kick.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/metag/kernel/kick.c b/arch/metag/kernel/kick.c
index 50fcbec98cd2..beb377621322 100644
--- a/arch/metag/kernel/kick.c
+++ b/arch/metag/kernel/kick.c
@@ -26,6 +26,8 @@
26 * pass it as an argument. 26 * pass it as an argument.
27 */ 27 */
28#include <linux/export.h> 28#include <linux/export.h>
29#include <linux/hardirq.h>
30#include <linux/irq.h>
29#include <linux/kernel.h> 31#include <linux/kernel.h>
30#include <linux/mm.h> 32#include <linux/mm.h>
31#include <linux/types.h> 33#include <linux/types.h>
@@ -66,6 +68,7 @@ EXPORT_SYMBOL(kick_unregister_func);
66TBIRES 68TBIRES
67kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI) 69kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
68{ 70{
71 struct pt_regs *old_regs;
69 struct kick_irq_handler *kh; 72 struct kick_irq_handler *kh;
70 struct list_head *lh; 73 struct list_head *lh;
71 int handled = 0; 74 int handled = 0;
@@ -79,6 +82,9 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
79 82
80 trace_hardirqs_off(); 83 trace_hardirqs_off();
81 84
85 old_regs = set_irq_regs((struct pt_regs *)State.Sig.pCtx);
86 irq_enter();
87
82 /* 88 /*
83 * There is no need to disable interrupts here because we 89 * There is no need to disable interrupts here because we
84 * can't nest KICK interrupts in a KICK interrupt handler. 90 * can't nest KICK interrupts in a KICK interrupt handler.
@@ -97,5 +103,8 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
97 103
98 WARN_ON(!handled); 104 WARN_ON(!handled);
99 105
106 irq_exit();
107 set_irq_regs(old_regs);
108
100 return tail_end(ret); 109 return tail_end(ret);
101} 110}