xref: /linux/arch/csky/include/asm/spinlock.h (revision 44f57d78)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __ASM_CSKY_SPINLOCK_H
4 #define __ASM_CSKY_SPINLOCK_H
5 
6 #include <linux/spinlock_types.h>
7 #include <asm/barrier.h>
8 
9 #ifdef CONFIG_QUEUED_RWLOCKS
10 
11 /*
12  * Ticket-based spin-locking.
13  */
14 static inline void arch_spin_lock(arch_spinlock_t *lock)
15 {
16 	arch_spinlock_t lockval;
17 	u32 ticket_next = 1 << TICKET_NEXT;
18 	u32 *p = &lock->lock;
19 	u32 tmp;
20 
21 	asm volatile (
22 		"1:	ldex.w		%0, (%2) \n"
23 		"	mov		%1, %0	 \n"
24 		"	add		%0, %3	 \n"
25 		"	stex.w		%0, (%2) \n"
26 		"	bez		%0, 1b   \n"
27 		: "=&r" (tmp), "=&r" (lockval)
28 		: "r"(p), "r"(ticket_next)
29 		: "cc");
30 
31 	while (lockval.tickets.next != lockval.tickets.owner)
32 		lockval.tickets.owner = READ_ONCE(lock->tickets.owner);
33 
34 	smp_mb();
35 }
36 
37 static inline int arch_spin_trylock(arch_spinlock_t *lock)
38 {
39 	u32 tmp, contended, res;
40 	u32 ticket_next = 1 << TICKET_NEXT;
41 	u32 *p = &lock->lock;
42 
43 	do {
44 		asm volatile (
45 		"	ldex.w		%0, (%3)   \n"
46 		"	movi		%2, 1	   \n"
47 		"	rotli		%1, %0, 16 \n"
48 		"	cmpne		%1, %0     \n"
49 		"	bt		1f         \n"
50 		"	movi		%2, 0	   \n"
51 		"	add		%0, %0, %4 \n"
52 		"	stex.w		%0, (%3)   \n"
53 		"1:				   \n"
54 		: "=&r" (res), "=&r" (tmp), "=&r" (contended)
55 		: "r"(p), "r"(ticket_next)
56 		: "cc");
57 	} while (!res);
58 
59 	if (!contended)
60 		smp_mb();
61 
62 	return !contended;
63 }
64 
65 static inline void arch_spin_unlock(arch_spinlock_t *lock)
66 {
67 	smp_mb();
68 	WRITE_ONCE(lock->tickets.owner, lock->tickets.owner + 1);
69 }
70 
71 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
72 {
73 	return lock.tickets.owner == lock.tickets.next;
74 }
75 
76 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
77 {
78 	return !arch_spin_value_unlocked(READ_ONCE(*lock));
79 }
80 
81 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
82 {
83 	struct __raw_tickets tickets = READ_ONCE(lock->tickets);
84 
85 	return (tickets.next - tickets.owner) > 1;
86 }
87 #define arch_spin_is_contended	arch_spin_is_contended
88 
89 #include <asm/qrwlock.h>
90 
91 /* See include/linux/spinlock.h */
92 #define smp_mb__after_spinlock()	smp_mb()
93 
94 #else /* CONFIG_QUEUED_RWLOCKS */
95 
96 /*
97  * Test-and-set spin-locking.
98  */
99 static inline void arch_spin_lock(arch_spinlock_t *lock)
100 {
101 	u32 *p = &lock->lock;
102 	u32 tmp;
103 
104 	asm volatile (
105 		"1:	ldex.w		%0, (%1) \n"
106 		"	bnez		%0, 1b   \n"
107 		"	movi		%0, 1    \n"
108 		"	stex.w		%0, (%1) \n"
109 		"	bez		%0, 1b   \n"
110 		: "=&r" (tmp)
111 		: "r"(p)
112 		: "cc");
113 	smp_mb();
114 }
115 
116 static inline void arch_spin_unlock(arch_spinlock_t *lock)
117 {
118 	smp_mb();
119 	WRITE_ONCE(lock->lock, 0);
120 }
121 
122 static inline int arch_spin_trylock(arch_spinlock_t *lock)
123 {
124 	u32 *p = &lock->lock;
125 	u32 tmp;
126 
127 	asm volatile (
128 		"1:	ldex.w		%0, (%1) \n"
129 		"	bnez		%0, 2f   \n"
130 		"	movi		%0, 1    \n"
131 		"	stex.w		%0, (%1) \n"
132 		"	bez		%0, 1b   \n"
133 		"	movi		%0, 0    \n"
134 		"2:				 \n"
135 		: "=&r" (tmp)
136 		: "r"(p)
137 		: "cc");
138 
139 	if (!tmp)
140 		smp_mb();
141 
142 	return !tmp;
143 }
144 
145 #define arch_spin_is_locked(x)	(READ_ONCE((x)->lock) != 0)
146 
147 /*
148  * read lock/unlock/trylock
149  */
150 static inline void arch_read_lock(arch_rwlock_t *lock)
151 {
152 	u32 *p = &lock->lock;
153 	u32 tmp;
154 
155 	asm volatile (
156 		"1:	ldex.w		%0, (%1) \n"
157 		"	blz		%0, 1b   \n"
158 		"	addi		%0, 1    \n"
159 		"	stex.w		%0, (%1) \n"
160 		"	bez		%0, 1b   \n"
161 		: "=&r" (tmp)
162 		: "r"(p)
163 		: "cc");
164 	smp_mb();
165 }
166 
167 static inline void arch_read_unlock(arch_rwlock_t *lock)
168 {
169 	u32 *p = &lock->lock;
170 	u32 tmp;
171 
172 	smp_mb();
173 	asm volatile (
174 		"1:	ldex.w		%0, (%1) \n"
175 		"	subi		%0, 1    \n"
176 		"	stex.w		%0, (%1) \n"
177 		"	bez		%0, 1b   \n"
178 		: "=&r" (tmp)
179 		: "r"(p)
180 		: "cc");
181 }
182 
183 static inline int arch_read_trylock(arch_rwlock_t *lock)
184 {
185 	u32 *p = &lock->lock;
186 	u32 tmp;
187 
188 	asm volatile (
189 		"1:	ldex.w		%0, (%1) \n"
190 		"	blz		%0, 2f   \n"
191 		"	addi		%0, 1    \n"
192 		"	stex.w		%0, (%1) \n"
193 		"	bez		%0, 1b   \n"
194 		"	movi		%0, 0    \n"
195 		"2:				 \n"
196 		: "=&r" (tmp)
197 		: "r"(p)
198 		: "cc");
199 
200 	if (!tmp)
201 		smp_mb();
202 
203 	return !tmp;
204 }
205 
206 /*
207  * write lock/unlock/trylock
208  */
209 static inline void arch_write_lock(arch_rwlock_t *lock)
210 {
211 	u32 *p = &lock->lock;
212 	u32 tmp;
213 
214 	asm volatile (
215 		"1:	ldex.w		%0, (%1) \n"
216 		"	bnez		%0, 1b   \n"
217 		"	subi		%0, 1    \n"
218 		"	stex.w		%0, (%1) \n"
219 		"	bez		%0, 1b   \n"
220 		: "=&r" (tmp)
221 		: "r"(p)
222 		: "cc");
223 	smp_mb();
224 }
225 
226 static inline void arch_write_unlock(arch_rwlock_t *lock)
227 {
228 	smp_mb();
229 	WRITE_ONCE(lock->lock, 0);
230 }
231 
232 static inline int arch_write_trylock(arch_rwlock_t *lock)
233 {
234 	u32 *p = &lock->lock;
235 	u32 tmp;
236 
237 	asm volatile (
238 		"1:	ldex.w		%0, (%1) \n"
239 		"	bnez		%0, 2f   \n"
240 		"	subi		%0, 1    \n"
241 		"	stex.w		%0, (%1) \n"
242 		"	bez		%0, 1b   \n"
243 		"	movi		%0, 0    \n"
244 		"2:				 \n"
245 		: "=&r" (tmp)
246 		: "r"(p)
247 		: "cc");
248 
249 	if (!tmp)
250 		smp_mb();
251 
252 	return !tmp;
253 }
254 
255 #endif /* CONFIG_QUEUED_RWLOCKS */
256 #endif /* __ASM_CSKY_SPINLOCK_H */
257