From: James Hogan Date: Mon, 1 Jul 2013 12:44:10 +0000 (+0100) Subject: metag: kick: add missing irq_enter/exit to kick_handler() X-Git-Tag: v3.11-rc1~79^2~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f6b30d32d242243a967993789c4cf550d840727e;p=platform%2Fupstream%2Fkernel-adaptation-pc.git 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 Acked-by: Thomas Gleixner --- diff --git a/arch/metag/kernel/kick.c b/arch/metag/kernel/kick.c index 50fcbec..beb3776 100644 --- a/arch/metag/kernel/kick.c +++ b/arch/metag/kernel/kick.c @@ -26,6 +26,8 @@ * pass it as an argument. */ #include +#include +#include #include #include #include @@ -66,6 +68,7 @@ EXPORT_SYMBOL(kick_unregister_func); TBIRES kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI) { + struct pt_regs *old_regs; struct kick_irq_handler *kh; struct list_head *lh; int handled = 0; @@ -79,6 +82,9 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI) trace_hardirqs_off(); + old_regs = set_irq_regs((struct pt_regs *)State.Sig.pCtx); + irq_enter(); + /* * There is no need to disable interrupts here because we * 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) WARN_ON(!handled); + irq_exit(); + set_irq_regs(old_regs); + return tail_end(ret); }