blob: f445bd7f2b9f2f573d99b0b739decb443c2b3666 [file] [log] [blame]
Catalin Marinas08e875c2012-03-05 11:49:30 +00001/*
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
Will Deacon81bb5c62015-02-10 03:03:15 +000019#include <asm/lse.h>
Catalin Marinas08e875c2012-03-05 11:49:30 +000020#include <asm/spinlock_types.h>
21#include <asm/processor.h>
22
23/*
24 * Spinlock implementation.
25 *
Catalin Marinas08e875c2012-03-05 11:49:30 +000026 * The memory barriers are implicit with the load-acquire and store-release
27 * instructions.
Catalin Marinas08e875c2012-03-05 11:49:30 +000028 */
Catalin Marinas08e875c2012-03-05 11:49:30 +000029
30#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
31
32static inline void arch_spin_lock(arch_spinlock_t *lock)
33{
34 unsigned int tmp;
Will Deacon52ea2a52013-10-09 15:54:26 +010035 arch_spinlock_t lockval, newval;
Catalin Marinas08e875c2012-03-05 11:49:30 +000036
37 asm volatile(
Will Deacon52ea2a52013-10-09 15:54:26 +010038 /* Atomically increment the next ticket. */
Will Deacon81bb5c62015-02-10 03:03:15 +000039 ARM64_LSE_ATOMIC_INSN(
40 /* LL/SC */
Will Deacon52ea2a52013-10-09 15:54:26 +010041" prfm pstl1strm, %3\n"
42"1: ldaxr %w0, %3\n"
43" add %w1, %w0, %w5\n"
44" stxr %w2, %w1, %3\n"
Will Deacon81bb5c62015-02-10 03:03:15 +000045" cbnz %w2, 1b\n",
46 /* LSE atomics */
47" mov %w2, %w5\n"
48" ldadda %w2, %w0, %3\n"
Will Deacon05492f22016-09-06 16:42:58 +010049 __nops(3)
Will Deacon81bb5c62015-02-10 03:03:15 +000050 )
51
Will Deacon52ea2a52013-10-09 15:54:26 +010052 /* Did we get the lock? */
53" eor %w1, %w0, %w0, ror #16\n"
54" cbz %w1, 3f\n"
55 /*
56 * No: spin on the owner. Send a local event to avoid missing an
57 * unlock before the exclusive load.
58 */
59" sevl\n"
60"2: wfe\n"
61" ldaxrh %w2, %4\n"
62" eor %w1, %w2, %w0, lsr #16\n"
63" cbnz %w1, 2b\n"
64 /* We got the lock. Critical section starts here. */
65"3:"
66 : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
67 : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
68 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +000069}
70
71static inline int arch_spin_trylock(arch_spinlock_t *lock)
72{
73 unsigned int tmp;
Will Deacon52ea2a52013-10-09 15:54:26 +010074 arch_spinlock_t lockval;
Catalin Marinas08e875c2012-03-05 11:49:30 +000075
Will Deacon81bb5c62015-02-10 03:03:15 +000076 asm volatile(ARM64_LSE_ATOMIC_INSN(
77 /* LL/SC */
78 " prfm pstl1strm, %2\n"
79 "1: ldaxr %w0, %2\n"
80 " eor %w1, %w0, %w0, ror #16\n"
81 " cbnz %w1, 2f\n"
82 " add %w0, %w0, %3\n"
83 " stxr %w1, %w0, %2\n"
84 " cbnz %w1, 1b\n"
85 "2:",
86 /* LSE atomics */
87 " ldr %w0, %2\n"
88 " eor %w1, %w0, %w0, ror #16\n"
89 " cbnz %w1, 1f\n"
90 " add %w1, %w0, %3\n"
91 " casa %w0, %w1, %2\n"
92 " and %w1, %w1, #0xffff\n"
93 " eor %w1, %w1, %w0, lsr #16\n"
94 "1:")
Will Deacon52ea2a52013-10-09 15:54:26 +010095 : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
96 : "I" (1 << TICKET_SHIFT)
97 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +000098
99 return !tmp;
100}
101
102static inline void arch_spin_unlock(arch_spinlock_t *lock)
103{
Will Deacon81bb5c62015-02-10 03:03:15 +0000104 unsigned long tmp;
105
106 asm volatile(ARM64_LSE_ATOMIC_INSN(
107 /* LL/SC */
Will Deaconc1d7cd22015-07-28 14:48:00 +0100108 " ldrh %w1, %0\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000109 " add %w1, %w1, #1\n"
110 " stlrh %w1, %0",
111 /* LSE atomics */
112 " mov %w1, #1\n"
Will Deacon05492f22016-09-06 16:42:58 +0100113 " staddlh %w1, %0\n"
114 __nops(1))
Will Deacon81bb5c62015-02-10 03:03:15 +0000115 : "=Q" (lock->owner), "=&r" (tmp)
116 :
Will Deacon52ea2a52013-10-09 15:54:26 +0100117 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000118}
119
Will Deacon5686b062013-10-09 15:54:27 +0100120static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
121{
122 return lock.owner == lock.next;
123}
124
Will Deacon52ea2a52013-10-09 15:54:26 +0100125static inline int arch_spin_is_locked(arch_spinlock_t *lock)
126{
Paul E. McKenney952111d2017-06-29 15:53:02 -0700127 /*
128 * Ensure prior spin_lock operations to other locks have completed
129 * on this CPU before we test whether "lock" is locked.
130 */
131 smp_mb(); /* ^^^ */
Christian Borntraegeraf2e7aa2014-11-24 10:53:11 +0100132 return !arch_spin_value_unlocked(READ_ONCE(*lock));
Will Deacon52ea2a52013-10-09 15:54:26 +0100133}
134
135static inline int arch_spin_is_contended(arch_spinlock_t *lock)
136{
Christian Borntraegeraf2e7aa2014-11-24 10:53:11 +0100137 arch_spinlock_t lockval = READ_ONCE(*lock);
Will Deacon52ea2a52013-10-09 15:54:26 +0100138 return (lockval.next - lockval.owner) > 1;
139}
140#define arch_spin_is_contended arch_spin_is_contended
141
Catalin Marinas08e875c2012-03-05 11:49:30 +0000142/*
143 * Write lock implementation.
144 *
145 * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
146 * exclusively held.
147 *
148 * The memory barriers are implicit with the load-acquire and store-release
149 * instructions.
150 */
151
152static inline void arch_write_lock(arch_rwlock_t *rw)
153{
154 unsigned int tmp;
155
Will Deacon81bb5c62015-02-10 03:03:15 +0000156 asm volatile(ARM64_LSE_ATOMIC_INSN(
157 /* LL/SC */
Catalin Marinas08e875c2012-03-05 11:49:30 +0000158 " sevl\n"
159 "1: wfe\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000160 "2: ldaxr %w0, %1\n"
Catalin Marinas08e875c2012-03-05 11:49:30 +0000161 " cbnz %w0, 1b\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000162 " stxr %w0, %w2, %1\n"
Catalin Marinas08e875c2012-03-05 11:49:30 +0000163 " cbnz %w0, 2b\n"
Will Deacon05492f22016-09-06 16:42:58 +0100164 __nops(1),
Will Deacon81bb5c62015-02-10 03:03:15 +0000165 /* LSE atomics */
166 "1: mov %w0, wzr\n"
167 "2: casa %w0, %w2, %1\n"
168 " cbz %w0, 3f\n"
169 " ldxr %w0, %1\n"
170 " cbz %w0, 2b\n"
171 " wfe\n"
172 " b 1b\n"
173 "3:")
Will Deacon3a0310e2013-02-04 12:12:33 +0000174 : "=&r" (tmp), "+Q" (rw->lock)
175 : "r" (0x80000000)
Will Deacon95c41892014-02-04 12:29:13 +0000176 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000177}
178
179static inline int arch_write_trylock(arch_rwlock_t *rw)
180{
181 unsigned int tmp;
182
Will Deacon81bb5c62015-02-10 03:03:15 +0000183 asm volatile(ARM64_LSE_ATOMIC_INSN(
184 /* LL/SC */
Will Deacon9511ca12015-07-22 18:25:52 +0100185 "1: ldaxr %w0, %1\n"
186 " cbnz %w0, 2f\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000187 " stxr %w0, %w2, %1\n"
Will Deacon9511ca12015-07-22 18:25:52 +0100188 " cbnz %w0, 1b\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000189 "2:",
190 /* LSE atomics */
191 " mov %w0, wzr\n"
192 " casa %w0, %w2, %1\n"
Will Deacon05492f22016-09-06 16:42:58 +0100193 __nops(2))
Will Deacon3a0310e2013-02-04 12:12:33 +0000194 : "=&r" (tmp), "+Q" (rw->lock)
195 : "r" (0x80000000)
Will Deacon95c41892014-02-04 12:29:13 +0000196 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000197
198 return !tmp;
199}
200
201static inline void arch_write_unlock(arch_rwlock_t *rw)
202{
Will Deacon81bb5c62015-02-10 03:03:15 +0000203 asm volatile(ARM64_LSE_ATOMIC_INSN(
204 " stlr wzr, %0",
205 " swpl wzr, wzr, %0")
206 : "=Q" (rw->lock) :: "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000207}
208
209/* write_can_lock - would write_trylock() succeed? */
210#define arch_write_can_lock(x) ((x)->lock == 0)
211
212/*
213 * Read lock implementation.
214 *
215 * It exclusively loads the lock value, increments it and stores the new value
216 * back if positive and the CPU still exclusively owns the location. If the
217 * value is negative, the lock is already held.
218 *
219 * During unlocking there may be multiple active read locks but no write lock.
220 *
221 * The memory barriers are implicit with the load-acquire and store-release
222 * instructions.
Will Deacon81bb5c62015-02-10 03:03:15 +0000223 *
224 * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
225 * and LSE implementations may exhibit different behaviour (although this
226 * will have no effect on lockdep).
Catalin Marinas08e875c2012-03-05 11:49:30 +0000227 */
228static inline void arch_read_lock(arch_rwlock_t *rw)
229{
230 unsigned int tmp, tmp2;
231
232 asm volatile(
233 " sevl\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000234 ARM64_LSE_ATOMIC_INSN(
235 /* LL/SC */
Catalin Marinas08e875c2012-03-05 11:49:30 +0000236 "1: wfe\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000237 "2: ldaxr %w0, %2\n"
Catalin Marinas08e875c2012-03-05 11:49:30 +0000238 " add %w0, %w0, #1\n"
239 " tbnz %w0, #31, 1b\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000240 " stxr %w1, %w0, %2\n"
Will Deacon05492f22016-09-06 16:42:58 +0100241 " cbnz %w1, 2b\n"
242 __nops(1),
Will Deacon81bb5c62015-02-10 03:03:15 +0000243 /* LSE atomics */
244 "1: wfe\n"
245 "2: ldxr %w0, %2\n"
246 " adds %w1, %w0, #1\n"
247 " tbnz %w1, #31, 1b\n"
248 " casa %w0, %w1, %2\n"
249 " sbc %w0, %w1, %w0\n"
250 " cbnz %w0, 2b")
Will Deacon3a0310e2013-02-04 12:12:33 +0000251 : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
252 :
Will Deacon81bb5c62015-02-10 03:03:15 +0000253 : "cc", "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000254}
255
256static inline void arch_read_unlock(arch_rwlock_t *rw)
257{
258 unsigned int tmp, tmp2;
259
Will Deacon81bb5c62015-02-10 03:03:15 +0000260 asm volatile(ARM64_LSE_ATOMIC_INSN(
261 /* LL/SC */
Will Deacon3a0310e2013-02-04 12:12:33 +0000262 "1: ldxr %w0, %2\n"
Catalin Marinas08e875c2012-03-05 11:49:30 +0000263 " sub %w0, %w0, #1\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000264 " stlxr %w1, %w0, %2\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000265 " cbnz %w1, 1b",
266 /* LSE atomics */
267 " movn %w0, #0\n"
Will Deacon05492f22016-09-06 16:42:58 +0100268 " staddl %w0, %2\n"
269 __nops(2))
Will Deacon3a0310e2013-02-04 12:12:33 +0000270 : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
271 :
Will Deacon95c41892014-02-04 12:29:13 +0000272 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000273}
274
275static inline int arch_read_trylock(arch_rwlock_t *rw)
276{
Will Deacon81bb5c62015-02-10 03:03:15 +0000277 unsigned int tmp, tmp2;
Catalin Marinas08e875c2012-03-05 11:49:30 +0000278
Will Deacon81bb5c62015-02-10 03:03:15 +0000279 asm volatile(ARM64_LSE_ATOMIC_INSN(
280 /* LL/SC */
281 " mov %w1, #1\n"
Will Deacon9511ca12015-07-22 18:25:52 +0100282 "1: ldaxr %w0, %2\n"
Catalin Marinas08e875c2012-03-05 11:49:30 +0000283 " add %w0, %w0, #1\n"
Will Deacon9511ca12015-07-22 18:25:52 +0100284 " tbnz %w0, #31, 2f\n"
Will Deacon3a0310e2013-02-04 12:12:33 +0000285 " stxr %w1, %w0, %2\n"
Will Deacon9511ca12015-07-22 18:25:52 +0100286 " cbnz %w1, 1b\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000287 "2:",
288 /* LSE atomics */
289 " ldr %w0, %2\n"
290 " adds %w1, %w0, #1\n"
291 " tbnz %w1, #31, 1f\n"
292 " casa %w0, %w1, %2\n"
293 " sbc %w1, %w1, %w0\n"
Will Deacon05492f22016-09-06 16:42:58 +0100294 __nops(1)
Will Deacon81bb5c62015-02-10 03:03:15 +0000295 "1:")
296 : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
Will Deacon3a0310e2013-02-04 12:12:33 +0000297 :
Will Deacon81bb5c62015-02-10 03:03:15 +0000298 : "cc", "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000299
300 return !tmp2;
301}
302
303/* read_can_lock - would read_trylock() succeed? */
304#define arch_read_can_lock(x) ((x)->lock < 0x80000000)
305
306#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
307#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
308
309#define arch_spin_relax(lock) cpu_relax()
310#define arch_read_relax(lock) cpu_relax()
311#define arch_write_relax(lock) cpu_relax()
312
Will Deacon872c63f2016-09-05 11:56:05 +0100313/*
314 * Accesses appearing in program order before a spin_lock() operation
315 * can be reordered with accesses inside the critical section, by virtue
316 * of arch_spin_lock being constructed using acquire semantics.
317 *
318 * In cases where this is problematic (e.g. try_to_wake_up), an
319 * smp_mb__before_spinlock() can restore the required ordering.
320 */
321#define smp_mb__before_spinlock() smp_mb()
322
Catalin Marinas08e875c2012-03-05 11:49:30 +0000323#endif /* __ASM_SPINLOCK_H */