Merge branch 'linux-linaro-lsk-v4.4' into linux-linaro-lsk-v4.4-android
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / include / asm / spinlock.h
1 /*
2  * Copyright (C) 2012 ARM Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 #ifndef __ASM_SPINLOCK_H
17 #define __ASM_SPINLOCK_H
18
19 #include <asm/lse.h>
20 #include <asm/spinlock_types.h>
21 #include <asm/processor.h>
22
23 /*
24  * Spinlock implementation.
25  *
26  * The memory barriers are implicit with the load-acquire and store-release
27  * instructions.
28  */
29 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
30 {
31         unsigned int tmp;
32         arch_spinlock_t lockval;
33
34         asm volatile(
35 "       sevl\n"
36 "1:     wfe\n"
37 "2:     ldaxr   %w0, %2\n"
38 "       eor     %w1, %w0, %w0, ror #16\n"
39 "       cbnz    %w1, 1b\n"
40         /* Serialise against any concurrent lockers */
41         ARM64_LSE_ATOMIC_INSN(
42         /* LL/SC */
43 "       stxr    %w1, %w0, %2\n"
44 "       nop\n"
45 "       nop\n",
46         /* LSE atomics */
47 "       mov     %w1, %w0\n"
48 "       cas     %w0, %w0, %2\n"
49 "       eor     %w1, %w1, %w0\n")
50 "       cbnz    %w1, 2b\n"
51         : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
52         :
53         : "memory");
54 }
55
56 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
57
58 static inline void arch_spin_lock(arch_spinlock_t *lock)
59 {
60         unsigned int tmp;
61         arch_spinlock_t lockval, newval;
62
63         asm volatile(
64         /* Atomically increment the next ticket. */
65         ARM64_LSE_ATOMIC_INSN(
66         /* LL/SC */
67 "       prfm    pstl1strm, %3\n"
68 "1:     ldaxr   %w0, %3\n"
69 "       add     %w1, %w0, %w5\n"
70 "       stxr    %w2, %w1, %3\n"
71 "       cbnz    %w2, 1b\n",
72         /* LSE atomics */
73 "       mov     %w2, %w5\n"
74 "       ldadda  %w2, %w0, %3\n"
75 "       nop\n"
76 "       nop\n"
77 "       nop\n"
78         )
79
80         /* Did we get the lock? */
81 "       eor     %w1, %w0, %w0, ror #16\n"
82 "       cbz     %w1, 3f\n"
83         /*
84          * No: spin on the owner. Send a local event to avoid missing an
85          * unlock before the exclusive load.
86          */
87 "       sevl\n"
88 "2:     wfe\n"
89 "       ldaxrh  %w2, %4\n"
90 "       eor     %w1, %w2, %w0, lsr #16\n"
91 "       cbnz    %w1, 2b\n"
92         /* We got the lock. Critical section starts here. */
93 "3:"
94         : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
95         : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
96         : "memory");
97 }
98
99 static inline int arch_spin_trylock(arch_spinlock_t *lock)
100 {
101         unsigned int tmp;
102         arch_spinlock_t lockval;
103
104         asm volatile(ARM64_LSE_ATOMIC_INSN(
105         /* LL/SC */
106         "       prfm    pstl1strm, %2\n"
107         "1:     ldaxr   %w0, %2\n"
108         "       eor     %w1, %w0, %w0, ror #16\n"
109         "       cbnz    %w1, 2f\n"
110         "       add     %w0, %w0, %3\n"
111         "       stxr    %w1, %w0, %2\n"
112         "       cbnz    %w1, 1b\n"
113         "2:",
114         /* LSE atomics */
115         "       ldr     %w0, %2\n"
116         "       eor     %w1, %w0, %w0, ror #16\n"
117         "       cbnz    %w1, 1f\n"
118         "       add     %w1, %w0, %3\n"
119         "       casa    %w0, %w1, %2\n"
120         "       and     %w1, %w1, #0xffff\n"
121         "       eor     %w1, %w1, %w0, lsr #16\n"
122         "1:")
123         : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
124         : "I" (1 << TICKET_SHIFT)
125         : "memory");
126
127         return !tmp;
128 }
129
130 static inline void arch_spin_unlock(arch_spinlock_t *lock)
131 {
132         unsigned long tmp;
133
134         asm volatile(ARM64_LSE_ATOMIC_INSN(
135         /* LL/SC */
136         "       ldrh    %w1, %0\n"
137         "       add     %w1, %w1, #1\n"
138         "       stlrh   %w1, %0",
139         /* LSE atomics */
140         "       mov     %w1, #1\n"
141         "       nop\n"
142         "       staddlh %w1, %0")
143         : "=Q" (lock->owner), "=&r" (tmp)
144         :
145         : "memory");
146 }
147
148 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
149 {
150         return lock.owner == lock.next;
151 }
152
153 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
154 {
155         return !arch_spin_value_unlocked(READ_ONCE(*lock));
156 }
157
158 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
159 {
160         arch_spinlock_t lockval = READ_ONCE(*lock);
161         return (lockval.next - lockval.owner) > 1;
162 }
163 #define arch_spin_is_contended  arch_spin_is_contended
164
165 /*
166  * Write lock implementation.
167  *
168  * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
169  * exclusively held.
170  *
171  * The memory barriers are implicit with the load-acquire and store-release
172  * instructions.
173  */
174
175 static inline void arch_write_lock(arch_rwlock_t *rw)
176 {
177         unsigned int tmp;
178
179         asm volatile(ARM64_LSE_ATOMIC_INSN(
180         /* LL/SC */
181         "       sevl\n"
182         "1:     wfe\n"
183         "2:     ldaxr   %w0, %1\n"
184         "       cbnz    %w0, 1b\n"
185         "       stxr    %w0, %w2, %1\n"
186         "       cbnz    %w0, 2b\n"
187         "       nop",
188         /* LSE atomics */
189         "1:     mov     %w0, wzr\n"
190         "2:     casa    %w0, %w2, %1\n"
191         "       cbz     %w0, 3f\n"
192         "       ldxr    %w0, %1\n"
193         "       cbz     %w0, 2b\n"
194         "       wfe\n"
195         "       b       1b\n"
196         "3:")
197         : "=&r" (tmp), "+Q" (rw->lock)
198         : "r" (0x80000000)
199         : "memory");
200 }
201
202 static inline int arch_write_trylock(arch_rwlock_t *rw)
203 {
204         unsigned int tmp;
205
206         asm volatile(ARM64_LSE_ATOMIC_INSN(
207         /* LL/SC */
208         "1:     ldaxr   %w0, %1\n"
209         "       cbnz    %w0, 2f\n"
210         "       stxr    %w0, %w2, %1\n"
211         "       cbnz    %w0, 1b\n"
212         "2:",
213         /* LSE atomics */
214         "       mov     %w0, wzr\n"
215         "       casa    %w0, %w2, %1\n"
216         "       nop\n"
217         "       nop")
218         : "=&r" (tmp), "+Q" (rw->lock)
219         : "r" (0x80000000)
220         : "memory");
221
222         return !tmp;
223 }
224
225 static inline void arch_write_unlock(arch_rwlock_t *rw)
226 {
227         asm volatile(ARM64_LSE_ATOMIC_INSN(
228         "       stlr    wzr, %0",
229         "       swpl    wzr, wzr, %0")
230         : "=Q" (rw->lock) :: "memory");
231 }
232
233 /* write_can_lock - would write_trylock() succeed? */
234 #define arch_write_can_lock(x)          ((x)->lock == 0)
235
236 /*
237  * Read lock implementation.
238  *
239  * It exclusively loads the lock value, increments it and stores the new value
240  * back if positive and the CPU still exclusively owns the location. If the
241  * value is negative, the lock is already held.
242  *
243  * During unlocking there may be multiple active read locks but no write lock.
244  *
245  * The memory barriers are implicit with the load-acquire and store-release
246  * instructions.
247  *
248  * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
249  * and LSE implementations may exhibit different behaviour (although this
250  * will have no effect on lockdep).
251  */
252 static inline void arch_read_lock(arch_rwlock_t *rw)
253 {
254         unsigned int tmp, tmp2;
255
256         asm volatile(
257         "       sevl\n"
258         ARM64_LSE_ATOMIC_INSN(
259         /* LL/SC */
260         "1:     wfe\n"
261         "2:     ldaxr   %w0, %2\n"
262         "       add     %w0, %w0, #1\n"
263         "       tbnz    %w0, #31, 1b\n"
264         "       stxr    %w1, %w0, %2\n"
265         "       nop\n"
266         "       cbnz    %w1, 2b",
267         /* LSE atomics */
268         "1:     wfe\n"
269         "2:     ldxr    %w0, %2\n"
270         "       adds    %w1, %w0, #1\n"
271         "       tbnz    %w1, #31, 1b\n"
272         "       casa    %w0, %w1, %2\n"
273         "       sbc     %w0, %w1, %w0\n"
274         "       cbnz    %w0, 2b")
275         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
276         :
277         : "cc", "memory");
278 }
279
280 static inline void arch_read_unlock(arch_rwlock_t *rw)
281 {
282         unsigned int tmp, tmp2;
283
284         asm volatile(ARM64_LSE_ATOMIC_INSN(
285         /* LL/SC */
286         "1:     ldxr    %w0, %2\n"
287         "       sub     %w0, %w0, #1\n"
288         "       stlxr   %w1, %w0, %2\n"
289         "       cbnz    %w1, 1b",
290         /* LSE atomics */
291         "       movn    %w0, #0\n"
292         "       nop\n"
293         "       nop\n"
294         "       staddl  %w0, %2")
295         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
296         :
297         : "memory");
298 }
299
300 static inline int arch_read_trylock(arch_rwlock_t *rw)
301 {
302         unsigned int tmp, tmp2;
303
304         asm volatile(ARM64_LSE_ATOMIC_INSN(
305         /* LL/SC */
306         "       mov     %w1, #1\n"
307         "1:     ldaxr   %w0, %2\n"
308         "       add     %w0, %w0, #1\n"
309         "       tbnz    %w0, #31, 2f\n"
310         "       stxr    %w1, %w0, %2\n"
311         "       cbnz    %w1, 1b\n"
312         "2:",
313         /* LSE atomics */
314         "       ldr     %w0, %2\n"
315         "       adds    %w1, %w0, #1\n"
316         "       tbnz    %w1, #31, 1f\n"
317         "       casa    %w0, %w1, %2\n"
318         "       sbc     %w1, %w1, %w0\n"
319         "       nop\n"
320         "1:")
321         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
322         :
323         : "cc", "memory");
324
325         return !tmp2;
326 }
327
328 /* read_can_lock - would read_trylock() succeed? */
329 #define arch_read_can_lock(x)           ((x)->lock < 0x80000000)
330
331 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
332 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
333
334 #define arch_spin_relax(lock)   cpu_relax()
335 #define arch_read_relax(lock)   cpu_relax()
336 #define arch_write_relax(lock)  cpu_relax()
337
338 /*
339  * Accesses appearing in program order before a spin_lock() operation
340  * can be reordered with accesses inside the critical section, by virtue
341  * of arch_spin_lock being constructed using acquire semantics.
342  *
343  * In cases where this is problematic (e.g. try_to_wake_up), an
344  * smp_mb__before_spinlock() can restore the required ordering.
345  */
346 #define smp_mb__before_spinlock()       smp_mb()
347
348 #endif /* __ASM_SPINLOCK_H */