1 /* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
2 * semaphore.c: Sparc64 semaphore implementation.
4 * This is basically the PPC semaphore scheme ported to use
5 * the sparc64 atomic instructions, so see the PPC code for
9 #include <linux/sched.h>
10 #include <linux/errno.h>
11 #include <linux/init.h>
14 * Atomically update sem->count.
15 * This does the equivalent of the following:
17 * old_count = sem->count;
18 * tmp = MAX(old_count, 0) + incr;
22 static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
26 __asm__ __volatile__("\n"
27 " ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
31 " movl %%icc, 0, %1\n"
36 " membar #StoreLoad | #StoreStore\n"
37 : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
38 : "r" (&sem->count), "r" (incr), "m" (sem->count)
44 static void __up(struct semaphore *sem)
46 __sem_update_count(sem, 1);
50 void up(struct semaphore *sem)
52 /* This atomically does:
53 * old_val = sem->count;
54 * new_val = sem->count + 1;
55 * sem->count = new_val;
59 * The (old_val < 0) test is equivalent to
60 * the more straightforward (new_val <= 0),
61 * but it is easier to test the former because
62 * of how the CAS instruction works.
65 __asm__ __volatile__("\n"
67 " membar #StoreLoad | #LoadLoad\n"
68 "1: lduw [%0], %%g5\n"
69 " add %%g5, 1, %%g7\n"
70 " cas [%0], %%g5, %%g7\n"
73 " addcc %%g7, 1, %%g0\n"
75 " membar #StoreLoad | #StoreStore\n"
79 " save %%sp, -160, %%sp\n"
88 " restore %%l3, %%g0, %%g3\n"
90 : : "r" (sem), "i" (__up)
91 : "g5", "g7", "memory", "cc");
94 static void __sched __down(struct semaphore * sem)
96 struct task_struct *tsk = current;
97 DECLARE_WAITQUEUE(wait, tsk);
99 tsk->state = TASK_UNINTERRUPTIBLE;
100 add_wait_queue_exclusive(&sem->wait, &wait);
102 while (__sem_update_count(sem, -1) <= 0) {
104 tsk->state = TASK_UNINTERRUPTIBLE;
106 remove_wait_queue(&sem->wait, &wait);
107 tsk->state = TASK_RUNNING;
112 void __sched down(struct semaphore *sem)
115 /* This atomically does:
116 * old_val = sem->count;
117 * new_val = sem->count - 1;
118 * sem->count = new_val;
122 * The (old_val < 1) test is equivalent to
123 * the more straightforward (new_val < 0),
124 * but it is easier to test the former because
125 * of how the CAS instruction works.
128 __asm__ __volatile__("\n"
130 "1: lduw [%0], %%g5\n"
131 " sub %%g5, 1, %%g7\n"
132 " cas [%0], %%g5, %%g7\n"
134 " bne,pn %%icc, 1b\n"
137 " membar #StoreLoad | #StoreStore\n"
141 " save %%sp, -160, %%sp\n"
150 " restore %%l3, %%g0, %%g3\n"
152 : : "r" (sem), "i" (__down)
153 : "g5", "g7", "memory", "cc");
156 int down_trylock(struct semaphore *sem)
160 /* This atomically does:
161 * old_val = sem->count;
162 * new_val = sem->count - 1;
166 * sem->count = new_val;
170 * The (old_val < 1) test is equivalent to
171 * the more straightforward (new_val < 0),
172 * but it is easier to test the former because
173 * of how the CAS instruction works.
176 __asm__ __volatile__("\n"
177 " ! down_trylock sem(%1) ret(%0)\n"
178 "1: lduw [%1], %%g5\n"
179 " sub %%g5, 1, %%g7\n"
183 " cas [%1], %%g5, %%g7\n"
185 " bne,pn %%icc, 1b\n"
187 " membar #StoreLoad | #StoreStore\n"
191 : "g5", "g7", "memory", "cc");
196 static int __sched __down_interruptible(struct semaphore * sem)
199 struct task_struct *tsk = current;
200 DECLARE_WAITQUEUE(wait, tsk);
202 tsk->state = TASK_INTERRUPTIBLE;
203 add_wait_queue_exclusive(&sem->wait, &wait);
205 while (__sem_update_count(sem, -1) <= 0) {
206 if (signal_pending(current)) {
207 __sem_update_count(sem, 0);
212 tsk->state = TASK_INTERRUPTIBLE;
214 tsk->state = TASK_RUNNING;
215 remove_wait_queue(&sem->wait, &wait);
220 int __sched down_interruptible(struct semaphore *sem)
225 /* This atomically does:
226 * old_val = sem->count;
227 * new_val = sem->count - 1;
228 * sem->count = new_val;
230 * ret = __down_interruptible(sem);
232 * The (old_val < 1) test is equivalent to
233 * the more straightforward (new_val < 0),
234 * but it is easier to test the former because
235 * of how the CAS instruction works.
238 __asm__ __volatile__("\n"
239 " ! down_interruptible sem(%2) ret(%0)\n"
240 "1: lduw [%2], %%g5\n"
241 " sub %%g5, 1, %%g7\n"
242 " cas [%2], %%g5, %%g7\n"
244 " bne,pn %%icc, 1b\n"
247 " membar #StoreLoad | #StoreStore\n"
251 " save %%sp, -160, %%sp\n"
261 " restore %%o0, %%g0, %0\n"
264 : "0" (ret), "r" (sem), "i" (__down_interruptible)
265 : "g5", "g7", "memory", "cc");