GNU Linux-libre 5.4.274-gnu1
[releases.git] / arch / csky / include / asm / spinlock.h
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 */