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 */ 14static 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 37static 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 65static 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 71static inline int arch_spin_value_unlocked(arch_spinlock_t lock) 72{ 73 return lock.tickets.owner == lock.tickets.next; 74} 75 76static inline int arch_spin_is_locked(arch_spinlock_t *lock) 77{ 78 return !arch_spin_value_unlocked(READ_ONCE(*lock)); 79} 80 81static 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 */ 99static 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 116static inline void arch_spin_unlock(arch_spinlock_t *lock) 117{ 118 smp_mb(); 119 WRITE_ONCE(lock->lock, 0); 120} 121 122static 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 */ 150static 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 167static 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 183static 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 */ 209static 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 226static inline void arch_write_unlock(arch_rwlock_t *lock) 227{ 228 smp_mb(); 229 WRITE_ONCE(lock->lock, 0); 230} 231 232static 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