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 37 static 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 58 static 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 72 static 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 82 static 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 108 static 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 133 static 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 155 static 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 172 static 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 199 static 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 209 static 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