1 /*
2 * Copyright (C) 1999, 2001, 02, 03 Ralf Baechle
3 *
4 * Heavily inspired by the Alpha implementation
5 */
6 #include <linux/config.h>
7 #include <linux/errno.h>
8 #include <linux/module.h>
9 #include <linux/sched.h>
10
11 #ifndef CONFIG_CPU_HAS_LLDSCD
12 /*
13 * On machines without lld/scd we need a spinlock to make the manipulation of
14 * sem->count and sem->waking atomic. Scalability isn't an issue because
15 * this lock is used on UP only so it's just an empty variable.
16 */
17 spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
18
19 EXPORT_SYMBOL(semaphore_lock);
20 #endif
21
22 /*
23 * Semaphores are implemented using a two-way counter: The "count" variable is
24 * decremented for each process that tries to sleep, while the "waking" variable
25 * is incremented when the "up()" code goes to wake up waiting processes.
26 *
27 * Notably, the inline "up()" and "down()" functions can efficiently test if
28 * they need to do any extra work (up needs to do something only if count was
29 * negative before the increment operation.
30 *
31 * waking_non_zero() must execute atomically.
32 *
33 * When __up() is called, the count was negative before incrementing it, and we
34 * need to wake up somebody.
35 *
36 * This routine adds one to the count of processes that need to wake up and
37 * exit. ALL waiting processes actually wake up but only the one that gets to
38 * the "waking" field first will gate through and acquire the semaphore. The
39 * others will go back to sleep.
40 *
41 * Note that these functions are only called when there is contention on the
42 * lock, and as such all this is the "non-critical" part of the whole semaphore
43 * business. The critical part is the inline stuff in <asm/semaphore.h> where
44 * we want to avoid any extra jumps and calls.
45 */
__up_wakeup(struct semaphore * sem)46 void __up_wakeup(struct semaphore *sem)
47 {
48 wake_up(&sem->wait);
49 }
50
51 EXPORT_SYMBOL(__up_wakeup);
52
53 #ifdef CONFIG_CPU_HAS_LLSC
54
waking_non_zero(struct semaphore * sem)55 static inline int waking_non_zero(struct semaphore *sem)
56 {
57 int ret, tmp;
58
59 __asm__ __volatile__(
60 "1: ll %1, %2 # waking_non_zero \n"
61 " blez %1, 2f \n"
62 " subu %0, %1, 1 \n"
63 " sc %0, %2 \n"
64 " beqz %0, 1b \n"
65 "2: \n"
66 : "=r" (ret), "=r" (tmp), "+m" (sem->waking)
67 : "0" (0));
68
69 return ret;
70 }
71
72 #else /* !CONFIG_CPU_HAS_LLSC */
73
waking_non_zero(struct semaphore * sem)74 static inline int waking_non_zero(struct semaphore *sem)
75 {
76 unsigned long flags;
77 int waking, ret = 0;
78
79 spin_lock_irqsave(&semaphore_lock, flags);
80 waking = atomic_read(&sem->waking);
81 if (waking > 0) {
82 atomic_set(&sem->waking, waking - 1);
83 ret = 1;
84 }
85 spin_unlock_irqrestore(&semaphore_lock, flags);
86
87 return ret;
88 }
89
90 #endif /* !CONFIG_CPU_HAS_LLSC */
91
92 /*
93 * Perform the "down" function. Return zero for semaphore acquired, return
94 * negative for signalled out of the function.
95 *
96 * If called from down, the return is ignored and the wait loop is not
97 * interruptible. This means that a task waiting on a semaphore using "down()"
98 * cannot be killed until someone does an "up()" on the semaphore.
99 *
100 * If called from down_interruptible, the return value gets checked upon return.
101 * If the return value is negative then the task continues with the negative
102 * value in the return register (it can be tested by the caller).
103 *
104 * Either form may be used in conjunction with "up()".
105 */
106
__down_failed(struct semaphore * sem)107 void __down_failed(struct semaphore * sem)
108 {
109 struct task_struct *tsk = current;
110 wait_queue_t wait;
111
112 init_waitqueue_entry(&wait, tsk);
113 __set_current_state(TASK_UNINTERRUPTIBLE);
114 add_wait_queue_exclusive(&sem->wait, &wait);
115
116 /*
117 * Ok, we're set up. sem->count is known to be less than zero
118 * so we must wait.
119 *
120 * We can let go the lock for purposes of waiting.
121 * We re-acquire it after awaking so as to protect
122 * all semaphore operations.
123 *
124 * If "up()" is called before we call waking_non_zero() then
125 * we will catch it right away. If it is called later then
126 * we will have to go through a wakeup cycle to catch it.
127 *
128 * Multiple waiters contend for the semaphore lock to see
129 * who gets to gate through and who has to wait some more.
130 */
131 for (;;) {
132 if (waking_non_zero(sem))
133 break;
134 schedule();
135 __set_current_state(TASK_UNINTERRUPTIBLE);
136 }
137 __set_current_state(TASK_RUNNING);
138 remove_wait_queue(&sem->wait, &wait);
139 }
140
141 EXPORT_SYMBOL(__down_failed);
142
143 #ifdef CONFIG_CPU_HAS_LLDSCD
144
145 /*
146 * waking_non_zero_interruptible:
147 * 1 got the lock
148 * 0 go to sleep
149 * -EINTR interrupted
150 *
151 * We must undo the sem->count down_interruptible decrement
152 * simultaneously and atomically with the sem->waking adjustment,
153 * otherwise we can race with wake_one_more.
154 *
155 * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
156 *
157 * This is crazy. Normally it's strictly forbidden to use 64-bit operations
158 * in the 32-bit MIPS kernel. In this case it's however ok because if an
159 * interrupt has destroyed the upper half of registers sc will fail.
160 * Note also that this will not work for MIPS32 CPUs!
161 *
162 * Pseudocode:
163 *
164 * If(sem->waking > 0) {
165 * Decrement(sem->waking)
166 * Return(SUCCESS)
167 * } else If(signal_pending(tsk)) {
168 * Increment(sem->count)
169 * Return(-EINTR)
170 * } else {
171 * Return(SLEEP)
172 * }
173 */
174
175 static inline int
waking_non_zero_interruptible(struct semaphore * sem,struct task_struct * tsk)176 waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
177 {
178 long ret, tmp;
179
180 __asm__ __volatile__(
181 " .set push # waking_non_zero_interruptible \n"
182 " .set mips3 \n"
183 " .set noat \n"
184 "0: lld %1, %2 \n"
185 " li %0, 0 \n"
186 " sll $1, %1, 0 \n"
187 " blez $1, 1f \n"
188 " daddiu %1, %1, -1 \n"
189 " li %0, 1 \n"
190 " b 2f \n"
191 "1: beqz %3, 2f \n"
192 " li %0, %4 \n"
193 " dli $1, 0x0000000100000000 \n"
194 " daddu %1, %1, $1 \n"
195 "2: scd %1, %2 \n"
196 " beqz %1, 0b \n"
197 " .set pop \n"
198 : "=&r" (ret), "=&r" (tmp), "=m" (*sem)
199 : "r" (signal_pending(tsk)), "i" (-EINTR));
200
201 return ret;
202 }
203
204 #else /* !CONFIG_CPU_HAS_LLDSCD */
205
waking_non_zero_interruptible(struct semaphore * sem,struct task_struct * tsk)206 static inline int waking_non_zero_interruptible(struct semaphore *sem,
207 struct task_struct *tsk)
208 {
209 int waking, pending, ret = 0;
210 unsigned long flags;
211
212 pending = signal_pending(tsk);
213
214 spin_lock_irqsave(&semaphore_lock, flags);
215 waking = atomic_read(&sem->waking);
216 if (waking > 0) {
217 atomic_set(&sem->waking, waking - 1);
218 ret = 1;
219 } else if (pending) {
220 atomic_set(&sem->count, atomic_read(&sem->count) + 1);
221 ret = -EINTR;
222 }
223 spin_unlock_irqrestore(&semaphore_lock, flags);
224
225 return ret;
226 }
227
228 #endif /* !CONFIG_CPU_HAS_LLDSCD */
229
__down_failed_interruptible(struct semaphore * sem)230 int __down_failed_interruptible(struct semaphore * sem)
231 {
232 struct task_struct *tsk = current;
233 wait_queue_t wait;
234 int ret = 0;
235
236 init_waitqueue_entry(&wait, tsk);
237 __set_current_state(TASK_INTERRUPTIBLE);
238 add_wait_queue_exclusive(&sem->wait, &wait);
239
240 /*
241 * Ok, we're set up. sem->count is known to be less than zero
242 * so we must wait.
243 *
244 * We can let go the lock for purposes of waiting.
245 * We re-acquire it after awaking so as to protect
246 * all semaphore operations.
247 *
248 * If "up()" is called before we call waking_non_zero() then
249 * we will catch it right away. If it is called later then
250 * we will have to go through a wakeup cycle to catch it.
251 *
252 * Multiple waiters contend for the semaphore lock to see
253 * who gets to gate through and who has to wait some more.
254 */
255 for (;;) {
256 ret = waking_non_zero_interruptible(sem, tsk);
257 if (ret) {
258 if (ret == 1)
259 /* ret != 0 only if we get interrupted -arca */
260 ret = 0;
261 break;
262 }
263 schedule();
264 __set_current_state(TASK_INTERRUPTIBLE);
265 }
266 __set_current_state(TASK_RUNNING);
267 remove_wait_queue(&sem->wait, &wait);
268
269 return ret;
270 }
271
272 EXPORT_SYMBOL(__down_failed_interruptible);
273