2 * Copyright (C) 2009 Imagination Technologies
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive
8 * The Meta KICK interrupt mechanism is generally a useful feature, so
9 * we provide an interface for registering multiple interrupt
10 * handlers. All the registered interrupt handlers are "chained". When
11 * a KICK interrupt is received the first function in the list is
12 * called. If that interrupt handler cannot handle the KICK the next
13 * one is called, then the next until someone handles it (or we run
14 * out of functions). As soon as one function handles the interrupt no
15 * other handlers are called.
17 * The only downside of chaining interrupt handlers is that each
18 * handler must be able to detect whether the KICK was intended for it
19 * or not. For example, when the IPI handler runs and it sees that
20 * there are no IPI messages it must not signal that the KICK was
21 * handled, thereby giving the other handlers a chance to run.
23 * The reason that we provide our own interface for calling KICK
24 * handlers instead of using the generic kernel infrastructure is that
25 * the KICK handlers require access to a CPU's pTBI structure. So we
26 * pass it as an argument.
28 #include <linux/export.h>
29 #include <linux/hardirq.h>
30 #include <linux/irq.h>
31 #include <linux/kernel.h>
33 #include <linux/types.h>
35 #include <asm/traps.h>
38 * All accesses/manipulations of kick_handlers_list should be
39 * performed while holding kick_handlers_lock.
41 static DEFINE_SPINLOCK(kick_handlers_lock
);
42 static LIST_HEAD(kick_handlers_list
);
44 void kick_register_func(struct kick_irq_handler
*kh
)
48 spin_lock_irqsave(&kick_handlers_lock
, flags
);
50 list_add_tail(&kh
->list
, &kick_handlers_list
);
52 spin_unlock_irqrestore(&kick_handlers_lock
, flags
);
54 EXPORT_SYMBOL(kick_register_func
);
56 void kick_unregister_func(struct kick_irq_handler
*kh
)
60 spin_lock_irqsave(&kick_handlers_lock
, flags
);
64 spin_unlock_irqrestore(&kick_handlers_lock
, flags
);
66 EXPORT_SYMBOL(kick_unregister_func
);
69 kick_handler(TBIRES State
, int SigNum
, int Triggers
, int Inst
, PTBI pTBI
)
71 struct pt_regs
*old_regs
;
72 struct kick_irq_handler
*kh
;
77 head_end(State
, ~INTS_OFF_MASK
);
79 /* If we interrupted user code handle any critical sections. */
80 if (State
.Sig
.SaveMask
& TBICTX_PRIV_BIT
)
81 restart_critical_section(State
);
85 old_regs
= set_irq_regs((struct pt_regs
*)State
.Sig
.pCtx
);
89 * There is no need to disable interrupts here because we
90 * can't nest KICK interrupts in a KICK interrupt handler.
92 spin_lock(&kick_handlers_lock
);
94 list_for_each(lh
, &kick_handlers_list
) {
95 kh
= list_entry(lh
, struct kick_irq_handler
, list
);
97 ret
= kh
->func(State
, SigNum
, Triggers
, Inst
, pTBI
, &handled
);
102 spin_unlock(&kick_handlers_lock
);
107 set_irq_regs(old_regs
);
109 return tail_end(ret
);