cleanup
[linux-2.4.git] / include / asm-s390x / rwsem.h
1 #ifndef _S390X_RWSEM_H
2 #define _S390X_RWSEM_H
3
4 /*
5  *  include/asm-s390x/rwsem.h
6  *
7  *  S390 version
8  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
9  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
10  *
11  *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
12  */
13
14 /*
15  *
16  * The MSW of the count is the negated number of active writers and waiting
17  * lockers, and the LSW is the total number of active locks
18  *
19  * The lock count is initialized to 0 (no active and no waiting lockers).
20  *
21  * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
22  * uncontended lock. This can be determined because XADD returns the old value.
23  * Readers increment by 1 and see a positive value when uncontended, negative
24  * if there are writers (and maybe) readers waiting (in which case it goes to
25  * sleep).
26  *
27  * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
28  * be extended to 65534 by manually checking the whole MSW rather than relying
29  * on the S flag.
30  *
31  * The value of ACTIVE_BIAS supports up to 65535 active processes.
32  *
33  * This should be totally fair - if anything is waiting, a process that wants a
34  * lock will go to the back of the queue. When the currently active lock is
35  * released, if there's a writer at the front of the queue, then that and only
36  * that will be woken up; if there's a bunch of consequtive readers at the
37  * front, then they'll all be woken up, but no other readers will be.
38  */
39
40 #ifndef _LINUX_RWSEM_H
41 #error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
42 #endif
43
44 #ifdef __KERNEL__
45
46 #include <linux/list.h>
47 #include <linux/spinlock.h>
48
49 struct rwsem_waiter;
50
51 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
52 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
53 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
54
55 /*
56  * the semaphore definition
57  */
58 struct rw_semaphore {
59         signed long             count;
60         spinlock_t              wait_lock;
61         struct list_head        wait_list;
62 };
63
64 #define RWSEM_UNLOCKED_VALUE    0x0000000000000000L
65 #define RWSEM_ACTIVE_BIAS       0x0000000000000001L
66 #define RWSEM_ACTIVE_MASK       0x00000000ffffffffL
67 #define RWSEM_WAITING_BIAS      (-0x0000000100000000L)
68 #define RWSEM_ACTIVE_READ_BIAS  RWSEM_ACTIVE_BIAS
69 #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
70
71 /*
72  * initialisation
73  */
74 #define __RWSEM_INITIALIZER(name) \
75 { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
76
77 #define DECLARE_RWSEM(name) \
78         struct rw_semaphore name = __RWSEM_INITIALIZER(name)
79
80 static inline void init_rwsem(struct rw_semaphore *sem)
81 {
82         sem->count = RWSEM_UNLOCKED_VALUE;
83         spin_lock_init(&sem->wait_lock);
84         INIT_LIST_HEAD(&sem->wait_list);
85 }
86
87 /*
88  * lock for reading
89  */
90 static inline void __down_read(struct rw_semaphore *sem)
91 {
92         signed long old, new;
93
94         __asm__ __volatile__(
95                 "   lg   %0,0(%2)\n"
96                 "0: lgr  %1,%0\n"
97                 "   aghi %1,%3\n"
98                 "   csg  %0,%1,0(%2)\n"
99                 "   jl   0b"
100                 : "=&d" (old), "=&d" (new)
101                 : "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
102                 : "cc", "memory" );
103         if (old < 0)
104                 rwsem_down_read_failed(sem);
105 }
106
107 /*
108  * trylock for reading -- returns 1 if successful, 0 if contention
109  */
110 static inline int __down_read_trylock(struct rw_semaphore *sem)
111 {
112         signed long old, new;
113
114         __asm__ __volatile__(
115                 "   lg   %0,0(%2)\n"
116                 "0: ltgr %1,%0\n"
117                 "   jm   1f\n"
118                 "   aghi %1,%3\n"
119                 "   csg  %0,%1,0(%2)\n"
120                 "   jl   0b\n"
121                 "1:"
122                 : "=&d" (old), "=&d" (new)
123                 : "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
124                 : "cc", "memory" );
125         return old >= 0 ? 1 : 0;
126 }
127
128 /*
129  * lock for writing
130  */
131 static inline void __down_write(struct rw_semaphore *sem)
132 {
133         signed long old, new, tmp;
134
135         tmp = RWSEM_ACTIVE_WRITE_BIAS;
136         __asm__ __volatile__(
137                 "   lg   %0,0(%2)\n"
138                 "0: lgr  %1,%0\n"
139                 "   ag   %1,%3\n"
140                 "   csg  %0,%1,0(%2)\n"
141                 "   jl   0b"
142                 : "=&d" (old), "=&d" (new)
143                 : "a" (&sem->count), "m" (tmp)
144                 : "cc", "memory" );
145         if (old != 0)
146                 rwsem_down_write_failed(sem);
147 }
148
149 /*
150  * trylock for writing -- returns 1 if successful, 0 if contention
151  */
152 static inline int __down_write_trylock(struct rw_semaphore *sem)
153 {
154         signed long old;
155
156         __asm__ __volatile__(
157                 "   lg   %0,0(%1)\n"
158                 "0: ltgr %0,%0\n"
159                 "   jnz  1f\n"
160                 "   csg  %0,%2,0(%1)\n"
161                 "   jl   0b\n"
162                 "1:"
163                 : "=&d" (old)
164                 : "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
165                 : "cc", "memory" );
166         return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
167 }
168
169 /*
170  * unlock after reading
171  */
172 static inline void __up_read(struct rw_semaphore *sem)
173 {
174         signed long old, new;
175
176         __asm__ __volatile__(
177                 "   lg   %0,0(%2)\n"
178                 "0: lgr  %1,%0\n"
179                 "   aghi %1,%3\n"
180                 "   csg  %0,%1,0(%2)\n"
181                 "   jl   0b"
182                 : "=&d" (old), "=&d" (new)
183                 : "a" (&sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
184                 : "cc", "memory" );
185         if (new < 0)
186                 if ((int) new == 0)
187                         rwsem_wake(sem);
188 }
189
190 /*
191  * unlock after writing
192  */
193 static inline void __up_write(struct rw_semaphore *sem)
194 {
195         signed long old, new, tmp;
196
197         tmp = -RWSEM_ACTIVE_WRITE_BIAS;
198         __asm__ __volatile__(
199                 "   lg   %0,0(%2)\n"
200                 "0: lgr  %1,%0\n"
201                 "   ag   %1,%3\n"
202                 "   csg  %0,%1,0(%2)\n"
203                 "   jl   0b"
204                 : "=&d" (old), "=&d" (new)
205                 : "a" (&sem->count), "m" (tmp)
206                 : "cc", "memory" );
207         if (new < 0)
208                 if ((int) new == 0)
209                         rwsem_wake(sem);
210 }
211
212 /*
213  * implement atomic add functionality
214  */
215 static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
216 {
217         signed long old, new;
218
219         __asm__ __volatile__(
220                 "   lg   %0,0(%2)\n"
221                 "0: lgr  %1,%0\n"
222                 "   agr  %1,%3\n"
223                 "   csg  %0,%1,0(%2)\n"
224                 "   jl   0b"
225                 : "=&d" (old), "=&d" (new)
226                 : "a" (&sem->count), "d" (delta)
227                 : "cc", "memory" );
228 }
229
230 /*
231  * implement exchange and add functionality
232  */
233 static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
234 {
235         signed long old, new;
236
237         __asm__ __volatile__(
238                 "   lg   %0,0(%2)\n"
239                 "0: lgr  %1,%0\n"
240                 "   agr  %1,%3\n"
241                 "   csg  %0,%1,0(%2)\n"
242                 "   jl   0b"
243                 : "=&d" (old), "=&d" (new)
244                 : "a" (&sem->count), "d" (delta)
245                 : "cc", "memory" );
246         return new;
247 }
248
249 #endif /* __KERNEL__ */
250 #endif /* _S390X_RWSEM_H */