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 #ifndef __ASSEMBLY__ 10 11 #include <asm/processor.h> 12 #include <asm/barrier.h> 13 14 /* To get debugging spinlocks which detect and catch 15 * deadlock situations, set CONFIG_DEBUG_SPINLOCK 16 * and rebuild your kernel. 17 */ 18 19 /* Because we play games to save cycles in the non-contention case, we 20 * need to be extra careful about branch targets into the "spinning" 21 * code. They live in their own section, but the newer V9 branches 22 * have a shorter range than the traditional 32-bit sparc branch 23 * variants. The rule is that the branches that go into and out of 24 * the spinner sections must be pre-V9 branches. 25 */ 26 27 #define arch_spin_is_locked(lp) ((lp)->lock != 0) 28 29 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) 30 { 31 smp_cond_load_acquire(&lock->lock, !VAL); 32 } 33 34 static inline void arch_spin_lock(arch_spinlock_t *lock) 35 { 36 unsigned long tmp; 37 38 __asm__ __volatile__( 39 "1: ldstub [%1], %0\n" 40 " brnz,pn %0, 2f\n" 41 " nop\n" 42 " .subsection 2\n" 43 "2: ldub [%1], %0\n" 44 " brnz,pt %0, 2b\n" 45 " nop\n" 46 " ba,a,pt %%xcc, 1b\n" 47 " .previous" 48 : "=&r" (tmp) 49 : "r" (lock) 50 : "memory"); 51 } 52 53 static inline int arch_spin_trylock(arch_spinlock_t *lock) 54 { 55 unsigned long result; 56 57 __asm__ __volatile__( 58 " ldstub [%1], %0\n" 59 : "=r" (result) 60 : "r" (lock) 61 : "memory"); 62 63 return (result == 0UL); 64 } 65 66 static inline void arch_spin_unlock(arch_spinlock_t *lock) 67 { 68 __asm__ __volatile__( 69 " stb %%g0, [%0]" 70 : /* No outputs */ 71 : "r" (lock) 72 : "memory"); 73 } 74 75 static inline void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags) 76 { 77 unsigned long tmp1, tmp2; 78 79 __asm__ __volatile__( 80 "1: ldstub [%2], %0\n" 81 " brnz,pn %0, 2f\n" 82 " nop\n" 83 " .subsection 2\n" 84 "2: rdpr %%pil, %1\n" 85 " wrpr %3, %%pil\n" 86 "3: ldub [%2], %0\n" 87 " brnz,pt %0, 3b\n" 88 " nop\n" 89 " ba,pt %%xcc, 1b\n" 90 " wrpr %1, %%pil\n" 91 " .previous" 92 : "=&r" (tmp1), "=&r" (tmp2) 93 : "r"(lock), "r"(flags) 94 : "memory"); 95 } 96 97 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ 98 99 static inline void arch_read_lock(arch_rwlock_t *lock) 100 { 101 unsigned long tmp1, tmp2; 102 103 __asm__ __volatile__ ( 104 "1: ldsw [%2], %0\n" 105 " brlz,pn %0, 2f\n" 106 "4: add %0, 1, %1\n" 107 " cas [%2], %0, %1\n" 108 " cmp %0, %1\n" 109 " bne,pn %%icc, 1b\n" 110 " nop\n" 111 " .subsection 2\n" 112 "2: ldsw [%2], %0\n" 113 " brlz,pt %0, 2b\n" 114 " nop\n" 115 " ba,a,pt %%xcc, 4b\n" 116 " .previous" 117 : "=&r" (tmp1), "=&r" (tmp2) 118 : "r" (lock) 119 : "memory"); 120 } 121 122 static inline int arch_read_trylock(arch_rwlock_t *lock) 123 { 124 int tmp1, tmp2; 125 126 __asm__ __volatile__ ( 127 "1: ldsw [%2], %0\n" 128 " brlz,a,pn %0, 2f\n" 129 " mov 0, %0\n" 130 " add %0, 1, %1\n" 131 " cas [%2], %0, %1\n" 132 " cmp %0, %1\n" 133 " bne,pn %%icc, 1b\n" 134 " mov 1, %0\n" 135 "2:" 136 : "=&r" (tmp1), "=&r" (tmp2) 137 : "r" (lock) 138 : "memory"); 139 140 return tmp1; 141 } 142 143 static inline void arch_read_unlock(arch_rwlock_t *lock) 144 { 145 unsigned long tmp1, tmp2; 146 147 __asm__ __volatile__( 148 "1: lduw [%2], %0\n" 149 " sub %0, 1, %1\n" 150 " cas [%2], %0, %1\n" 151 " cmp %0, %1\n" 152 " bne,pn %%xcc, 1b\n" 153 " nop" 154 : "=&r" (tmp1), "=&r" (tmp2) 155 : "r" (lock) 156 : "memory"); 157 } 158 159 static inline void arch_write_lock(arch_rwlock_t *lock) 160 { 161 unsigned long mask, tmp1, tmp2; 162 163 mask = 0x80000000UL; 164 165 __asm__ __volatile__( 166 "1: lduw [%2], %0\n" 167 " brnz,pn %0, 2f\n" 168 "4: or %0, %3, %1\n" 169 " cas [%2], %0, %1\n" 170 " cmp %0, %1\n" 171 " bne,pn %%icc, 1b\n" 172 " nop\n" 173 " .subsection 2\n" 174 "2: lduw [%2], %0\n" 175 " brnz,pt %0, 2b\n" 176 " nop\n" 177 " ba,a,pt %%xcc, 4b\n" 178 " .previous" 179 : "=&r" (tmp1), "=&r" (tmp2) 180 : "r" (lock), "r" (mask) 181 : "memory"); 182 } 183 184 static inline void arch_write_unlock(arch_rwlock_t *lock) 185 { 186 __asm__ __volatile__( 187 " stw %%g0, [%0]" 188 : /* no outputs */ 189 : "r" (lock) 190 : "memory"); 191 } 192 193 static inline int arch_write_trylock(arch_rwlock_t *lock) 194 { 195 unsigned long mask, tmp1, tmp2, result; 196 197 mask = 0x80000000UL; 198 199 __asm__ __volatile__( 200 " mov 0, %2\n" 201 "1: lduw [%3], %0\n" 202 " brnz,pn %0, 2f\n" 203 " or %0, %4, %1\n" 204 " cas [%3], %0, %1\n" 205 " cmp %0, %1\n" 206 " bne,pn %%icc, 1b\n" 207 " nop\n" 208 " mov 1, %2\n" 209 "2:" 210 : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result) 211 : "r" (lock), "r" (mask) 212 : "memory"); 213 214 return result; 215 } 216 217 #define arch_read_lock_flags(p, f) arch_read_lock(p) 218 #define arch_write_lock_flags(p, f) arch_write_lock(p) 219 220 #define arch_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) 221 #define arch_write_can_lock(rw) (!(rw)->lock) 222 223 #define arch_spin_relax(lock) cpu_relax() 224 #define arch_read_relax(lock) cpu_relax() 225 #define arch_write_relax(lock) cpu_relax() 226 227 #endif /* !(__ASSEMBLY__) */ 228 229 #endif /* !(__SPARC64_SPINLOCK_H) */ 230