lin
2025-03-21 36aaa54056c4f4e150f6ee0636610d9a68470a08
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 *  Copyright (C) 2009 Imagination Technologies
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 * The Meta KICK interrupt mechanism is generally a useful feature, so
 * we provide an interface for registering multiple interrupt
 * handlers. All the registered interrupt handlers are "chained". When
 * a KICK interrupt is received the first function in the list is
 * called. If that interrupt handler cannot handle the KICK the next
 * one is called, then the next until someone handles it (or we run
 * out of functions). As soon as one function handles the interrupt no
 * other handlers are called.
 *
 * The only downside of chaining interrupt handlers is that each
 * handler must be able to detect whether the KICK was intended for it
 * or not.  For example, when the IPI handler runs and it sees that
 * there are no IPI messages it must not signal that the KICK was
 * handled, thereby giving the other handlers a chance to run.
 *
 * The reason that we provide our own interface for calling KICK
 * handlers instead of using the generic kernel infrastructure is that
 * the KICK handlers require access to a CPU's pTBI structure. So we
 * pass it as an argument.
 */
#include <linux/export.h>
#include <linux/hardirq.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/types.h>
 
#include <asm/traps.h>
 
/*
 * All accesses/manipulations of kick_handlers_list should be
 * performed while holding kick_handlers_lock.
 */
static DEFINE_SPINLOCK(kick_handlers_lock);
static LIST_HEAD(kick_handlers_list);
 
void kick_register_func(struct kick_irq_handler *kh)
{
   unsigned long flags;
 
   spin_lock_irqsave(&kick_handlers_lock, flags);
 
   list_add_tail(&kh->list, &kick_handlers_list);
 
   spin_unlock_irqrestore(&kick_handlers_lock, flags);
}
EXPORT_SYMBOL(kick_register_func);
 
void kick_unregister_func(struct kick_irq_handler *kh)
{
   unsigned long flags;
 
   spin_lock_irqsave(&kick_handlers_lock, flags);
 
   list_del(&kh->list);
 
   spin_unlock_irqrestore(&kick_handlers_lock, flags);
}
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;
   TBIRES ret;
 
   head_end(State, ~INTS_OFF_MASK);
 
   /* If we interrupted user code handle any critical sections. */
   if (State.Sig.SaveMask & TBICTX_PRIV_BIT)
       restart_critical_section(State);
 
   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.
    */
   spin_lock(&kick_handlers_lock);
 
   list_for_each(lh, &kick_handlers_list) {
       kh = list_entry(lh, struct kick_irq_handler, list);
 
       ret = kh->func(State, SigNum, Triggers, Inst, pTBI, &handled);
       if (handled)
           break;
   }
 
   spin_unlock(&kick_handlers_lock);
 
   WARN_ON(!handled);
 
   irq_exit();
   set_irq_regs(old_regs);
 
   return tail_end(ret);
}