mm: hugetlb: fix hugepage memory leak caused by wrong reserve count
[linux/fpc-iii.git] / arch / arm64 / include / asm / spinlock.h
blobc85e96d174a5fbd4764adb748b9bc11c70479617
1 /*
2 * Copyright (C) 2012 ARM Ltd.
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.
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.
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/>.
16 #ifndef __ASM_SPINLOCK_H
17 #define __ASM_SPINLOCK_H
19 #include <asm/lse.h>
20 #include <asm/spinlock_types.h>
21 #include <asm/processor.h>
24 * Spinlock implementation.
26 * The memory barriers are implicit with the load-acquire and store-release
27 * instructions.
30 #define arch_spin_unlock_wait(lock) \
31 do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
33 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
35 static inline void arch_spin_lock(arch_spinlock_t *lock)
37 unsigned int tmp;
38 arch_spinlock_t lockval, newval;
40 asm volatile(
41 /* Atomically increment the next ticket. */
42 ARM64_LSE_ATOMIC_INSN(
43 /* LL/SC */
44 " prfm pstl1strm, %3\n"
45 "1: ldaxr %w0, %3\n"
46 " add %w1, %w0, %w5\n"
47 " stxr %w2, %w1, %3\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"
57 /* Did we get the lock? */
58 " eor %w1, %w0, %w0, ror #16\n"
59 " cbz %w1, 3f\n"
61 * No: spin on the owner. Send a local event to avoid missing an
62 * unlock before the exclusive load.
64 " sevl\n"
65 "2: wfe\n"
66 " ldaxrh %w2, %4\n"
67 " eor %w1, %w2, %w0, lsr #16\n"
68 " cbnz %w1, 2b\n"
69 /* We got the lock. Critical section starts here. */
70 "3:"
71 : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
72 : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
73 : "memory");
76 static inline int arch_spin_trylock(arch_spinlock_t *lock)
78 unsigned int tmp;
79 arch_spinlock_t lockval;
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:")
100 : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
101 : "I" (1 << TICKET_SHIFT)
102 : "memory");
104 return !tmp;
107 static inline void arch_spin_unlock(arch_spinlock_t *lock)
109 unsigned long tmp;
111 asm volatile(ARM64_LSE_ATOMIC_INSN(
112 /* LL/SC */
113 " ldrh %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)
122 : "memory");
125 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
127 return lock.owner == lock.next;
130 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
132 return !arch_spin_value_unlocked(READ_ONCE(*lock));
135 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
137 arch_spinlock_t lockval = READ_ONCE(*lock);
138 return (lockval.next - lockval.owner) > 1;
140 #define arch_spin_is_contended arch_spin_is_contended
143 * Write lock implementation.
145 * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is
146 * exclusively held.
148 * The memory barriers are implicit with the load-acquire and store-release
149 * instructions.
152 static inline void arch_write_lock(arch_rwlock_t *rw)
154 unsigned int tmp;
156 asm volatile(ARM64_LSE_ATOMIC_INSN(
157 /* LL/SC */
158 " sevl\n"
159 "1: wfe\n"
160 "2: ldaxr %w0, %1\n"
161 " cbnz %w0, 1b\n"
162 " stxr %w0, %w2, %1\n"
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:")
174 : "=&r" (tmp), "+Q" (rw->lock)
175 : "r" (0x80000000)
176 : "memory");
179 static inline int arch_write_trylock(arch_rwlock_t *rw)
181 unsigned int tmp;
183 asm volatile(ARM64_LSE_ATOMIC_INSN(
184 /* LL/SC */
185 "1: ldaxr %w0, %1\n"
186 " cbnz %w0, 2f\n"
187 " stxr %w0, %w2, %1\n"
188 " cbnz %w0, 1b\n"
189 "2:",
190 /* LSE atomics */
191 " mov %w0, wzr\n"
192 " casa %w0, %w2, %1\n"
193 " nop\n"
194 " nop")
195 : "=&r" (tmp), "+Q" (rw->lock)
196 : "r" (0x80000000)
197 : "memory");
199 return !tmp;
202 static inline void arch_write_unlock(arch_rwlock_t *rw)
204 asm volatile(ARM64_LSE_ATOMIC_INSN(
205 " stlr wzr, %0",
206 " swpl wzr, wzr, %0")
207 : "=Q" (rw->lock) :: "memory");
210 /* write_can_lock - would write_trylock() succeed? */
211 #define arch_write_can_lock(x) ((x)->lock == 0)
214 * Read lock implementation.
216 * It exclusively loads the lock value, increments it and stores the new value
217 * back if positive and the CPU still exclusively owns the location. If the
218 * value is negative, the lock is already held.
220 * During unlocking there may be multiple active read locks but no write lock.
222 * The memory barriers are implicit with the load-acquire and store-release
223 * instructions.
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).
229 static inline void arch_read_lock(arch_rwlock_t *rw)
231 unsigned int tmp, tmp2;
233 asm volatile(
234 " sevl\n"
235 ARM64_LSE_ATOMIC_INSN(
236 /* LL/SC */
237 "1: wfe\n"
238 "2: ldaxr %w0, %2\n"
239 " add %w0, %w0, #1\n"
240 " tbnz %w0, #31, 1b\n"
241 " stxr %w1, %w0, %2\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")
252 : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
254 : "cc", "memory");
257 static inline void arch_read_unlock(arch_rwlock_t *rw)
259 unsigned int tmp, tmp2;
261 asm volatile(ARM64_LSE_ATOMIC_INSN(
262 /* LL/SC */
263 "1: ldxr %w0, %2\n"
264 " sub %w0, %w0, #1\n"
265 " stlxr %w1, %w0, %2\n"
266 " cbnz %w1, 1b",
267 /* LSE atomics */
268 " movn %w0, #0\n"
269 " nop\n"
270 " nop\n"
271 " staddl %w0, %2")
272 : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
274 : "memory");
277 static inline int arch_read_trylock(arch_rwlock_t *rw)
279 unsigned int tmp, tmp2;
281 asm volatile(ARM64_LSE_ATOMIC_INSN(
282 /* LL/SC */
283 " mov %w1, #1\n"
284 "1: ldaxr %w0, %2\n"
285 " add %w0, %w0, #1\n"
286 " tbnz %w0, #31, 2f\n"
287 " stxr %w1, %w0, %2\n"
288 " cbnz %w1, 1b\n"
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)
300 : "cc", "memory");
302 return !tmp2;
305 /* read_can_lock - would read_trylock() succeed? */
306 #define arch_read_can_lock(x) ((x)->lock < 0x80000000)
308 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
309 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
311 #define arch_spin_relax(lock) cpu_relax()
312 #define arch_read_relax(lock) cpu_relax()
313 #define arch_write_relax(lock) cpu_relax()
315 #endif /* __ASM_SPINLOCK_H */