Automatic merge of rsync://www.parisc-linux.org/~jejb/git/scsi-for-linus-2.6.git
[linux-2.6] / arch / sparc64 / kernel / semaphore.c
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 #include <linux/errno.h>
11 #include <linux/init.h>
12
13 /*
14  * Atomically update sem->count.
15  * This does the equivalent of the following:
16  *
17  *      old_count = sem->count;
18  *      tmp = MAX(old_count, 0) + incr;
19  *      sem->count = tmp;
20  *      return old_count;
21  */
22 static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
23 {
24         int old_count, tmp;
25
26         __asm__ __volatile__("\n"
27 "       ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
28 "1:     ldsw    [%3], %0\n"
29 "       mov     %0, %1\n"
30 "       cmp     %0, 0\n"
31 "       movl    %%icc, 0, %1\n"
32 "       add     %1, %4, %1\n"
33 "       cas     [%3], %0, %1\n"
34 "       cmp     %0, %1\n"
35 "       bne,pn  %%icc, 1b\n"
36 "        membar #StoreLoad | #StoreStore\n"
37         : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
38         : "r" (&sem->count), "r" (incr), "m" (sem->count)
39         : "cc");
40
41         return old_count;
42 }
43
44 static void __up(struct semaphore *sem)
45 {
46         __sem_update_count(sem, 1);
47         wake_up(&sem->wait);
48 }
49
50 void up(struct semaphore *sem)
51 {
52         /* This atomically does:
53          *      old_val = sem->count;
54          *      new_val = sem->count + 1;
55          *      sem->count = new_val;
56          *      if (old_val < 0)
57          *              __up(sem);
58          *
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.
63          */
64
65         __asm__ __volatile__("\n"
66 "       ! up sem(%0)\n"
67 "       membar  #StoreLoad | #LoadLoad\n"
68 "1:     lduw    [%0], %%g1\n"
69 "       add     %%g1, 1, %%g7\n"
70 "       cas     [%0], %%g1, %%g7\n"
71 "       cmp     %%g1, %%g7\n"
72 "       bne,pn  %%icc, 1b\n"
73 "        addcc  %%g7, 1, %%g0\n"
74 "       ble,pn  %%icc, 3f\n"
75 "        membar #StoreLoad | #StoreStore\n"
76 "2:\n"
77 "       .subsection 2\n"
78 "3:     mov     %0, %%g1\n"
79 "       save    %%sp, -160, %%sp\n"
80 "       call    %1\n"
81 "        mov    %%g1, %%o0\n"
82 "       ba,pt   %%xcc, 2b\n"
83 "        restore\n"
84 "       .previous\n"
85         : : "r" (sem), "i" (__up)
86         : "g1", "g2", "g3", "g7", "memory", "cc");
87 }
88
89 static void __sched __down(struct semaphore * sem)
90 {
91         struct task_struct *tsk = current;
92         DECLARE_WAITQUEUE(wait, tsk);
93
94         tsk->state = TASK_UNINTERRUPTIBLE;
95         add_wait_queue_exclusive(&sem->wait, &wait);
96
97         while (__sem_update_count(sem, -1) <= 0) {
98                 schedule();
99                 tsk->state = TASK_UNINTERRUPTIBLE;
100         }
101         remove_wait_queue(&sem->wait, &wait);
102         tsk->state = TASK_RUNNING;
103
104         wake_up(&sem->wait);
105 }
106
107 void __sched down(struct semaphore *sem)
108 {
109         might_sleep();
110         /* This atomically does:
111          *      old_val = sem->count;
112          *      new_val = sem->count - 1;
113          *      sem->count = new_val;
114          *      if (old_val < 1)
115          *              __down(sem);
116          *
117          * The (old_val < 1) test is equivalent to
118          * the more straightforward (new_val < 0),
119          * but it is easier to test the former because
120          * of how the CAS instruction works.
121          */
122
123         __asm__ __volatile__("\n"
124 "       ! down sem(%0)\n"
125 "1:     lduw    [%0], %%g1\n"
126 "       sub     %%g1, 1, %%g7\n"
127 "       cas     [%0], %%g1, %%g7\n"
128 "       cmp     %%g1, %%g7\n"
129 "       bne,pn  %%icc, 1b\n"
130 "        cmp    %%g7, 1\n"
131 "       bl,pn   %%icc, 3f\n"
132 "        membar #StoreLoad | #StoreStore\n"
133 "2:\n"
134 "       .subsection 2\n"
135 "3:     mov     %0, %%g1\n"
136 "       save    %%sp, -160, %%sp\n"
137 "       call    %1\n"
138 "        mov    %%g1, %%o0\n"
139 "       ba,pt   %%xcc, 2b\n"
140 "        restore\n"
141 "       .previous\n"
142         : : "r" (sem), "i" (__down)
143         : "g1", "g2", "g3", "g7", "memory", "cc");
144 }
145
146 int down_trylock(struct semaphore *sem)
147 {
148         int ret;
149
150         /* This atomically does:
151          *      old_val = sem->count;
152          *      new_val = sem->count - 1;
153          *      if (old_val < 1) {
154          *              ret = 1;
155          *      } else {
156          *              sem->count = new_val;
157          *              ret = 0;
158          *      }
159          *
160          * The (old_val < 1) test is equivalent to
161          * the more straightforward (new_val < 0),
162          * but it is easier to test the former because
163          * of how the CAS instruction works.
164          */
165
166         __asm__ __volatile__("\n"
167 "       ! down_trylock sem(%1) ret(%0)\n"
168 "1:     lduw    [%1], %%g1\n"
169 "       sub     %%g1, 1, %%g7\n"
170 "       cmp     %%g1, 1\n"
171 "       bl,pn   %%icc, 2f\n"
172 "        mov    1, %0\n"
173 "       cas     [%1], %%g1, %%g7\n"
174 "       cmp     %%g1, %%g7\n"
175 "       bne,pn  %%icc, 1b\n"
176 "        mov    0, %0\n"
177 "       membar  #StoreLoad | #StoreStore\n"
178 "2:\n"
179         : "=&r" (ret)
180         : "r" (sem)
181         : "g1", "g7", "memory", "cc");
182
183         return ret;
184 }
185
186 static int __sched __down_interruptible(struct semaphore * sem)
187 {
188         int retval = 0;
189         struct task_struct *tsk = current;
190         DECLARE_WAITQUEUE(wait, tsk);
191
192         tsk->state = TASK_INTERRUPTIBLE;
193         add_wait_queue_exclusive(&sem->wait, &wait);
194
195         while (__sem_update_count(sem, -1) <= 0) {
196                 if (signal_pending(current)) {
197                         __sem_update_count(sem, 0);
198                         retval = -EINTR;
199                         break;
200                 }
201                 schedule();
202                 tsk->state = TASK_INTERRUPTIBLE;
203         }
204         tsk->state = TASK_RUNNING;
205         remove_wait_queue(&sem->wait, &wait);
206         wake_up(&sem->wait);
207         return retval;
208 }
209
210 int __sched down_interruptible(struct semaphore *sem)
211 {
212         int ret = 0;
213         
214         might_sleep();
215         /* This atomically does:
216          *      old_val = sem->count;
217          *      new_val = sem->count - 1;
218          *      sem->count = new_val;
219          *      if (old_val < 1)
220          *              ret = __down_interruptible(sem);
221          *
222          * The (old_val < 1) test is equivalent to
223          * the more straightforward (new_val < 0),
224          * but it is easier to test the former because
225          * of how the CAS instruction works.
226          */
227
228         __asm__ __volatile__("\n"
229 "       ! down_interruptible sem(%2) ret(%0)\n"
230 "1:     lduw    [%2], %%g1\n"
231 "       sub     %%g1, 1, %%g7\n"
232 "       cas     [%2], %%g1, %%g7\n"
233 "       cmp     %%g1, %%g7\n"
234 "       bne,pn  %%icc, 1b\n"
235 "        cmp    %%g7, 1\n"
236 "       bl,pn   %%icc, 3f\n"
237 "        membar #StoreLoad | #StoreStore\n"
238 "2:\n"
239 "       .subsection 2\n"
240 "3:     mov     %2, %%g1\n"
241 "       save    %%sp, -160, %%sp\n"
242 "       call    %3\n"
243 "        mov    %%g1, %%o0\n"
244 "       ba,pt   %%xcc, 2b\n"
245 "        restore\n"
246 "       .previous\n"
247         : "=r" (ret)
248         : "0" (ret), "r" (sem), "i" (__down_interruptible)
249         : "g1", "g2", "g3", "g7", "memory", "cc");
250         return ret;
251 }