1 /* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
2 * semaphore.c: Sparc64 semaphore implementation.
3 *
4 * This is basically the PPC semaphore scheme ported to use
5 * the sparc64 atomic instructions, so see the PPC code for
6 * credits.
7 */
8
9 #include <linux/sched.h>
10
11 /*
12 * Atomically update sem->count.
13 * This does the equivalent of the following:
14 *
15 * old_count = sem->count;
16 * tmp = MAX(old_count, 0) + incr;
17 * sem->count = tmp;
18 * return old_count;
19 */
__sem_update_count(struct semaphore * sem,int incr)20 static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
21 {
22 int old_count, tmp;
23
24 __asm__ __volatile__("\n"
25 " ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
26 "1: ldsw [%3], %0\n"
27 " mov %0, %1\n"
28 " cmp %0, 0\n"
29 " movl %%icc, 0, %1\n"
30 " add %1, %4, %1\n"
31 " cas [%3], %0, %1\n"
32 " cmp %0, %1\n"
33 " bne,pn %%icc, 1b\n"
34 " membar #StoreLoad | #StoreStore\n"
35 : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
36 : "r" (&sem->count), "r" (incr), "m" (sem->count)
37 : "cc");
38
39 return old_count;
40 }
41
__up(struct semaphore * sem)42 void __up(struct semaphore *sem)
43 {
44 __sem_update_count(sem, 1);
45 wake_up(&sem->wait);
46 }
47
__down(struct semaphore * sem)48 void __down(struct semaphore * sem)
49 {
50 struct task_struct *tsk = current;
51 DECLARE_WAITQUEUE(wait, tsk);
52
53 tsk->state = TASK_UNINTERRUPTIBLE;
54 add_wait_queue_exclusive(&sem->wait, &wait);
55
56 while (__sem_update_count(sem, -1) <= 0) {
57 schedule();
58 tsk->state = TASK_UNINTERRUPTIBLE;
59 }
60 remove_wait_queue(&sem->wait, &wait);
61 tsk->state = TASK_RUNNING;
62
63 wake_up(&sem->wait);
64 }
65
__down_interruptible(struct semaphore * sem)66 int __down_interruptible(struct semaphore * sem)
67 {
68 int retval = 0;
69 struct task_struct *tsk = current;
70 DECLARE_WAITQUEUE(wait, tsk);
71
72 tsk->state = TASK_INTERRUPTIBLE;
73 add_wait_queue_exclusive(&sem->wait, &wait);
74
75 while (__sem_update_count(sem, -1) <= 0) {
76 if (signal_pending(current)) {
77 __sem_update_count(sem, 0);
78 retval = -EINTR;
79 break;
80 }
81 schedule();
82 tsk->state = TASK_INTERRUPTIBLE;
83 }
84 tsk->state = TASK_RUNNING;
85 remove_wait_queue(&sem->wait, &wait);
86 wake_up(&sem->wait);
87 return retval;
88 }
89