2 * linux/arch/alpha/kernel/irq_smp.c
6 #include <linux/kernel.h>
7 #include <linux/signal.h>
8 #include <linux/sched.h>
9 #include <linux/interrupt.h>
10 #include <linux/random.h>
11 #include <linux/init.h>
12 #include <linux/delay.h>
13 #include <linux/irq.h>
15 #include <asm/system.h>
19 /* Who has global_irq_lock. */
20 int global_irq_holder
= NO_PROC_ID
;
22 /* This protects IRQ's. */
23 spinlock_t global_irq_lock
= SPIN_LOCK_UNLOCKED
;
25 /* Global IRQ locking depth. */
26 static void *previous_irqholder
= NULL
;
28 #define MAXCOUNT 100000000
32 show(char * str
, void *where
)
38 int cpu
= smp_processor_id();
40 printk("\n%s, CPU %d: %p\n", str
, cpu
, where
);
41 printk("irq: %d [%d %d]\n",
46 printk("bh: %d [%d %d]\n",
47 spin_is_locked(&global_bh_lock
) ? 1 : 0,
51 stack
= (unsigned long *) &str
;
52 for (i
= 40; i
; i
--) {
53 unsigned long x
= *++stack
;
54 if (x
> (unsigned long) &init_task_union
&&
55 x
< (unsigned long) &vsprintf
) {
56 printk("<[%08lx]> ", x
);
63 wait_on_irq(int cpu
, void *where
)
70 * Wait until all interrupts are gone. Wait
71 * for bottom half handlers unless we're
72 * already executing in one..
74 if (!irqs_running()) {
75 if (local_bh_count(cpu
)
76 || !spin_is_locked(&global_bh_lock
))
80 /* Duh, we have to loop. Release the lock to avoid deadlocks */
81 spin_unlock(&global_irq_lock
);
85 show("wait_on_irq", where
);
89 udelay(1); /* make sure to run pending irqs */
94 if (spin_is_locked(&global_irq_lock
))
96 if (!local_bh_count(cpu
)
97 && spin_is_locked(&global_bh_lock
))
99 if (spin_trylock(&global_irq_lock
))
106 get_irqlock(int cpu
, void* where
)
108 if (!spin_trylock(&global_irq_lock
)) {
109 /* Do we already hold the lock? */
110 if (cpu
== global_irq_holder
)
112 /* Uhhuh.. Somebody else got it. Wait. */
113 spin_lock(&global_irq_lock
);
117 * Ok, we got the lock bit.
118 * But that's actually just the easy part.. Now
119 * we need to make sure that nobody else is running
120 * in an interrupt context.
122 wait_on_irq(cpu
, where
);
127 #ifdef CONFIG_DEBUG_SPINLOCK
128 global_irq_lock
.task
= current
;
129 global_irq_lock
.previous
= where
;
131 global_irq_holder
= cpu
;
132 previous_irqholder
= where
;
138 int cpu
= smp_processor_id();
139 void *where
= __builtin_return_address(0);
142 * Maximize ipl. If ipl was previously 0 and if this thread
143 * is not in an irq, then take global_irq_lock.
145 if (swpipl(IPL_MAX
) == IPL_MIN
&& !local_irq_count(cpu
))
146 get_irqlock(cpu
, where
);
152 int cpu
= smp_processor_id();
154 if (!local_irq_count(cpu
))
155 release_irqlock(cpu
);
160 * SMP flags value to restore to:
167 __global_save_flags(void)
172 int cpu
= smp_processor_id();
175 local_enabled
= (!(flags
& 7));
176 /* default to local */
177 retval
= 2 + local_enabled
;
179 /* Check for global flags if we're not in an interrupt. */
180 if (!local_irq_count(cpu
)) {
183 if (global_irq_holder
== cpu
)
190 __global_restore_flags(unsigned long flags
)
206 printk(KERN_ERR
"global_restore_flags: %08lx (%p)\n",
207 flags
, __builtin_return_address(0));
212 * From its use, I infer that synchronize_irq() stalls a thread until
213 * the effects of a command to an external device are known to have
214 * taken hold. Typically, the command is to stop sending interrupts.
215 * The strategy here is wait until there is at most one processor
216 * (this one) in an irq. The memory barrier serializes the write to
217 * the device and the subsequent accesses of global_irq_count.
220 #define DEBUG_SYNCHRONIZE_IRQ 0
223 synchronize_irq(void)
227 int cpu
= smp_processor_id();
230 int countdown
= 1<<24;
231 void *where
= __builtin_return_address(0);
235 local_count
= local_irq_count(cpu
);
236 global_count
= atomic_read(&global_irq_count
);
237 if (DEBUG_SYNCHRONIZE_IRQ
&& (--countdown
== 0)) {
238 printk("%d:%d/%d\n", cpu
, local_count
, global_count
);
239 show("synchronize_irq", where
);
242 } while (global_count
!= local_count
);
245 if (irqs_running()) {