1/* spinlock.h: 64-bit Sparc spinlock support. 2 * 3 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 4 */ 5 6#ifndef __SPARC64_SPINLOCK_H 7#define __SPARC64_SPINLOCK_H 8 9#include <linux/threads.h> /* For NR_CPUS */ 10 11#ifndef __ASSEMBLY__ 12 13/* To get debugging spinlocks which detect and catch 14 * deadlock situations, set CONFIG_DEBUG_SPINLOCK 15 * and rebuild your kernel. 16 */ 17 18/* All of these locking primitives are expected to work properly 19 * even in an RMO memory model, which currently is what the kernel 20 * runs in. 21 * 22 * There is another issue. Because we play games to save cycles 23 * in the non-contention case, we need to be extra careful about 24 * branch targets into the "spinning" code. They live in their 25 * own section, but the newer V9 branches have a shorter range 26 * than the traditional 32-bit sparc branch variants. The rule 27 * is that the branches that go into and out of the spinner sections 28 * must be pre-V9 branches. 29 */ 30 31#define __raw_spin_is_locked(lp) ((lp)->lock != 0) 32 33#define __raw_spin_unlock_wait(lp) \ 34 do { rmb(); \ 35 } while((lp)->lock) 36 37static inline void __raw_spin_lock(raw_spinlock_t *lock) 38{ 39 unsigned long tmp; 40 41 __asm__ __volatile__( 42"1: ldstub [%1], %0\n" 43" membar #StoreLoad | #StoreStore\n" 44" brnz,pn %0, 2f\n" 45" nop\n" 46" .subsection 2\n" 47"2: ldub [%1], %0\n" 48" membar #LoadLoad\n" 49" brnz,pt %0, 2b\n" 50" nop\n" 51" ba,a,pt %%xcc, 1b\n" 52" .previous" 53 : "=&r" (tmp) 54 : "r" (lock) 55 : "memory"); 56} 57 58static inline int __raw_spin_trylock(raw_spinlock_t *lock) 59{ 60 unsigned long result; 61 62 __asm__ __volatile__( 63" ldstub [%1], %0\n" 64" membar #StoreLoad | #StoreStore" 65 : "=r" (result) 66 : "r" (lock) 67 : "memory"); 68 69 return (result == 0UL); 70} 71 72static inline void __raw_spin_unlock(raw_spinlock_t *lock) 73{ 74 __asm__ __volatile__( 75" membar #StoreStore | #LoadStore\n" 76" stb %%g0, [%0]" 77 : /* No outputs */ 78 : "r" (lock) 79 : "memory"); 80} 81 82static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) 83{ 84 unsigned long tmp1, tmp2; 85 86 __asm__ __volatile__( 87"1: ldstub [%2], %0\n" 88" membar #StoreLoad | #StoreStore\n" 89" brnz,pn %0, 2f\n" 90" nop\n" 91" .subsection 2\n" 92"2: rdpr %%pil, %1\n" 93" wrpr %3, %%pil\n" 94"3: ldub [%2], %0\n" 95" membar #LoadLoad\n" 96" brnz,pt %0, 3b\n" 97" nop\n" 98" ba,pt %%xcc, 1b\n" 99" wrpr %1, %%pil\n" 100" .previous" 101 : "=&r" (tmp1), "=&r" (tmp2) 102 : "r"(lock), "r"(flags) 103 : "memory"); 104} 105 106/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ 107 108static void inline __read_lock(raw_rwlock_t *lock) 109{ 110 unsigned long tmp1, tmp2; 111 112 __asm__ __volatile__ ( 113"1: ldsw [%2], %0\n" 114" brlz,pn %0, 2f\n" 115"4: add %0, 1, %1\n" 116" cas [%2], %0, %1\n" 117" cmp %0, %1\n" 118" membar #StoreLoad | #StoreStore\n" 119" bne,pn %%icc, 1b\n" 120" nop\n" 121" .subsection 2\n" 122"2: ldsw [%2], %0\n" 123" membar #LoadLoad\n" 124" brlz,pt %0, 2b\n" 125" nop\n" 126" ba,a,pt %%xcc, 4b\n" 127" .previous" 128 : "=&r" (tmp1), "=&r" (tmp2) 129 : "r" (lock) 130 : "memory"); 131} 132 133static int inline __read_trylock(raw_rwlock_t *lock) 134{ 135 int tmp1, tmp2; 136 137 __asm__ __volatile__ ( 138"1: ldsw [%2], %0\n" 139" brlz,a,pn %0, 2f\n" 140" mov 0, %0\n" 141" add %0, 1, %1\n" 142" cas [%2], %0, %1\n" 143" cmp %0, %1\n" 144" membar #StoreLoad | #StoreStore\n" 145" bne,pn %%icc, 1b\n" 146" mov 1, %0\n" 147"2:" 148 : "=&r" (tmp1), "=&r" (tmp2) 149 : "r" (lock) 150 : "memory"); 151 152 return tmp1; 153} 154 155static void inline __read_unlock(raw_rwlock_t *lock) 156{ 157 unsigned long tmp1, tmp2; 158 159 __asm__ __volatile__( 160" membar #StoreLoad | #LoadLoad\n" 161"1: lduw [%2], %0\n" 162" sub %0, 1, %1\n" 163" cas [%2], %0, %1\n" 164" cmp %0, %1\n" 165" bne,pn %%xcc, 1b\n" 166" nop" 167 : "=&r" (tmp1), "=&r" (tmp2) 168 : "r" (lock) 169 : "memory"); 170} 171 172static void inline __write_lock(raw_rwlock_t *lock) 173{ 174 unsigned long mask, tmp1, tmp2; 175 176 mask = 0x80000000UL; 177 178 __asm__ __volatile__( 179"1: lduw [%2], %0\n" 180" brnz,pn %0, 2f\n" 181"4: or %0, %3, %1\n" 182" cas [%2], %0, %1\n" 183" cmp %0, %1\n" 184" membar #StoreLoad | #StoreStore\n" 185" bne,pn %%icc, 1b\n" 186" nop\n" 187" .subsection 2\n" 188"2: lduw [%2], %0\n" 189" membar #LoadLoad\n" 190" brnz,pt %0, 2b\n" 191" nop\n" 192" ba,a,pt %%xcc, 4b\n" 193" .previous" 194 : "=&r" (tmp1), "=&r" (tmp2) 195 : "r" (lock), "r" (mask) 196 : "memory"); 197} 198 199static void inline __write_unlock(raw_rwlock_t *lock) 200{ 201 __asm__ __volatile__( 202" membar #LoadStore | #StoreStore\n" 203" stw %%g0, [%0]" 204 : /* no outputs */ 205 : "r" (lock) 206 : "memory"); 207} 208 209static int inline __write_trylock(raw_rwlock_t *lock) 210{ 211 unsigned long mask, tmp1, tmp2, result; 212 213 mask = 0x80000000UL; 214 215 __asm__ __volatile__( 216" mov 0, %2\n" 217"1: lduw [%3], %0\n" 218" brnz,pn %0, 2f\n" 219" or %0, %4, %1\n" 220" cas [%3], %0, %1\n" 221" cmp %0, %1\n" 222" membar #StoreLoad | #StoreStore\n" 223" bne,pn %%icc, 1b\n" 224" nop\n" 225" mov 1, %2\n" 226"2:" 227 : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result) 228 : "r" (lock), "r" (mask) 229 : "memory"); 230 231 return result; 232} 233 234#define __raw_read_lock(p) __read_lock(p) 235#define __raw_read_trylock(p) __read_trylock(p) 236#define __raw_read_unlock(p) __read_unlock(p) 237#define __raw_write_lock(p) __write_lock(p) 238#define __raw_write_unlock(p) __write_unlock(p) 239#define __raw_write_trylock(p) __write_trylock(p) 240 241#define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) 242#define __raw_write_can_lock(rw) (!(rw)->lock) 243 244#define _raw_spin_relax(lock) cpu_relax() 245#define _raw_read_relax(lock) cpu_relax() 246#define _raw_write_relax(lock) cpu_relax() 247 248#endif /* !(__ASSEMBLY__) */ 249 250#endif /* !(__SPARC64_SPINLOCK_H) */ 251