1 #ifndef _SPARC64_SEMAPHORE_H
2 #define _SPARC64_SEMAPHORE_H
4 /* These are actually reasonable on the V9. */
7 #include <asm/atomic.h>
8 #include <asm/bitops.h>
9 #include <asm/system.h>
10 #include <linux/wait.h>
15 wait_queue_head_t wait
;
22 # define __SEM_DEBUG_INIT(name) \
23 , (long)&(name).__magic
25 # define __SEM_DEBUG_INIT(name)
28 #define __SEMAPHORE_INITIALIZER(name,count) \
29 { ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
30 __SEM_DEBUG_INIT(name) }
32 #define __MUTEX_INITIALIZER(name) \
33 __SEMAPHORE_INITIALIZER(name,1)
35 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
36 struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
38 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
39 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
41 extern inline void sema_init (struct semaphore
*sem
, int val
)
43 atomic_set(&sem
->count
, val
);
44 atomic_set(&sem
->waking
, 0);
45 init_waitqueue_head(&sem
->wait
);
47 sem
->__magic
= (long)&sem
->__magic
;
51 static inline void init_MUTEX (struct semaphore
*sem
)
56 static inline void init_MUTEX_LOCKED (struct semaphore
*sem
)
61 extern void __down(struct semaphore
* sem
);
62 extern int __down_interruptible(struct semaphore
* sem
);
63 extern int __down_trylock(struct semaphore
* sem
);
64 extern void __up(struct semaphore
* sem
);
66 extern __inline__
void down(struct semaphore
* sem
)
69 CHECK_MAGIC(sem
->__magic
);
71 __asm__
__volatile__("
92 restore %%l3, %%g0, %%g3
94 : : "r" (sem
), "i" (__down
)
95 : "g5", "g7", "memory", "cc");
98 extern __inline__
int down_interruptible(struct semaphore
*sem
)
103 CHECK_MAGIC(sem
->__magic
);
105 __asm__
__volatile__("
117 save %%sp, -160, %%sp
127 restore %%o0, %%g0, %0
130 : "0" (ret
), "r" (sem
), "i" (__down_interruptible
)
131 : "g5", "g7", "memory", "cc");
135 extern inline int down_trylock(struct semaphore
*sem
)
139 CHECK_MAGIC(sem
->__magic
);
141 __asm__
__volatile__("
153 save %%sp, -160, %%sp
163 restore %%o0, %%g0, %0
166 : "0" (ret
), "r" (sem
), "i" (__down_trylock
)
167 : "g5", "g7", "memory", "cc");
171 extern __inline__
void up(struct semaphore
* sem
)
174 CHECK_MAGIC(sem
->__magic
);
176 __asm__
__volatile__("
177 membar #StoreLoad | #LoadLoad
189 save %%sp, -160, %%sp
198 restore %%l3, %%g0, %%g3
200 : : "r" (sem
), "i" (__up
)
201 : "g5", "g7", "memory", "cc");
204 /* rw mutexes (should that be mutices? =) -- throw rw
205 * spinlocks and semaphores together, and this is what we
208 * The lock is initialized to BIAS. This way, a writer
209 * subtracts BIAS ands gets 0 for the case of an uncontended
210 * lock. Readers decrement by 1 and see a positive value
211 * when uncontended, negative if there are writers waiting
212 * (in which case it goes to sleep).
214 * The value 0x01000000 supports up to 128 processors and
215 * lots of processes. BIAS must be chosen such that subtracting
216 * BIAS once per CPU will result in the int remaining
218 * In terms of fairness, this should result in the lock
219 * flopping back and forth between readers and writers
224 * Once we start supporting machines with more than 128 CPUs,
225 * we should go for using a 64bit atomic type instead of 32bit
226 * as counter. We shall probably go for bias 0x80000000 then,
227 * so that single sethi can set it.
231 #define RW_LOCK_BIAS 0x01000000
232 #define RW_LOCK_BIAS_STR "0x01000000"
234 struct rw_semaphore
{
236 /* So that this does not have to be 64bit type,
237 * we'll use le bitops on it which use casa instead of casx.
238 * bit 0 means read bias granted
239 * bit 1 means write bias granted
242 wait_queue_head_t wait
;
243 wait_queue_head_t write_bias_wait
;
252 #define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
254 #define __RWSEM_DEBUG_INIT /* */
257 #define __RWSEM_INITIALIZER(name,count) \
258 { (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
259 __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
260 __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
262 #define __DECLARE_RWSEM_GENERIC(name,count) \
263 struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
265 #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
266 #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
267 #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
269 extern inline void init_rwsem(struct rw_semaphore
*sem
)
271 sem
->count
= RW_LOCK_BIAS
;
273 init_waitqueue_head(&sem
->wait
);
274 init_waitqueue_head(&sem
->write_bias_wait
);
276 sem
->__magic
= (long)&sem
->__magic
;
277 atomic_set(&sem
->readers
, 0);
278 atomic_set(&sem
->writers
, 0);
282 extern void __down_read_failed(/* Special calling convention */ void);
283 extern void __down_write_failed(/* Special calling convention */ void);
284 extern void __rwsem_wake(struct rw_semaphore
*sem
, unsigned long readers
);
286 extern inline void down_read(struct rw_semaphore
*sem
)
289 CHECK_MAGIC(sem
->__magic
);
291 __asm__
__volatile__("
303 save %%sp, -160, %%sp
311 restore %%l3, %%g0, %%g3
313 : : "r" (sem
), "i" (__down_read_failed
)
314 : "g5", "g7", "memory", "cc");
316 if (test_le_bit(1, &sem
->granted
))
318 if (atomic_read(&sem
->writers
))
320 atomic_inc(&sem
->readers
);
324 extern inline void down_write(struct rw_semaphore
*sem
)
327 CHECK_MAGIC(sem
->__magic
);
329 __asm__
__volatile__("
331 sethi %%hi(" RW_LOCK_BIAS_STR
"), %%g7
332 subcc %%g5, %%g7, %%g7
342 save %%sp, -160, %%sp
350 restore %%l3, %%g0, %%g3
352 : : "r" (sem
), "i" (__down_write_failed
)
353 : "g5", "g7", "memory", "cc");
355 if (atomic_read(&sem
->writers
))
357 if (atomic_read(&sem
->readers
))
359 if (test_le_bit(0, &sem
->granted
))
361 if (test_le_bit(1, &sem
->granted
))
363 atomic_inc(&sem
->writers
);
367 /* When a reader does a release, the only significant
368 * case is when there was a writer waiting, and we've
369 * bumped the count to 0: we must wake the writer up.
371 extern inline void __up_read(struct rw_semaphore
*sem
)
373 __asm__
__volatile__("
374 membar #StoreLoad | #LoadLoad
386 save %%sp, -160, %%sp
396 restore %%l3, %%g0, %%g3
398 : : "r" (sem
), "i" (__rwsem_wake
)
399 : "g5", "g7", "memory", "cc");
402 /* releasing the writer is easy -- just release it and
403 * wake up any sleepers.
405 extern inline void __up_write(struct rw_semaphore
*sem
)
407 __asm__
__volatile__("
408 membar #StoreLoad | #LoadLoad
410 sethi %%hi(" RW_LOCK_BIAS_STR
"), %%g7
415 sethi %%hi(" RW_LOCK_BIAS_STR
"), %%g7
416 addcc %%g5, %%g7, %%g5
422 save %%sp, -160, %%sp
432 restore %%l3, %%g0, %%g3
434 : : "r" (sem
), "i" (__rwsem_wake
)
435 : "g5", "g7", "memory", "cc");
438 extern inline void up_read(struct rw_semaphore
*sem
)
441 if (test_le_bit(1, &sem
->granted
))
443 if (atomic_read(&sem
->writers
))
445 atomic_dec(&sem
->readers
);
450 extern inline void up_write(struct rw_semaphore
*sem
)
453 if (test_le_bit(0, &sem
->granted
))
455 if (test_le_bit(1, &sem
->granted
))
457 if (atomic_read(&sem
->readers
))
459 if (atomic_read(&sem
->writers
) != 1)
461 atomic_dec(&sem
->writers
);
466 #endif /* __KERNEL__ */
468 #endif /* !(_SPARC64_SEMAPHORE_H) */