File: /usr/src/linux/arch/ia64/sn/sn1/sv.c
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2000 Silicon Graphics, Inc. All rights reserved
7 *
8 * This implemenation of synchronization variables is heavily based on
9 * one done by Steve Lord <lord@sgi.com>
10 *
11 * Paul Cassella <pwc@sgi.com>
12 */
13
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/init.h>
17
18 #include <asm/semaphore.h>
19 #include <asm/hardirq.h>
20 #include <asm/softirq.h>
21 #include <asm/current.h>
22
23 #include <asm/sn/sv.h>
24
25 /* Define this to have sv_test() run some simple tests.
26 kernel_thread() must behave as expected when this is called. */
27 #undef RUN_SV_TEST
28
29 #define DEBUG
30
31 /* Set up some macros so sv_wait(), sv_signal(), and sv_broadcast()
32 can sanity check interrupt state on architectures where we know
33 how. */
34 #ifdef DEBUG
35 #define SV_DEBUG_INTERRUPT_STATE
36 #ifdef __mips64
37 #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x1) != 0)
38 #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x1) == 0)
39 #define SV_INTERRUPT_TEST_WORKERS 31
40 #elif defined(__ia64)
41 #define SV_TEST_INTERRUPTS_ENABLED(flags) ((flags & 0x4000) != 0)
42 #define SV_TEST_INTERRUPTS_DISABLED(flags) ((flags & 0x4000) == 0)
43 #define SV_INTERRUPT_TEST_WORKERS 4 /* simulator's slow */
44 #else
45 #undef SV_DEBUG_INTERRUPT_STATE
46 #define SV_INTERRUPT_TEST_WORKERS 4 /* reasonable? default. */
47 #endif /* __mips64 */
48 #endif /* DEBUG */
49
50
51 /* XXX FIXME hack hack hack. Our mips64 tree is from before the
52 switch to WQ_FLAG_EXCLUSIVE, and our ia64 tree is from after it. */
53 #ifdef TASK_EXCLUSIVE
54 #undef EXCLUSIVE_IN_QUEUE
55 #else
56 #define EXCLUSIVE_IN_QUEUE
57 #define TASK_EXCLUSIVE 0 /* for the set_current_state() in sv_wait() */
58 #endif
59
60
61 static inline void sv_lock(sv_t *sv) {
62 spin_lock(&sv->sv_lock);
63 }
64
65 static inline void sv_unlock(sv_t *sv) {
66 spin_unlock(&sv->sv_lock);
67 }
68
69 /* up() is "extern inline", so we can't pass its address to sv_wait.
70 Use this function's address instead. */
71 static void up_wrapper(struct semaphore *sem) {
72 up(sem);
73 }
74
75 /* spin_unlock() is sometimes a macro. */
76 static void spin_unlock_wrapper(spinlock_t *s) {
77 spin_unlock(s);
78 }
79
80 /* XXX Perhaps sv_wait() should do the switch() each time and avoid
81 the extra indirection and the need for the _wrapper functions? */
82
83 static inline void sv_set_mon_type(sv_t *sv, int type) {
84 switch (type) {
85 case SV_MON_SPIN:
86 sv->sv_mon_unlock_func =
87 (sv_mon_unlock_func_t)spin_unlock_wrapper;
88 break;
89 case SV_MON_SEMA:
90 sv->sv_mon_unlock_func =
91 (sv_mon_unlock_func_t)up_wrapper;
92 if(sv->sv_flags & SV_INTS) {
93 printk(KERN_ERR "sv_set_mon_type: The monitor lock "
94 "cannot be shared with interrupts if it is a "
95 "semaphore!\n");
96 BUG();
97 }
98 if(sv->sv_flags & SV_BHS) {
99 printk(KERN_ERR "sv_set_mon_type: The monitor lock "
100 "cannot be shared with bottom-halves if it is "
101 "a semaphore!\n");
102 BUG();
103 }
104 break;
105 #if 0
106 /*
107 * If needed, and will need to think about interrupts. This
108 * may be needed, for example, if someone wants to use sv's
109 * with something like dev_base; writers need to hold two
110 * locks.
111 */
112 case SV_MON_CUSTOM:
113 {
114 struct sv_mon_custom *c = lock;
115 sv->sv_mon_unlock_func = c->sv_mon_unlock_func;
116 sv->sv_mon_lock = c->sv_mon_lock;
117 break;
118 }
119 #endif
120
121 default:
122 printk(KERN_ERR "sv_set_mon_type: unknown type %d (0x%x)! "
123 "(flags 0x%x)\n", type, type, sv->sv_flags);
124 BUG();
125 break;
126 }
127 sv->sv_flags |= type;
128 }
129
130 static inline void sv_set_ord(sv_t *sv, int ord) {
131 if (!ord)
132 ord = SV_ORDER_DEFAULT;
133
134 if (ord != SV_ORDER_FIFO && ord != SV_ORDER_LIFO) {
135 printk(KERN_EMERG "sv_set_ord: unknown order %d (0x%x)! ",
136 ord, ord);
137 BUG();
138 }
139
140 sv->sv_flags |= ord;
141 }
142
143 void sv_init(sv_t *sv, sv_mon_lock_t *lock, int flags)
144 {
145 int ord = flags & SV_ORDER_MASK;
146 int type = flags & SV_MON_MASK;
147
148 /* Copy all non-order, non-type flags */
149 sv->sv_flags = (flags & ~(SV_ORDER_MASK | SV_MON_MASK));
150
151 if((sv->sv_flags & (SV_INTS | SV_BHS)) == (SV_INTS | SV_BHS)) {
152 printk(KERN_ERR "sv_init: do not set both SV_INTS and SV_BHS, only SV_INTS.\n");
153 BUG();
154 }
155
156 sv_set_ord(sv, ord);
157 sv_set_mon_type(sv, type);
158
159 /* If lock is NULL, we'll get it from sv_wait_compat() (and
160 ignore it in sv_signal() and sv_broadcast()). */
161 sv->sv_mon_lock = lock;
162
163 spin_lock_init(&sv->sv_lock);
164 init_waitqueue_head(&sv->sv_waiters);
165 }
166
167 /*
168 * The associated lock must be locked on entry. It is unlocked on return.
169 *
170 * Return values:
171 *
172 * n < 0 : interrupted, -n jiffies remaining on timeout, or -1 if timeout == 0
173 * n = 0 : timeout expired
174 * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0
175 */
176 signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout)
177 {
178 DECLARE_WAITQUEUE( wait, current );
179 unsigned long flags;
180 signed long ret = 0;
181
182 #ifdef SV_DEBUG_INTERRUPT_STATE
183 {
184 unsigned long flags;
185 __save_flags(flags);
186
187 if(sv->sv_flags & SV_INTS) {
188 if(SV_TEST_INTERRUPTS_ENABLED(flags)) {
189 printk(KERN_ERR "sv_wait: SV_INTS and interrupts "
190 "enabled (flags: 0x%lx)\n", flags);
191 BUG();
192 }
193 } else {
194 if (SV_TEST_INTERRUPTS_DISABLED(flags)) {
195 printk(KERN_WARNING "sv_wait: !SV_INTS and interrupts "
196 "disabled! (flags: 0x%lx)\n", flags);
197 }
198 }
199 }
200 #endif /* SV_DEBUG_INTERRUPT_STATE */
201
202 sv_lock(sv);
203
204 sv->sv_mon_unlock_func(sv->sv_mon_lock);
205
206 /* Add ourselves to the wait queue and set the state before
207 * releasing the sv_lock so as to avoid racing with the
208 * wake_up() in sv_signal() and sv_broadcast().
209 */
210
211 /* don't need the _irqsave part, but there is no wq_write_lock() */
212 wq_write_lock_irqsave(&sv->sv_waiters.lock, flags);
213
214 #ifdef EXCLUSIVE_IN_QUEUE
215 wait.flags |= WQ_FLAG_EXCLUSIVE;
216 #endif
217
218 switch(sv->sv_flags & SV_ORDER_MASK) {
219 case SV_ORDER_FIFO:
220 __add_wait_queue_tail(&sv->sv_waiters, &wait);
221 break;
222 case SV_ORDER_FILO:
223 __add_wait_queue(&sv->sv_waiters, &wait);
224 break;
225 default:
226 printk(KERN_ERR "sv_wait: unknown order! (sv: 0x%p, flags: 0x%x)\n",
227 sv, sv->sv_flags);
228 BUG();
229 }
230 wq_write_unlock_irqrestore(&sv->sv_waiters.lock, flags);
231
232 if(sv_wait_flags & SV_WAIT_SIG)
233 set_current_state(TASK_EXCLUSIVE | TASK_INTERRUPTIBLE );
234 else
235 set_current_state(TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE);
236
237 spin_unlock(&sv->sv_lock);
238
239 if(sv->sv_flags & SV_INTS)
240 local_irq_enable();
241 else if(sv->sv_flags & SV_BHS)
242 local_bh_enable();
243
244 if (timeout)
245 ret = schedule_timeout(timeout);
246 else
247 schedule();
248
249 if(current->state != TASK_RUNNING) /* XXX Is this possible? */ {
250 printk(KERN_ERR "sv_wait: state not TASK_RUNNING after "
251 "schedule().\n");
252 set_current_state(TASK_RUNNING);
253 }
254
255 remove_wait_queue(&sv->sv_waiters, &wait);
256
257 /* Return cases:
258 - woken by a sv_signal/sv_broadcast
259 - woken by a signal
260 - woken by timeout expiring
261 */
262
263 /* XXX This isn't really accurate; we may have been woken
264 before the signal anyway.... */
265 if(signal_pending(current))
266 return timeout ? -ret : -1;
267 return timeout ? ret : 1;
268 }
269
270
271 void sv_signal(sv_t *sv)
272 {
273 /* If interrupts can acquire this lock, they can also acquire the
274 sv_mon_lock, which we must already have to have called this, so
275 interrupts must be disabled already. If interrupts cannot
276 contend for this lock, we don't have to worry about it. */
277
278 #ifdef SV_DEBUG_INTERRUPT_STATE
279 if(sv->sv_flags & SV_INTS) {
280 unsigned long flags;
281 __save_flags(flags);
282 if(SV_TEST_INTERRUPTS_ENABLED(flags))
283 printk(KERN_ERR "sv_signal: SV_INTS and "
284 "interrupts enabled! (flags: 0x%lx)\n", flags);
285 }
286 #endif /* SV_DEBUG_INTERRUPT_STATE */
287
288 sv_lock(sv);
289 wake_up(&sv->sv_waiters);
290 sv_unlock(sv);
291 }
292
293 void sv_broadcast(sv_t *sv)
294 {
295 #ifdef SV_DEBUG_INTERRUPT_STATE
296 if(sv->sv_flags & SV_INTS) {
297 unsigned long flags;
298 __save_flags(flags);
299 if(SV_TEST_INTERRUPTS_ENABLED(flags))
300 printk(KERN_ERR "sv_broadcast: SV_INTS and "
301 "interrupts enabled! (flags: 0x%lx)\n", flags);
302 }
303 #endif /* SV_DEBUG_INTERRUPT_STATE */
304
305 sv_lock(sv);
306 wake_up_all(&sv->sv_waiters);
307 sv_unlock(sv);
308 }
309
310 void sv_destroy(sv_t *sv)
311 {
312 if(!spin_trylock(&sv->sv_lock)) {
313 printk(KERN_ERR "sv_destroy: someone else has sv 0x%p locked!\n", sv);
314 BUG();
315 }
316
317 /* XXX Check that the waitqueue is empty?
318 Mark the sv destroyed?
319 */
320 }
321
322
323 #ifdef RUN_SV_TEST
324
325 static DECLARE_MUTEX_LOCKED(talkback);
326 static DECLARE_MUTEX_LOCKED(sem);
327 sv_t sv;
328 sv_t sv_filo;
329
330 static int sv_test_1_w(void *arg)
331 {
332 printk("sv_test_1_w: acquiring spinlock 0x%p...\n", arg);
333
334 spin_lock((spinlock_t*)arg);
335 printk("sv_test_1_w: spinlock acquired, waking sv_test_1_s.\n");
336
337 up(&sem);
338
339 printk("sv_test_1_w: sv_spin_wait()'ing.\n");
340
341 sv_spin_wait(&sv, arg);
342
343 printk("sv_test_1_w: talkback.\n");
344 up(&talkback);
345
346 printk("sv_test_1_w: exiting.\n");
347 return 0;
348 }
349
350 static int sv_test_1_s(void *arg)
351 {
352 printk("sv_test_1_s: waiting for semaphore.\n");
353 down(&sem);
354 printk("sv_test_1_s: semaphore acquired. Acquiring spinlock.\n");
355 spin_lock((spinlock_t*)arg);
356 printk("sv_test_1_s: spinlock acquired. sv_signaling.\n");
357 sv_signal(&sv);
358 printk("sv_test_1_s: talkback.\n");
359 up(&talkback);
360 printk("sv_test_1_s: exiting.\n");
361 return 0;
362
363 }
364
365 static int count;
366 static DECLARE_MUTEX(monitor);
367
368 static int sv_test_2_w(void *arg)
369 {
370 int dummy = count++;
371 sv_t *sv = (sv_t *)arg;
372
373 down(&monitor);
374 up(&talkback);
375 printk("sv_test_2_w: thread %d started, sv_waiting.\n", dummy);
376 sv_sema_wait(sv, &monitor);
377 printk("sv_test_2_w: thread %d woken, exiting.\n", dummy);
378 up(&sem);
379 return 0;
380 }
381
382 static int sv_test_2_s_1(void *arg)
383 {
384 int i;
385 sv_t *sv = (sv_t *)arg;
386
387 down(&monitor);
388 for(i = 0; i < 3; i++) {
389 printk("sv_test_2_s_1: waking one thread.\n");
390 sv_signal(sv);
391 down(&sem);
392 }
393
394 printk("sv_test_2_s_1: signaling and broadcasting again. Nothing should happen.\n");
395 sv_signal(sv);
396 sv_broadcast(sv);
397 sv_signal(sv);
398 sv_broadcast(sv);
399
400 printk("sv_test_2_s_1: talkbacking.\n");
401 up(&talkback);
402 up(&monitor);
403 return 0;
404 }
405
406 static int sv_test_2_s(void *arg)
407 {
408 int i;
409 sv_t *sv = (sv_t *)arg;
410
411 down(&monitor);
412 for(i = 0; i < 3; i++) {
413 printk("sv_test_2_s: waking one thread (should be %d.)\n", i);
414 sv_signal(sv);
415 down(&sem);
416 }
417
418 printk("sv_test_3_s: waking remaining threads with broadcast.\n");
419 sv_broadcast(sv);
420 for(; i < 10; i++)
421 down(&sem);
422
423 printk("sv_test_3_s: sending talkback.\n");
424 up(&talkback);
425
426 printk("sv_test_3_s: exiting.\n");
427 up(&monitor);
428 return 0;
429 }
430
431
432 static void big_test(sv_t *sv)
433 {
434 int i;
435
436 count = 0;
437
438 for(i = 0; i < 3; i++) {
439 printk("big_test: spawning thread %d.\n", i);
440 kernel_thread(sv_test_2_w, sv, 0);
441 down(&talkback);
442 }
443
444 printk("big_test: spawning first wake-up thread.\n");
445 kernel_thread(sv_test_2_s_1, sv, 0);
446
447 down(&talkback);
448 printk("big_test: talkback happened.\n");
449
450
451 for(i = 3; i < 13; i++) {
452 printk("big_test: spawning thread %d.\n", i);
453 kernel_thread(sv_test_2_w, sv, 0);
454 down(&talkback);
455 }
456
457 printk("big_test: spawning wake-up thread.\n");
458 kernel_thread(sv_test_2_s, sv, 0);
459
460 down(&talkback);
461 }
462
463 sv_t int_test_sv;
464 spinlock_t int_test_spin = SPIN_LOCK_UNLOCKED;
465 int int_test_ready;
466 static int irqtestcount;
467
468 static int interrupt_test_worker(void *unused)
469 {
470 int id = ++irqtestcount;
471 int it = 0;
472 unsigned long flags, flags2;
473
474 printk("ITW: thread %d started.\n", id);
475
476 while(1) {
477 __save_flags(flags2);
478 if(jiffies % 3) {
479 printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2);
480 spin_lock_irqsave(&int_test_spin, flags);
481 } else {
482 printk("ITW %2d %5d: spin_lock_irqing (%lx)\n", id, it, flags2);
483 spin_lock_irq(&int_test_spin);
484 }
485
486 __save_flags(flags2);
487 printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2);
488 sv_wait(&int_test_sv, 0, 0);
489
490 __save_flags(flags2);
491 printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2);
492 set_current_state(TASK_INTERRUPTIBLE);
493 schedule_timeout(jiffies & 0xf);
494 if(current->state != TASK_RUNNING)
495 printk("ITW: current->state isn't RUNNING after schedule!\n");
496 it++;
497 }
498 }
499
500 static void interrupt_test(void)
501 {
502 int i;
503
504 printk("interrupt_test: initing sv.\n");
505 sv_init(&int_test_sv, &int_test_spin, SV_MON_SPIN | SV_INTS);
506
507 for(i = 0; i < SV_INTERRUPT_TEST_WORKERS; i++) {
508 printk("interrupt_test: starting test thread %d.\n", i);
509 kernel_thread(interrupt_test_worker, 0, 0);
510 }
511 printk("interrupt_test: done with init part.\n");
512 int_test_ready = 1;
513 }
514
515 int sv_test(void)
516 {
517 spinlock_t s = SPIN_LOCK_UNLOCKED;
518
519 sv_init(&sv, &s, SV_MON_SPIN);
520 printk("sv_test: starting sv_test_1_w.\n");
521 kernel_thread(sv_test_1_w, &s, 0);
522 printk("sv_test: starting sv_test_1_s.\n");
523 kernel_thread(sv_test_1_s, &s, 0);
524
525 printk("sv_test: waiting for talkback.\n");
526 down(&talkback); down(&talkback);
527 printk("sv_test: talkback happened, sv_destroying.\n");
528 sv_destroy(&sv);
529
530 count = 0;
531
532 printk("sv_test: beginning big_test on sv.\n");
533
534 sv_init(&sv, &monitor, SV_MON_SEMA);
535 big_test(&sv);
536 sv_destroy(&sv);
537
538 printk("sv_test: beginning big_test on sv_filo.\n");
539 sv_init(&sv_filo, &monitor, SV_MON_SEMA | SV_ORDER_FILO);
540 big_test(&sv_filo);
541 sv_destroy(&sv_filo);
542
543 interrupt_test();
544
545 printk("sv_test: done.\n");
546 return 0;
547 }
548
549 __initcall(sv_test);
550
551 #endif /* RUN_SV_TEST */
552