1#ifndef _ASM_M32R_SPINLOCK_H 2#define _ASM_M32R_SPINLOCK_H 3 4/* 5 * linux/include/asm-m32r/spinlock.h 6 * 7 * M32R version: 8 * Copyright (C) 2001, 2002 Hitoshi Yamamoto 9 * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> 10 */ 11 12#include <linux/compiler.h> 13#include <linux/atomic.h> 14#include <asm/dcache_clear.h> 15#include <asm/page.h> 16 17/* 18 * Your basic SMP spinlocks, allowing only a single CPU anywhere 19 * 20 * (the type definitions are in asm/spinlock_types.h) 21 * 22 * Simple spin lock operations. There are two variants, one clears IRQ's 23 * on the local processor, one does not. 24 * 25 * We make no fairness assumptions. They have a cost. 26 */ 27 28#define arch_spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) 29#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) 30#define arch_spin_unlock_wait(x) \ 31 do { cpu_relax(); } while (arch_spin_is_locked(x)) 32 33/** 34 * arch_spin_trylock - Try spin lock and return a result 35 * @lock: Pointer to the lock variable 36 * 37 * arch_spin_trylock() tries to get the lock and returns a result. 38 * On the m32r, the result value is 1 (= Success) or 0 (= Failure). 39 */ 40static inline int arch_spin_trylock(arch_spinlock_t *lock) 41{ 42 int oldval; 43 unsigned long tmp1, tmp2; 44 45 /* 46 * lock->slock : =1 : unlock 47 * : <=0 : lock 48 * { 49 * oldval = lock->slock; <--+ need atomic operation 50 * lock->slock = 0; <--+ 51 * } 52 */ 53 __asm__ __volatile__ ( 54 "# arch_spin_trylock \n\t" 55 "ldi %1, #0; \n\t" 56 "mvfc %2, psw; \n\t" 57 "clrpsw #0x40 -> nop; \n\t" 58 DCACHE_CLEAR("%0", "r6", "%3") 59 "lock %0, @%3; \n\t" 60 "unlock %1, @%3; \n\t" 61 "mvtc %2, psw; \n\t" 62 : "=&r" (oldval), "=&r" (tmp1), "=&r" (tmp2) 63 : "r" (&lock->slock) 64 : "memory" 65#ifdef CONFIG_CHIP_M32700_TS1 66 , "r6" 67#endif /* CONFIG_CHIP_M32700_TS1 */ 68 ); 69 70 return (oldval > 0); 71} 72 73static inline void arch_spin_lock(arch_spinlock_t *lock) 74{ 75 unsigned long tmp0, tmp1; 76 77 /* 78 * lock->slock : =1 : unlock 79 * : <=0 : lock 80 * 81 * for ( ; ; ) { 82 * lock->slock -= 1; <-- need atomic operation 83 * if (lock->slock == 0) break; 84 * for ( ; lock->slock <= 0 ; ); 85 * } 86 */ 87 __asm__ __volatile__ ( 88 "# arch_spin_lock \n\t" 89 ".fillinsn \n" 90 "1: \n\t" 91 "mvfc %1, psw; \n\t" 92 "clrpsw #0x40 -> nop; \n\t" 93 DCACHE_CLEAR("%0", "r6", "%2") 94 "lock %0, @%2; \n\t" 95 "addi %0, #-1; \n\t" 96 "unlock %0, @%2; \n\t" 97 "mvtc %1, psw; \n\t" 98 "bltz %0, 2f; \n\t" 99 LOCK_SECTION_START(".balign 4 \n\t") 100 ".fillinsn \n" 101 "2: \n\t" 102 "ld %0, @%2; \n\t" 103 "bgtz %0, 1b; \n\t" 104 "bra 2b; \n\t" 105 LOCK_SECTION_END 106 : "=&r" (tmp0), "=&r" (tmp1) 107 : "r" (&lock->slock) 108 : "memory" 109#ifdef CONFIG_CHIP_M32700_TS1 110 , "r6" 111#endif /* CONFIG_CHIP_M32700_TS1 */ 112 ); 113} 114 115static inline void arch_spin_unlock(arch_spinlock_t *lock) 116{ 117 mb(); 118 lock->slock = 1; 119} 120 121/* 122 * Read-write spinlocks, allowing multiple readers 123 * but only one writer. 124 * 125 * NOTE! it is quite common to have readers in interrupts 126 * but no interrupt writers. For those circumstances we 127 * can "mix" irq-safe locks - any writer needs to get a 128 * irq-safe write-lock, but readers can get non-irqsafe 129 * read-locks. 130 * 131 * On x86, we implement read-write locks as a 32-bit counter 132 * with the high bit (sign) being the "contended" bit. 133 * 134 * The inline assembly is non-obvious. Think about it. 135 * 136 * Changed to use the same technique as rw semaphores. See 137 * semaphore.h for details. -ben 138 */ 139 140/** 141 * read_can_lock - would read_trylock() succeed? 142 * @lock: the rwlock in question. 143 */ 144#define arch_read_can_lock(x) ((int)(x)->lock > 0) 145 146/** 147 * write_can_lock - would write_trylock() succeed? 148 * @lock: the rwlock in question. 149 */ 150#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) 151 152static inline void arch_read_lock(arch_rwlock_t *rw) 153{ 154 unsigned long tmp0, tmp1; 155 156 /* 157 * rw->lock : >0 : unlock 158 * : <=0 : lock 159 * 160 * for ( ; ; ) { 161 * rw->lock -= 1; <-- need atomic operation 162 * if (rw->lock >= 0) break; 163 * rw->lock += 1; <-- need atomic operation 164 * for ( ; rw->lock <= 0 ; ); 165 * } 166 */ 167 __asm__ __volatile__ ( 168 "# read_lock \n\t" 169 ".fillinsn \n" 170 "1: \n\t" 171 "mvfc %1, psw; \n\t" 172 "clrpsw #0x40 -> nop; \n\t" 173 DCACHE_CLEAR("%0", "r6", "%2") 174 "lock %0, @%2; \n\t" 175 "addi %0, #-1; \n\t" 176 "unlock %0, @%2; \n\t" 177 "mvtc %1, psw; \n\t" 178 "bltz %0, 2f; \n\t" 179 LOCK_SECTION_START(".balign 4 \n\t") 180 ".fillinsn \n" 181 "2: \n\t" 182 "clrpsw #0x40 -> nop; \n\t" 183 DCACHE_CLEAR("%0", "r6", "%2") 184 "lock %0, @%2; \n\t" 185 "addi %0, #1; \n\t" 186 "unlock %0, @%2; \n\t" 187 "mvtc %1, psw; \n\t" 188 ".fillinsn \n" 189 "3: \n\t" 190 "ld %0, @%2; \n\t" 191 "bgtz %0, 1b; \n\t" 192 "bra 3b; \n\t" 193 LOCK_SECTION_END 194 : "=&r" (tmp0), "=&r" (tmp1) 195 : "r" (&rw->lock) 196 : "memory" 197#ifdef CONFIG_CHIP_M32700_TS1 198 , "r6" 199#endif /* CONFIG_CHIP_M32700_TS1 */ 200 ); 201} 202 203static inline void arch_write_lock(arch_rwlock_t *rw) 204{ 205 unsigned long tmp0, tmp1, tmp2; 206 207 /* 208 * rw->lock : =RW_LOCK_BIAS_STR : unlock 209 * : !=RW_LOCK_BIAS_STR : lock 210 * 211 * for ( ; ; ) { 212 * rw->lock -= RW_LOCK_BIAS_STR; <-- need atomic operation 213 * if (rw->lock == 0) break; 214 * rw->lock += RW_LOCK_BIAS_STR; <-- need atomic operation 215 * for ( ; rw->lock != RW_LOCK_BIAS_STR ; ) ; 216 * } 217 */ 218 __asm__ __volatile__ ( 219 "# write_lock \n\t" 220 "seth %1, #high(" RW_LOCK_BIAS_STR "); \n\t" 221 "or3 %1, %1, #low(" RW_LOCK_BIAS_STR "); \n\t" 222 ".fillinsn \n" 223 "1: \n\t" 224 "mvfc %2, psw; \n\t" 225 "clrpsw #0x40 -> nop; \n\t" 226 DCACHE_CLEAR("%0", "r7", "%3") 227 "lock %0, @%3; \n\t" 228 "sub %0, %1; \n\t" 229 "unlock %0, @%3; \n\t" 230 "mvtc %2, psw; \n\t" 231 "bnez %0, 2f; \n\t" 232 LOCK_SECTION_START(".balign 4 \n\t") 233 ".fillinsn \n" 234 "2: \n\t" 235 "clrpsw #0x40 -> nop; \n\t" 236 DCACHE_CLEAR("%0", "r7", "%3") 237 "lock %0, @%3; \n\t" 238 "add %0, %1; \n\t" 239 "unlock %0, @%3; \n\t" 240 "mvtc %2, psw; \n\t" 241 ".fillinsn \n" 242 "3: \n\t" 243 "ld %0, @%3; \n\t" 244 "beq %0, %1, 1b; \n\t" 245 "bra 3b; \n\t" 246 LOCK_SECTION_END 247 : "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2) 248 : "r" (&rw->lock) 249 : "memory" 250#ifdef CONFIG_CHIP_M32700_TS1 251 , "r7" 252#endif /* CONFIG_CHIP_M32700_TS1 */ 253 ); 254} 255 256static inline void arch_read_unlock(arch_rwlock_t *rw) 257{ 258 unsigned long tmp0, tmp1; 259 260 __asm__ __volatile__ ( 261 "# read_unlock \n\t" 262 "mvfc %1, psw; \n\t" 263 "clrpsw #0x40 -> nop; \n\t" 264 DCACHE_CLEAR("%0", "r6", "%2") 265 "lock %0, @%2; \n\t" 266 "addi %0, #1; \n\t" 267 "unlock %0, @%2; \n\t" 268 "mvtc %1, psw; \n\t" 269 : "=&r" (tmp0), "=&r" (tmp1) 270 : "r" (&rw->lock) 271 : "memory" 272#ifdef CONFIG_CHIP_M32700_TS1 273 , "r6" 274#endif /* CONFIG_CHIP_M32700_TS1 */ 275 ); 276} 277 278static inline void arch_write_unlock(arch_rwlock_t *rw) 279{ 280 unsigned long tmp0, tmp1, tmp2; 281 282 __asm__ __volatile__ ( 283 "# write_unlock \n\t" 284 "seth %1, #high(" RW_LOCK_BIAS_STR "); \n\t" 285 "or3 %1, %1, #low(" RW_LOCK_BIAS_STR "); \n\t" 286 "mvfc %2, psw; \n\t" 287 "clrpsw #0x40 -> nop; \n\t" 288 DCACHE_CLEAR("%0", "r7", "%3") 289 "lock %0, @%3; \n\t" 290 "add %0, %1; \n\t" 291 "unlock %0, @%3; \n\t" 292 "mvtc %2, psw; \n\t" 293 : "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2) 294 : "r" (&rw->lock) 295 : "memory" 296#ifdef CONFIG_CHIP_M32700_TS1 297 , "r7" 298#endif /* CONFIG_CHIP_M32700_TS1 */ 299 ); 300} 301 302static inline int arch_read_trylock(arch_rwlock_t *lock) 303{ 304 atomic_t *count = (atomic_t*)lock; 305 if (atomic_dec_return(count) >= 0) 306 return 1; 307 atomic_inc(count); 308 return 0; 309} 310 311static inline int arch_write_trylock(arch_rwlock_t *lock) 312{ 313 atomic_t *count = (atomic_t *)lock; 314 if (atomic_sub_and_test(RW_LOCK_BIAS, count)) 315 return 1; 316 atomic_add(RW_LOCK_BIAS, count); 317 return 0; 318} 319 320#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) 321#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) 322 323#define arch_spin_relax(lock) cpu_relax() 324#define arch_read_relax(lock) cpu_relax() 325#define arch_write_relax(lock) cpu_relax() 326 327#endif /* _ASM_M32R_SPINLOCK_H */ 328