spi: rockchip: Signal unfinished DMA transfers
[cascardo/linux.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         ARM64_LSE_ATOMIC_INSN(
41         /* LL/SC */
42 "       stxr    %w1, %w0, %2\n"
43 "       cbnz    %w1, 2b\n", /* Serialise against any concurrent lockers */
44         /* LSE atomics */
45 "       nop\n"
46 "       nop\n")
47         : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
48         :
49         : "memory");
50 }
51
52 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
53
54 static inline void arch_spin_lock(arch_spinlock_t *lock)
55 {
56         unsigned int tmp;
57         arch_spinlock_t lockval, newval;
58
59         asm volatile(
60         /* Atomically increment the next ticket. */
61         ARM64_LSE_ATOMIC_INSN(
62         /* LL/SC */
63 "       prfm    pstl1strm, %3\n"
64 "1:     ldaxr   %w0, %3\n"
65 "       add     %w1, %w0, %w5\n"
66 "       stxr    %w2, %w1, %3\n"
67 "       cbnz    %w2, 1b\n",
68         /* LSE atomics */
69 "       mov     %w2, %w5\n"
70 "       ldadda  %w2, %w0, %3\n"
71 "       nop\n"
72 "       nop\n"
73 "       nop\n"
74         )
75
76         /* Did we get the lock? */
77 "       eor     %w1, %w0, %w0, ror #16\n"
78 "       cbz     %w1, 3f\n"
79         /*
80          * No: spin on the owner. Send a local event to avoid missing an
81          * unlock before the exclusive load.
82          */
83 "       sevl\n"
84 "2:     wfe\n"
85 "       ldaxrh  %w2, %4\n"
86 "       eor     %w1, %w2, %w0, lsr #16\n"
87 "       cbnz    %w1, 2b\n"
88         /* We got the lock. Critical section starts here. */
89 "3:"
90         : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
91         : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
92         : "memory");
93 }
94
95 static inline int arch_spin_trylock(arch_spinlock_t *lock)
96 {
97         unsigned int tmp;
98         arch_spinlock_t lockval;
99
100         asm volatile(ARM64_LSE_ATOMIC_INSN(
101         /* LL/SC */
102         "       prfm    pstl1strm, %2\n"
103         "1:     ldaxr   %w0, %2\n"
104         "       eor     %w1, %w0, %w0, ror #16\n"
105         "       cbnz    %w1, 2f\n"
106         "       add     %w0, %w0, %3\n"
107         "       stxr    %w1, %w0, %2\n"
108         "       cbnz    %w1, 1b\n"
109         "2:",
110         /* LSE atomics */
111         "       ldr     %w0, %2\n"
112         "       eor     %w1, %w0, %w0, ror #16\n"
113         "       cbnz    %w1, 1f\n"
114         "       add     %w1, %w0, %3\n"
115         "       casa    %w0, %w1, %2\n"
116         "       and     %w1, %w1, #0xffff\n"
117         "       eor     %w1, %w1, %w0, lsr #16\n"
118         "1:")
119         : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
120         : "I" (1 << TICKET_SHIFT)
121         : "memory");
122
123         return !tmp;
124 }
125
126 static inline void arch_spin_unlock(arch_spinlock_t *lock)
127 {
128         unsigned long tmp;
129
130         asm volatile(ARM64_LSE_ATOMIC_INSN(
131         /* LL/SC */
132         "       ldrh    %w1, %0\n"
133         "       add     %w1, %w1, #1\n"
134         "       stlrh   %w1, %0",
135         /* LSE atomics */
136         "       mov     %w1, #1\n"
137         "       nop\n"
138         "       staddlh %w1, %0")
139         : "=Q" (lock->owner), "=&r" (tmp)
140         :
141         : "memory");
142 }
143
144 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
145 {
146         return lock.owner == lock.next;
147 }
148
149 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
150 {
151         return !arch_spin_value_unlocked(READ_ONCE(*lock));
152 }
153
154 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
155 {
156         arch_spinlock_t lockval = READ_ONCE(*lock);
157         return (lockval.next - lockval.owner) > 1;
158 }
159 #define arch_spin_is_contended  arch_spin_is_contended
160
161 /*
162  * Write lock implementation.
163  *
164  * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
165  * exclusively held.
166  *
167  * The memory barriers are implicit with the load-acquire and store-release
168  * instructions.
169  */
170
171 static inline void arch_write_lock(arch_rwlock_t *rw)
172 {
173         unsigned int tmp;
174
175         asm volatile(ARM64_LSE_ATOMIC_INSN(
176         /* LL/SC */
177         "       sevl\n"
178         "1:     wfe\n"
179         "2:     ldaxr   %w0, %1\n"
180         "       cbnz    %w0, 1b\n"
181         "       stxr    %w0, %w2, %1\n"
182         "       cbnz    %w0, 2b\n"
183         "       nop",
184         /* LSE atomics */
185         "1:     mov     %w0, wzr\n"
186         "2:     casa    %w0, %w2, %1\n"
187         "       cbz     %w0, 3f\n"
188         "       ldxr    %w0, %1\n"
189         "       cbz     %w0, 2b\n"
190         "       wfe\n"
191         "       b       1b\n"
192         "3:")
193         : "=&r" (tmp), "+Q" (rw->lock)
194         : "r" (0x80000000)
195         : "memory");
196 }
197
198 static inline int arch_write_trylock(arch_rwlock_t *rw)
199 {
200         unsigned int tmp;
201
202         asm volatile(ARM64_LSE_ATOMIC_INSN(
203         /* LL/SC */
204         "1:     ldaxr   %w0, %1\n"
205         "       cbnz    %w0, 2f\n"
206         "       stxr    %w0, %w2, %1\n"
207         "       cbnz    %w0, 1b\n"
208         "2:",
209         /* LSE atomics */
210         "       mov     %w0, wzr\n"
211         "       casa    %w0, %w2, %1\n"
212         "       nop\n"
213         "       nop")
214         : "=&r" (tmp), "+Q" (rw->lock)
215         : "r" (0x80000000)
216         : "memory");
217
218         return !tmp;
219 }
220
221 static inline void arch_write_unlock(arch_rwlock_t *rw)
222 {
223         asm volatile(ARM64_LSE_ATOMIC_INSN(
224         "       stlr    wzr, %0",
225         "       swpl    wzr, wzr, %0")
226         : "=Q" (rw->lock) :: "memory");
227 }
228
229 /* write_can_lock - would write_trylock() succeed? */
230 #define arch_write_can_lock(x)          ((x)->lock == 0)
231
232 /*
233  * Read lock implementation.
234  *
235  * It exclusively loads the lock value, increments it and stores the new value
236  * back if positive and the CPU still exclusively owns the location. If the
237  * value is negative, the lock is already held.
238  *
239  * During unlocking there may be multiple active read locks but no write lock.
240  *
241  * The memory barriers are implicit with the load-acquire and store-release
242  * instructions.
243  *
244  * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
245  * and LSE implementations may exhibit different behaviour (although this
246  * will have no effect on lockdep).
247  */
248 static inline void arch_read_lock(arch_rwlock_t *rw)
249 {
250         unsigned int tmp, tmp2;
251
252         asm volatile(
253         "       sevl\n"
254         ARM64_LSE_ATOMIC_INSN(
255         /* LL/SC */
256         "1:     wfe\n"
257         "2:     ldaxr   %w0, %2\n"
258         "       add     %w0, %w0, #1\n"
259         "       tbnz    %w0, #31, 1b\n"
260         "       stxr    %w1, %w0, %2\n"
261         "       nop\n"
262         "       cbnz    %w1, 2b",
263         /* LSE atomics */
264         "1:     wfe\n"
265         "2:     ldxr    %w0, %2\n"
266         "       adds    %w1, %w0, #1\n"
267         "       tbnz    %w1, #31, 1b\n"
268         "       casa    %w0, %w1, %2\n"
269         "       sbc     %w0, %w1, %w0\n"
270         "       cbnz    %w0, 2b")
271         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
272         :
273         : "cc", "memory");
274 }
275
276 static inline void arch_read_unlock(arch_rwlock_t *rw)
277 {
278         unsigned int tmp, tmp2;
279
280         asm volatile(ARM64_LSE_ATOMIC_INSN(
281         /* LL/SC */
282         "1:     ldxr    %w0, %2\n"
283         "       sub     %w0, %w0, #1\n"
284         "       stlxr   %w1, %w0, %2\n"
285         "       cbnz    %w1, 1b",
286         /* LSE atomics */
287         "       movn    %w0, #0\n"
288         "       nop\n"
289         "       nop\n"
290         "       staddl  %w0, %2")
291         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
292         :
293         : "memory");
294 }
295
296 static inline int arch_read_trylock(arch_rwlock_t *rw)
297 {
298         unsigned int tmp, tmp2;
299
300         asm volatile(ARM64_LSE_ATOMIC_INSN(
301         /* LL/SC */
302         "       mov     %w1, #1\n"
303         "1:     ldaxr   %w0, %2\n"
304         "       add     %w0, %w0, #1\n"
305         "       tbnz    %w0, #31, 2f\n"
306         "       stxr    %w1, %w0, %2\n"
307         "       cbnz    %w1, 1b\n"
308         "2:",
309         /* LSE atomics */
310         "       ldr     %w0, %2\n"
311         "       adds    %w1, %w0, #1\n"
312         "       tbnz    %w1, #31, 1f\n"
313         "       casa    %w0, %w1, %2\n"
314         "       sbc     %w1, %w1, %w0\n"
315         "       nop\n"
316         "1:")
317         : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
318         :
319         : "cc", "memory");
320
321         return !tmp2;
322 }
323
324 /* read_can_lock - would read_trylock() succeed? */
325 #define arch_read_can_lock(x)           ((x)->lock < 0x80000000)
326
327 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
328 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
329
330 #define arch_spin_relax(lock)   cpu_relax()
331 #define arch_read_relax(lock)   cpu_relax()
332 #define arch_write_relax(lock)  cpu_relax()
333
334 #endif /* __ASM_SPINLOCK_H */