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