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>
This commit is contained in:
parent
9649814432
commit
f6b30d32d2
@ -26,6 +26,8 @@
|
|||||||
* pass it as an argument.
|
* pass it as an argument.
|
||||||
*/
|
*/
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
@ -66,6 +68,7 @@ EXPORT_SYMBOL(kick_unregister_func);
|
|||||||
TBIRES
|
TBIRES
|
||||||
kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
|
kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
|
||||||
{
|
{
|
||||||
|
struct pt_regs *old_regs;
|
||||||
struct kick_irq_handler *kh;
|
struct kick_irq_handler *kh;
|
||||||
struct list_head *lh;
|
struct list_head *lh;
|
||||||
int handled = 0;
|
int handled = 0;
|
||||||
@ -79,6 +82,9 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
|
|||||||
|
|
||||||
trace_hardirqs_off();
|
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
|
* There is no need to disable interrupts here because we
|
||||||
* can't nest KICK interrupts in a KICK interrupt handler.
|
* 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);
|
WARN_ON(!handled);
|
||||||
|
|
||||||
|
irq_exit();
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
|
||||||
return tail_end(ret);
|
return tail_end(ret);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user