16
16
#ifndef __ASM_SPINLOCK_H
17
17
#define __ASM_SPINLOCK_H
18
18
19
+ #include <asm/lse.h>
19
20
#include <asm/spinlock_types.h>
20
21
#include <asm/processor.h>
21
22
@@ -38,11 +39,21 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
38
39
39
40
asm volatile (
40
41
/* Atomically increment the next ticket. */
42
+ ARM64_LSE_ATOMIC_INSN (
43
+ /* LL/SC */
41
44
" prfm pstl1strm, %3\n"
42
45
"1: ldaxr %w0, %3\n"
43
46
" add %w1, %w0, %w5\n"
44
47
" stxr %w2, %w1, %3\n"
45
- " cbnz %w2, 1b\n"
48
+ " cbnz %w2, 1b\n" ,
49
+ /* LSE atomics */
50
+ " mov %w2, %w5\n"
51
+ " ldadda %w2, %w0, %3\n"
52
+ " nop\n"
53
+ " nop\n"
54
+ " nop\n"
55
+ )
56
+
46
57
/* Did we get the lock? */
47
58
" eor %w1, %w0, %w0, ror #16\n"
48
59
" cbz %w1, 3f\n"
@@ -67,15 +78,25 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
67
78
unsigned int tmp ;
68
79
arch_spinlock_t lockval ;
69
80
70
- asm volatile (
71
- " prfm pstl1strm, %2\n"
72
- "1: ldaxr %w0, %2\n"
73
- " eor %w1, %w0, %w0, ror #16\n"
74
- " cbnz %w1, 2f\n"
75
- " add %w0, %w0, %3\n"
76
- " stxr %w1, %w0, %2\n"
77
- " cbnz %w1, 1b\n"
78
- "2:"
81
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
82
+ /* LL/SC */
83
+ " prfm pstl1strm, %2\n"
84
+ "1: ldaxr %w0, %2\n"
85
+ " eor %w1, %w0, %w0, ror #16\n"
86
+ " cbnz %w1, 2f\n"
87
+ " add %w0, %w0, %3\n"
88
+ " stxr %w1, %w0, %2\n"
89
+ " cbnz %w1, 1b\n"
90
+ "2:" ,
91
+ /* LSE atomics */
92
+ " ldr %w0, %2\n"
93
+ " eor %w1, %w0, %w0, ror #16\n"
94
+ " cbnz %w1, 1f\n"
95
+ " add %w1, %w0, %3\n"
96
+ " casa %w0, %w1, %2\n"
97
+ " and %w1, %w1, #0xffff\n"
98
+ " eor %w1, %w1, %w0, lsr #16\n"
99
+ "1:" )
79
100
: "=&r" (lockval ), "=&r" (tmp ), "+Q" (* lock )
80
101
: "I" (1 << TICKET_SHIFT )
81
102
: "memory" );
@@ -85,10 +106,19 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
85
106
86
107
static inline void arch_spin_unlock (arch_spinlock_t * lock )
87
108
{
88
- asm volatile (
89
- " stlrh %w1, %0\n"
90
- : "=Q" (lock -> owner )
91
- : "r" (lock -> owner + 1 )
109
+ unsigned long tmp ;
110
+
111
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
112
+ /* LL/SC */
113
+ " ldr %w1, %0\n"
114
+ " add %w1, %w1, #1\n"
115
+ " stlrh %w1, %0" ,
116
+ /* LSE atomics */
117
+ " mov %w1, #1\n"
118
+ " nop\n"
119
+ " staddlh %w1, %0" )
120
+ : "=Q" (lock -> owner ), "=&r" (tmp )
121
+ :
92
122
: "memory" );
93
123
}
94
124
@@ -123,13 +153,24 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
123
153
{
124
154
unsigned int tmp ;
125
155
126
- asm volatile (
156
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
157
+ /* LL/SC */
127
158
" sevl\n"
128
159
"1: wfe\n"
129
160
"2: ldaxr %w0, %1\n"
130
161
" cbnz %w0, 1b\n"
131
162
" stxr %w0, %w2, %1\n"
132
163
" cbnz %w0, 2b\n"
164
+ " nop" ,
165
+ /* 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:" )
133
174
: "=&r" (tmp ), "+Q" (rw -> lock )
134
175
: "r" (0x80000000 )
135
176
: "memory" );
@@ -139,12 +180,18 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
139
180
{
140
181
unsigned int tmp ;
141
182
142
- asm volatile (
183
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
184
+ /* LL/SC */
143
185
"1: ldaxr %w0, %1\n"
144
186
" cbnz %w0, 2f\n"
145
187
" stxr %w0, %w2, %1\n"
146
188
" cbnz %w0, 1b\n"
147
- "2:\n"
189
+ "2:" ,
190
+ /* LSE atomics */
191
+ " mov %w0, wzr\n"
192
+ " casa %w0, %w2, %1\n"
193
+ " nop\n"
194
+ " nop" )
148
195
: "=&r" (tmp ), "+Q" (rw -> lock )
149
196
: "r" (0x80000000 )
150
197
: "memory" );
@@ -154,9 +201,10 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
154
201
155
202
static inline void arch_write_unlock (arch_rwlock_t * rw )
156
203
{
157
- asm volatile (
158
- " stlr %w1, %0\n"
159
- : "=Q" (rw -> lock ) : "r" (0 ) : "memory" );
204
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
205
+ " stlr wzr, %0" ,
206
+ " swpl wzr, wzr, %0" )
207
+ : "=Q" (rw -> lock ) :: "memory" );
160
208
}
161
209
162
210
/* write_can_lock - would write_trylock() succeed? */
@@ -173,52 +221,83 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
173
221
*
174
222
* The memory barriers are implicit with the load-acquire and store-release
175
223
* instructions.
224
+ *
225
+ * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC
226
+ * and LSE implementations may exhibit different behaviour (although this
227
+ * will have no effect on lockdep).
176
228
*/
177
229
static inline void arch_read_lock (arch_rwlock_t * rw )
178
230
{
179
231
unsigned int tmp , tmp2 ;
180
232
181
233
asm volatile (
182
234
" sevl\n"
235
+ ARM64_LSE_ATOMIC_INSN (
236
+ /* LL/SC */
183
237
"1: wfe\n"
184
238
"2: ldaxr %w0, %2\n"
185
239
" add %w0, %w0, #1\n"
186
240
" tbnz %w0, #31, 1b\n"
187
241
" stxr %w1, %w0, %2\n"
188
- " cbnz %w1, 2b\n"
242
+ " nop\n"
243
+ " cbnz %w1, 2b" ,
244
+ /* LSE atomics */
245
+ "1: wfe\n"
246
+ "2: ldxr %w0, %2\n"
247
+ " adds %w1, %w0, #1\n"
248
+ " tbnz %w1, #31, 1b\n"
249
+ " casa %w0, %w1, %2\n"
250
+ " sbc %w0, %w1, %w0\n"
251
+ " cbnz %w0, 2b" )
189
252
: "= & r " (tmp), " = & r " (tmp2), " + Q " (rw->lock)
190
253
:
191
- : "memory" );
254
+ : " cc ", " memory ");
192
255
}
193
256
194
257
static inline void arch_read_unlock (arch_rwlock_t * rw )
195
258
{
196
259
unsigned int tmp , tmp2 ;
197
260
198
- asm volatile (
261
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
262
+ /* LL/SC */
199
263
"1: ldxr %w0, %2\n"
200
264
" sub %w0, %w0, #1\n"
201
265
" stlxr %w1, %w0, %2\n"
202
- " cbnz %w1, 1b\n"
266
+ " cbnz %w1, 1b" ,
267
+ /* LSE atomics */
268
+ " movn %w0, #0\n"
269
+ " nop\n"
270
+ " nop\n"
271
+ " staddl %w0, %2" )
203
272
: "=&r" (tmp ), "=&r" (tmp2 ), "+Q" (rw -> lock )
204
273
:
205
274
: "memory" );
206
275
}
207
276
208
277
static inline int arch_read_trylock (arch_rwlock_t * rw )
209
278
{
210
- unsigned int tmp , tmp2 = 1 ;
279
+ unsigned int tmp , tmp2 ;
211
280
212
- asm volatile (
281
+ asm volatile (ARM64_LSE_ATOMIC_INSN (
282
+ /* LL/SC */
283
+ " mov %w1, #1\n"
213
284
"1: ldaxr %w0, %2\n"
214
285
" add %w0, %w0, #1\n"
215
286
" tbnz %w0, #31, 2f\n"
216
287
" stxr %w1, %w0, %2\n"
217
288
" cbnz %w1, 1b\n"
218
- "2:\n"
219
- : "=&r" (tmp ), "+r" (tmp2 ), "+Q" (rw -> lock )
289
+ "2:" ,
290
+ /* LSE atomics */
291
+ " ldr %w0, %2\n"
292
+ " adds %w1, %w0, #1\n"
293
+ " tbnz %w1, #31, 1f\n"
294
+ " casa %w0, %w1, %2\n"
295
+ " sbc %w1, %w1, %w0\n"
296
+ " nop\n"
297
+ "1:" )
298
+ : "=&r" (tmp ), "=&r" (tmp2 ), "+Q" (rw -> lock )
220
299
:
221
- : "memory" );
300
+ : "cc" , " memory" );
222
301
223
302
return !tmp2 ;
224
303
}
0 commit comments