make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / include / asm-mips / semaphore.h
1 /*
2  * SMP- and interrupt-safe semaphores..
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * (C) Copyright 1996  Linus Torvalds
9  * (C) Copyright 1998, 99, 2000, 01  Ralf Baechle
10  * (C) Copyright 1999, 2000  Silicon Graphics, Inc.
11  * Copyright (C) 2000, 01 MIPS Technologies, Inc.  All rights reserved.
12  */
13 #ifndef _ASM_SEMAPHORE_H
14 #define _ASM_SEMAPHORE_H
15
16 #include <asm/system.h>
17 #include <asm/atomic.h>
18 #include <linux/spinlock.h>
19 #include <linux/wait.h>
20 #include <linux/config.h>
21 #include <linux/rwsem.h>
22
23 struct semaphore {
24 #ifdef __MIPSEB__
25         atomic_t count;
26         atomic_t waking;
27 #else
28         atomic_t waking;
29         atomic_t count;
30 #endif
31         wait_queue_head_t wait;
32 #if WAITQUEUE_DEBUG
33         long __magic;
34 #endif
35 } __attribute__((aligned(8)));
36
37 #if WAITQUEUE_DEBUG
38 # define __SEM_DEBUG_INIT(name) \
39                 , (long)&(name).__magic
40 #else
41 # define __SEM_DEBUG_INIT(name)
42 #endif
43
44 #ifdef __MIPSEB__
45 #define __SEMAPHORE_INITIALIZER(name,count) \
46 { ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
47         __SEM_DEBUG_INIT(name) }
48 #else
49 #define __SEMAPHORE_INITIALIZER(name,count) \
50 { ATOMIC_INIT(0), ATOMIC_INIT(count), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
51         __SEM_DEBUG_INIT(name) }
52 #endif
53
54 #define __MUTEX_INITIALIZER(name) \
55         __SEMAPHORE_INITIALIZER(name,1)
56
57 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
58         struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
59
60 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
61 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
62
63 static inline void sema_init (struct semaphore *sem, int val)
64 {
65         atomic_set(&sem->count, val);
66         atomic_set(&sem->waking, 0);
67         init_waitqueue_head(&sem->wait);
68 #if WAITQUEUE_DEBUG
69         sem->__magic = (long)&sem->__magic;
70 #endif
71 }
72
73 static inline void init_MUTEX (struct semaphore *sem)
74 {
75         sema_init(sem, 1);
76 }
77
78 static inline void init_MUTEX_LOCKED (struct semaphore *sem)
79 {
80         sema_init(sem, 0);
81 }
82
83 asmlinkage void __down(struct semaphore * sem);
84 asmlinkage int  __down_interruptible(struct semaphore * sem);
85 asmlinkage int __down_trylock(struct semaphore * sem);
86 asmlinkage void __up(struct semaphore * sem);
87
88 static inline void down(struct semaphore * sem)
89 {
90 #if WAITQUEUE_DEBUG
91         CHECK_MAGIC(sem->__magic);
92 #endif
93         if (atomic_dec_return(&sem->count) < 0)
94                 __down(sem);
95 }
96
97 /*
98  * Interruptible try to acquire a semaphore.  If we obtained
99  * it, return zero.  If we were interrupted, returns -EINTR
100  */
101 static inline int down_interruptible(struct semaphore * sem)
102 {
103         int ret = 0;
104
105 #if WAITQUEUE_DEBUG
106         CHECK_MAGIC(sem->__magic);
107 #endif
108         if (atomic_dec_return(&sem->count) < 0)
109                 ret = __down_interruptible(sem);
110         return ret;
111 }
112
113 #ifndef CONFIG_CPU_HAS_LLDSCD
114
115 /*
116  * Non-blockingly attempt to down() a semaphore.
117  * Returns zero if we acquired it
118  */
119 static inline int down_trylock(struct semaphore * sem)
120 {
121         int ret = 0;
122         if (atomic_dec_return(&sem->count) < 0)
123                 ret = __down_trylock(sem);
124         return ret;
125 }
126
127 #else
128
129 /*
130  * down_trylock returns 0 on success, 1 if we failed to get the lock.
131  *
132  * We must manipulate count and waking simultaneously and atomically.
133  * Here, we do this by using lld/scd on the pair of 32-bit words.  This
134  * won't work on MIPS32 platforms, however, and must be rewritten.
135  *
136  * Pseudocode:
137  *
138  *   Decrement(sem->count)
139  *   If(sem->count >=0) {
140  *      Return(SUCCESS)                 // resource is free
141  *   } else {
142  *      If(sem->waking <= 0) {          // if no wakeup pending
143  *         Increment(sem->count)        // undo decrement
144  *         Return(FAILURE)
145  *      } else {
146  *         Decrement(sem->waking)       // otherwise "steal" wakeup
147  *         Return(SUCCESS)
148  *      }
149  *   }
150  */
151 static inline int down_trylock(struct semaphore * sem)
152 {
153         long ret, tmp, tmp2, sub;
154
155 #if WAITQUEUE_DEBUG
156         CHECK_MAGIC(sem->__magic);
157 #endif
158
159         __asm__ __volatile__(
160         ".set\tmips3\t\t\t# down_trylock\n"
161         "0:\tlld\t%1, %4\n\t"
162         "dli\t%3, 0x0000000100000000\n\t"
163         "dsubu\t%1, %3\n\t"
164         "li\t%0, 0\n\t"
165         "bgez\t%1, 2f\n\t"
166         "sll\t%2, %1, 0\n\t"
167         "blez\t%2, 1f\n\t"
168         "daddiu\t%1, %1, -1\n\t"
169         "b\t2f\n\t"
170         "1:\tdaddu\t%1, %1, %3\n"
171         "li\t%0, 1\n"
172         "2:\tscd\t%1, %4\n\t"
173         "beqz\t%1, 0b\n\t"
174         ".set   mips0"
175         : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
176         : "m"(*sem)
177         : "memory");
178
179         return ret;
180 }
181
182 #endif /* CONFIG_CPU_HAS_LLDSCD */
183
184 /*
185  * Note! This is subtle. We jump to wake people up only if
186  * the semaphore was negative (== somebody was waiting on it).
187  */
188 static inline void up(struct semaphore * sem)
189 {
190 #if WAITQUEUE_DEBUG
191         CHECK_MAGIC(sem->__magic);
192 #endif
193         if (atomic_inc_return(&sem->count) <= 0)
194                 __up(sem);
195 }
196
197 static inline int sem_getcount(struct semaphore *sem)
198 {
199         return atomic_read(&sem->count);
200 }
201
202 #endif /* _ASM_SEMAPHORE_H */