uprobes: remove function declarations from arch/{mips,s390}
[cascardo/linux.git] / arch / s390 / include / asm / spinlock.h
1 /*
2  *  S390 version
3  *    Copyright IBM Corp. 1999
4  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
5  *
6  *  Derived from "include/asm-i386/spinlock.h"
7  */
8
9 #ifndef __ASM_SPINLOCK_H
10 #define __ASM_SPINLOCK_H
11
12 #include <linux/smp.h>
13 #include <asm/barrier.h>
14 #include <asm/processor.h>
15
16 #define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval)
17
18 extern int spin_retry;
19
20 static inline int
21 _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new)
22 {
23         return __sync_bool_compare_and_swap(lock, old, new);
24 }
25
26 /*
27  * Simple spin lock operations.  There are two variants, one clears IRQ's
28  * on the local processor, one does not.
29  *
30  * We make no fairness assumptions. They have a cost.
31  *
32  * (the type definitions are in asm/spinlock_types.h)
33  */
34
35 void arch_lock_relax(unsigned int cpu);
36
37 void arch_spin_lock_wait(arch_spinlock_t *);
38 int arch_spin_trylock_retry(arch_spinlock_t *);
39 void arch_spin_lock_wait_flags(arch_spinlock_t *, unsigned long flags);
40
41 static inline void arch_spin_relax(arch_spinlock_t *lock)
42 {
43         arch_lock_relax(lock->lock);
44 }
45
46 static inline u32 arch_spin_lockval(int cpu)
47 {
48         return ~cpu;
49 }
50
51 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
52 {
53         return lock.lock == 0;
54 }
55
56 static inline int arch_spin_is_locked(arch_spinlock_t *lp)
57 {
58         return ACCESS_ONCE(lp->lock) != 0;
59 }
60
61 static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
62 {
63         barrier();
64         return likely(arch_spin_value_unlocked(*lp) &&
65                       _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL));
66 }
67
68 static inline void arch_spin_lock(arch_spinlock_t *lp)
69 {
70         if (!arch_spin_trylock_once(lp))
71                 arch_spin_lock_wait(lp);
72 }
73
74 static inline void arch_spin_lock_flags(arch_spinlock_t *lp,
75                                         unsigned long flags)
76 {
77         if (!arch_spin_trylock_once(lp))
78                 arch_spin_lock_wait_flags(lp, flags);
79 }
80
81 static inline int arch_spin_trylock(arch_spinlock_t *lp)
82 {
83         if (!arch_spin_trylock_once(lp))
84                 return arch_spin_trylock_retry(lp);
85         return 1;
86 }
87
88 static inline void arch_spin_unlock(arch_spinlock_t *lp)
89 {
90         typecheck(unsigned int, lp->lock);
91         asm volatile(
92                 "st     %1,%0\n"
93                 : "+Q" (lp->lock)
94                 : "d" (0)
95                 : "cc", "memory");
96 }
97
98 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
99 {
100         while (arch_spin_is_locked(lock))
101                 arch_spin_relax(lock);
102         smp_acquire__after_ctrl_dep();
103 }
104
105 /*
106  * Read-write spinlocks, allowing multiple readers
107  * but only one writer.
108  *
109  * NOTE! it is quite common to have readers in interrupts
110  * but no interrupt writers. For those circumstances we
111  * can "mix" irq-safe locks - any writer needs to get a
112  * irq-safe write-lock, but readers can get non-irqsafe
113  * read-locks.
114  */
115
116 /**
117  * read_can_lock - would read_trylock() succeed?
118  * @lock: the rwlock in question.
119  */
120 #define arch_read_can_lock(x) ((int)(x)->lock >= 0)
121
122 /**
123  * write_can_lock - would write_trylock() succeed?
124  * @lock: the rwlock in question.
125  */
126 #define arch_write_can_lock(x) ((x)->lock == 0)
127
128 extern int _raw_read_trylock_retry(arch_rwlock_t *lp);
129 extern int _raw_write_trylock_retry(arch_rwlock_t *lp);
130
131 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
132 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
133
134 static inline int arch_read_trylock_once(arch_rwlock_t *rw)
135 {
136         unsigned int old = ACCESS_ONCE(rw->lock);
137         return likely((int) old >= 0 &&
138                       _raw_compare_and_swap(&rw->lock, old, old + 1));
139 }
140
141 static inline int arch_write_trylock_once(arch_rwlock_t *rw)
142 {
143         unsigned int old = ACCESS_ONCE(rw->lock);
144         return likely(old == 0 &&
145                       _raw_compare_and_swap(&rw->lock, 0, 0x80000000));
146 }
147
148 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
149
150 #define __RAW_OP_OR     "lao"
151 #define __RAW_OP_AND    "lan"
152 #define __RAW_OP_ADD    "laa"
153
154 #define __RAW_LOCK(ptr, op_val, op_string)              \
155 ({                                                      \
156         unsigned int old_val;                           \
157                                                         \
158         typecheck(unsigned int *, ptr);                 \
159         asm volatile(                                   \
160                 op_string "     %0,%2,%1\n"             \
161                 "bcr    14,0\n"                         \
162                 : "=d" (old_val), "+Q" (*ptr)           \
163                 : "d" (op_val)                          \
164                 : "cc", "memory");                      \
165         old_val;                                        \
166 })
167
168 #define __RAW_UNLOCK(ptr, op_val, op_string)            \
169 ({                                                      \
170         unsigned int old_val;                           \
171                                                         \
172         typecheck(unsigned int *, ptr);                 \
173         asm volatile(                                   \
174                 op_string "     %0,%2,%1\n"             \
175                 : "=d" (old_val), "+Q" (*ptr)           \
176                 : "d" (op_val)                          \
177                 : "cc", "memory");                      \
178         old_val;                                        \
179 })
180
181 extern void _raw_read_lock_wait(arch_rwlock_t *lp);
182 extern void _raw_write_lock_wait(arch_rwlock_t *lp, unsigned int prev);
183
184 static inline void arch_read_lock(arch_rwlock_t *rw)
185 {
186         unsigned int old;
187
188         old = __RAW_LOCK(&rw->lock, 1, __RAW_OP_ADD);
189         if ((int) old < 0)
190                 _raw_read_lock_wait(rw);
191 }
192
193 static inline void arch_read_unlock(arch_rwlock_t *rw)
194 {
195         __RAW_UNLOCK(&rw->lock, -1, __RAW_OP_ADD);
196 }
197
198 static inline void arch_write_lock(arch_rwlock_t *rw)
199 {
200         unsigned int old;
201
202         old = __RAW_LOCK(&rw->lock, 0x80000000, __RAW_OP_OR);
203         if (old != 0)
204                 _raw_write_lock_wait(rw, old);
205         rw->owner = SPINLOCK_LOCKVAL;
206 }
207
208 static inline void arch_write_unlock(arch_rwlock_t *rw)
209 {
210         rw->owner = 0;
211         __RAW_UNLOCK(&rw->lock, 0x7fffffff, __RAW_OP_AND);
212 }
213
214 #else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
215
216 extern void _raw_read_lock_wait(arch_rwlock_t *lp);
217 extern void _raw_write_lock_wait(arch_rwlock_t *lp);
218
219 static inline void arch_read_lock(arch_rwlock_t *rw)
220 {
221         if (!arch_read_trylock_once(rw))
222                 _raw_read_lock_wait(rw);
223 }
224
225 static inline void arch_read_unlock(arch_rwlock_t *rw)
226 {
227         unsigned int old;
228
229         do {
230                 old = ACCESS_ONCE(rw->lock);
231         } while (!_raw_compare_and_swap(&rw->lock, old, old - 1));
232 }
233
234 static inline void arch_write_lock(arch_rwlock_t *rw)
235 {
236         if (!arch_write_trylock_once(rw))
237                 _raw_write_lock_wait(rw);
238         rw->owner = SPINLOCK_LOCKVAL;
239 }
240
241 static inline void arch_write_unlock(arch_rwlock_t *rw)
242 {
243         typecheck(unsigned int, rw->lock);
244
245         rw->owner = 0;
246         asm volatile(
247                 "st     %1,%0\n"
248                 : "+Q" (rw->lock)
249                 : "d" (0)
250                 : "cc", "memory");
251 }
252
253 #endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
254
255 static inline int arch_read_trylock(arch_rwlock_t *rw)
256 {
257         if (!arch_read_trylock_once(rw))
258                 return _raw_read_trylock_retry(rw);
259         return 1;
260 }
261
262 static inline int arch_write_trylock(arch_rwlock_t *rw)
263 {
264         if (!arch_write_trylock_once(rw) && !_raw_write_trylock_retry(rw))
265                 return 0;
266         rw->owner = SPINLOCK_LOCKVAL;
267         return 1;
268 }
269
270 static inline void arch_read_relax(arch_rwlock_t *rw)
271 {
272         arch_lock_relax(rw->owner);
273 }
274
275 static inline void arch_write_relax(arch_rwlock_t *rw)
276 {
277         arch_lock_relax(rw->owner);
278 }
279
280 #endif /* __ASM_SPINLOCK_H */