blob: 26c5bd7d88d8d95099157ef8dc1668d693cc5ae7 [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
Catalin Marinas08e875c2012-03-05 11:49:30 +000030static inline void arch_spin_lock(arch_spinlock_t *lock)
31{
32 unsigned int tmp;
Will Deacon52ea2a52013-10-09 15:54:26 +010033 arch_spinlock_t lockval, newval;
Catalin Marinas08e875c2012-03-05 11:49:30 +000034
35 asm volatile(
Will Deacon52ea2a52013-10-09 15:54:26 +010036 /* Atomically increment the next ticket. */
Will Deacon81bb5c62015-02-10 03:03:15 +000037 ARM64_LSE_ATOMIC_INSN(
38 /* LL/SC */
Will Deacon52ea2a52013-10-09 15:54:26 +010039" prfm pstl1strm, %3\n"
40"1: ldaxr %w0, %3\n"
41" add %w1, %w0, %w5\n"
42" stxr %w2, %w1, %3\n"
Will Deacon81bb5c62015-02-10 03:03:15 +000043" cbnz %w2, 1b\n",
44 /* LSE atomics */
45" mov %w2, %w5\n"
46" ldadda %w2, %w0, %3\n"
Will Deacon05492f22016-09-06 16:42:58 +010047 __nops(3)
Will Deacon81bb5c62015-02-10 03:03:15 +000048 )
49
Will Deacon52ea2a52013-10-09 15:54:26 +010050 /* Did we get the lock? */
51" eor %w1, %w0, %w0, ror #16\n"
52" cbz %w1, 3f\n"
53 /*
54 * No: spin on the owner. Send a local event to avoid missing an
55 * unlock before the exclusive load.
56 */
57" sevl\n"
58"2: wfe\n"
59" ldaxrh %w2, %4\n"
60" eor %w1, %w2, %w0, lsr #16\n"
61" cbnz %w1, 2b\n"
62 /* We got the lock. Critical section starts here. */
63"3:"
64 : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
65 : "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
66 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +000067}
68
69static inline int arch_spin_trylock(arch_spinlock_t *lock)
70{
71 unsigned int tmp;
Will Deacon52ea2a52013-10-09 15:54:26 +010072 arch_spinlock_t lockval;
Catalin Marinas08e875c2012-03-05 11:49:30 +000073
Will Deacon81bb5c62015-02-10 03:03:15 +000074 asm volatile(ARM64_LSE_ATOMIC_INSN(
75 /* LL/SC */
76 " prfm pstl1strm, %2\n"
77 "1: ldaxr %w0, %2\n"
78 " eor %w1, %w0, %w0, ror #16\n"
79 " cbnz %w1, 2f\n"
80 " add %w0, %w0, %3\n"
81 " stxr %w1, %w0, %2\n"
82 " cbnz %w1, 1b\n"
83 "2:",
84 /* LSE atomics */
85 " ldr %w0, %2\n"
86 " eor %w1, %w0, %w0, ror #16\n"
87 " cbnz %w1, 1f\n"
88 " add %w1, %w0, %3\n"
89 " casa %w0, %w1, %2\n"
Will Deacon202fb4e2018-01-31 12:12:20 +000090 " sub %w1, %w1, %3\n"
91 " eor %w1, %w1, %w0\n"
Will Deacon81bb5c62015-02-10 03:03:15 +000092 "1:")
Will Deacon52ea2a52013-10-09 15:54:26 +010093 : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
94 : "I" (1 << TICKET_SHIFT)
95 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +000096
97 return !tmp;
98}
99
100static inline void arch_spin_unlock(arch_spinlock_t *lock)
101{
Will Deacon81bb5c62015-02-10 03:03:15 +0000102 unsigned long tmp;
103
104 asm volatile(ARM64_LSE_ATOMIC_INSN(
105 /* LL/SC */
Will Deaconc1d7cd22015-07-28 14:48:00 +0100106 " ldrh %w1, %0\n"
Will Deacon81bb5c62015-02-10 03:03:15 +0000107 " add %w1, %w1, #1\n"
108 " stlrh %w1, %0",
109 /* LSE atomics */
110 " mov %w1, #1\n"
Will Deacon05492f22016-09-06 16:42:58 +0100111 " staddlh %w1, %0\n"
112 __nops(1))
Will Deacon81bb5c62015-02-10 03:03:15 +0000113 : "=Q" (lock->owner), "=&r" (tmp)
114 :
Will Deacon52ea2a52013-10-09 15:54:26 +0100115 : "memory");
Catalin Marinas08e875c2012-03-05 11:49:30 +0000116}
117
Will Deacon5686b062013-10-09 15:54:27 +0100118static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
119{
120 return lock.owner == lock.next;
121}
122
Will Deacon52ea2a52013-10-09 15:54:26 +0100123static inline int arch_spin_is_locked(arch_spinlock_t *lock)
124{
Christian Borntraegeraf2e7aa2014-11-24 10:53:11 +0100125 return !arch_spin_value_unlocked(READ_ONCE(*lock));
Will Deacon52ea2a52013-10-09 15:54:26 +0100126}
127
128static inline int arch_spin_is_contended(arch_spinlock_t *lock)
129{
Christian Borntraegeraf2e7aa2014-11-24 10:53:11 +0100130 arch_spinlock_t lockval = READ_ONCE(*lock);
Will Deacon52ea2a52013-10-09 15:54:26 +0100131 return (lockval.next - lockval.owner) > 1;
132}
133#define arch_spin_is_contended arch_spin_is_contended
134
Will Deacon087133a2017-10-12 13:20:50 +0100135#include <asm/qrwlock.h>
Catalin Marinas08e875c2012-03-05 11:49:30 +0000136
Peter Zijlstrad89e588c2016-09-05 11:37:53 +0200137/* See include/linux/spinlock.h */
138#define smp_mb__after_spinlock() smp_mb()
Will Deacon872c63f2016-09-05 11:56:05 +0100139
Catalin Marinas08e875c2012-03-05 11:49:30 +0000140#endif /* __ASM_SPINLOCK_H */