Original kernel 2.4.37.5
[tomato.git] / release / src / linux / linux / arch / alpha / kernel / irq_smp.c
blob37f866966c5be8f87f463f247ac31a230ceb908a
1 /*
2 * linux/arch/alpha/kernel/irq_smp.c
4 */
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>
16 #include <asm/io.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
31 static void
32 show(char * str, void *where)
34 #if 0
35 int i;
36 unsigned long *stack;
37 #endif
38 int cpu = smp_processor_id();
40 printk("\n%s, CPU %d: %p\n", str, cpu, where);
41 printk("irq: %d [%d %d]\n",
42 irqs_running(),
43 local_irq_count(0),
44 local_irq_count(1));
46 printk("bh: %d [%d %d]\n",
47 spin_is_locked(&global_bh_lock) ? 1 : 0,
48 local_bh_count(0),
49 local_bh_count(1));
50 #if 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);
59 #endif
62 static inline void
63 wait_on_irq(int cpu, void *where)
65 int count = MAXCOUNT;
67 for (;;) {
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))
77 break;
80 /* Duh, we have to loop. Release the lock to avoid deadlocks */
81 spin_unlock(&global_irq_lock);
83 for (;;) {
84 if (!--count) {
85 show("wait_on_irq", where);
86 count = MAXCOUNT;
88 __sti();
89 udelay(1); /* make sure to run pending irqs */
90 __cli();
92 if (irqs_running())
93 continue;
94 if (spin_is_locked(&global_irq_lock))
95 continue;
96 if (!local_bh_count(cpu)
97 && spin_is_locked(&global_bh_lock))
98 continue;
99 if (spin_trylock(&global_irq_lock))
100 break;
105 static inline void
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)
111 return;
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);
125 * Finally.
127 #ifdef CONFIG_DEBUG_SPINLOCK
128 global_irq_lock.task = current;
129 global_irq_lock.previous = where;
130 #endif
131 global_irq_holder = cpu;
132 previous_irqholder = where;
135 void
136 __global_cli(void)
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);
149 void
150 __global_sti(void)
152 int cpu = smp_processor_id();
154 if (!local_irq_count(cpu))
155 release_irqlock(cpu);
156 __sti();
160 * SMP flags value to restore to:
161 * 0 - global cli
162 * 1 - global sti
163 * 2 - local cli
164 * 3 - local sti
166 unsigned long
167 __global_save_flags(void)
169 int retval;
170 int local_enabled;
171 unsigned long flags;
172 int cpu = smp_processor_id();
174 __save_flags(flags);
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)) {
181 if (local_enabled)
182 retval = 1;
183 if (global_irq_holder == cpu)
184 retval = 0;
186 return retval;
189 void
190 __global_restore_flags(unsigned long flags)
192 switch (flags) {
193 case 0:
194 __global_cli();
195 break;
196 case 1:
197 __global_sti();
198 break;
199 case 2:
200 __cli();
201 break;
202 case 3:
203 __sti();
204 break;
205 default:
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.
218 * --jmartin
220 #define DEBUG_SYNCHRONIZE_IRQ 0
222 void
223 synchronize_irq(void)
225 #if 0
226 /* Joe's version. */
227 int cpu = smp_processor_id();
228 int local_count;
229 int global_count;
230 int countdown = 1<<24;
231 void *where = __builtin_return_address(0);
233 mb();
234 do {
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);
240 break;
242 } while (global_count != local_count);
243 #else
244 /* Jay's version. */
245 if (irqs_running()) {
246 cli();
247 sti();
249 #endif