1 #ifndef _ALPHA_ATOMIC_H 2 #define _ALPHA_ATOMIC_H 3 4 #include <asm/barrier.h> 5 #include <asm/system.h> 6 7 /* 8 * Atomic operations that C can't guarantee us. Useful for 9 * resource counting etc... 10 * 11 * But use these as seldom as possible since they are much slower 12 * than regular operations. 13 */ 14 15 16 /* 17 * Counter is volatile to make sure gcc doesn't try to be clever 18 * and move things around on us. We need to use _exactly_ the address 19 * the user gave us, not some alias that contains the same information. 20 */ 21 typedef struct { volatile int counter; } atomic_t; 22 typedef struct { volatile long counter; } atomic64_t; 23 24 #define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) 25 #define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } ) 26 27 #define atomic_read(v) ((v)->counter + 0) 28 #define atomic64_read(v) ((v)->counter + 0) 29 30 #define atomic_set(v,i) ((v)->counter = (i)) 31 #define atomic64_set(v,i) ((v)->counter = (i)) 32 33 /* 34 * To get proper branch prediction for the main line, we must branch 35 * forward to code at the end of this object's .text section, then 36 * branch back to restart the operation. 37 */ 38 39 static __inline__ void atomic_add(int i, atomic_t * v) 40 { 41 unsigned long temp; 42 __asm__ __volatile__( 43 "1: ldl_l %0,%1\n" 44 " addl %0,%2,%0\n" 45 " stl_c %0,%1\n" 46 " beq %0,2f\n" 47 ".subsection 2\n" 48 "2: br 1b\n" 49 ".previous" 50 :"=&r" (temp), "=m" (v->counter) 51 :"Ir" (i), "m" (v->counter)); 52 } 53 54 static __inline__ void atomic64_add(long i, atomic64_t * v) 55 { 56 unsigned long temp; 57 __asm__ __volatile__( 58 "1: ldq_l %0,%1\n" 59 " addq %0,%2,%0\n" 60 " stq_c %0,%1\n" 61 " beq %0,2f\n" 62 ".subsection 2\n" 63 "2: br 1b\n" 64 ".previous" 65 :"=&r" (temp), "=m" (v->counter) 66 :"Ir" (i), "m" (v->counter)); 67 } 68 69 static __inline__ void atomic_sub(int i, atomic_t * v) 70 { 71 unsigned long temp; 72 __asm__ __volatile__( 73 "1: ldl_l %0,%1\n" 74 " subl %0,%2,%0\n" 75 " stl_c %0,%1\n" 76 " beq %0,2f\n" 77 ".subsection 2\n" 78 "2: br 1b\n" 79 ".previous" 80 :"=&r" (temp), "=m" (v->counter) 81 :"Ir" (i), "m" (v->counter)); 82 } 83 84 static __inline__ void atomic64_sub(long i, atomic64_t * v) 85 { 86 unsigned long temp; 87 __asm__ __volatile__( 88 "1: ldq_l %0,%1\n" 89 " subq %0,%2,%0\n" 90 " stq_c %0,%1\n" 91 " beq %0,2f\n" 92 ".subsection 2\n" 93 "2: br 1b\n" 94 ".previous" 95 :"=&r" (temp), "=m" (v->counter) 96 :"Ir" (i), "m" (v->counter)); 97 } 98 99 100 /* 101 * Same as above, but return the result value 102 */ 103 static inline int atomic_add_return(int i, atomic_t *v) 104 { 105 long temp, result; 106 smp_mb(); 107 __asm__ __volatile__( 108 "1: ldl_l %0,%1\n" 109 " addl %0,%3,%2\n" 110 " addl %0,%3,%0\n" 111 " stl_c %0,%1\n" 112 " beq %0,2f\n" 113 ".subsection 2\n" 114 "2: br 1b\n" 115 ".previous" 116 :"=&r" (temp), "=m" (v->counter), "=&r" (result) 117 :"Ir" (i), "m" (v->counter) : "memory"); 118 smp_mb(); 119 return result; 120 } 121 122 static __inline__ long atomic64_add_return(long i, atomic64_t * v) 123 { 124 long temp, result; 125 smp_mb(); 126 __asm__ __volatile__( 127 "1: ldq_l %0,%1\n" 128 " addq %0,%3,%2\n" 129 " addq %0,%3,%0\n" 130 " stq_c %0,%1\n" 131 " beq %0,2f\n" 132 ".subsection 2\n" 133 "2: br 1b\n" 134 ".previous" 135 :"=&r" (temp), "=m" (v->counter), "=&r" (result) 136 :"Ir" (i), "m" (v->counter) : "memory"); 137 smp_mb(); 138 return result; 139 } 140 141 static __inline__ long atomic_sub_return(int i, atomic_t * v) 142 { 143 long temp, result; 144 smp_mb(); 145 __asm__ __volatile__( 146 "1: ldl_l %0,%1\n" 147 " subl %0,%3,%2\n" 148 " subl %0,%3,%0\n" 149 " stl_c %0,%1\n" 150 " beq %0,2f\n" 151 ".subsection 2\n" 152 "2: br 1b\n" 153 ".previous" 154 :"=&r" (temp), "=m" (v->counter), "=&r" (result) 155 :"Ir" (i), "m" (v->counter) : "memory"); 156 smp_mb(); 157 return result; 158 } 159 160 static __inline__ long atomic64_sub_return(long i, atomic64_t * v) 161 { 162 long temp, result; 163 smp_mb(); 164 __asm__ __volatile__( 165 "1: ldq_l %0,%1\n" 166 " subq %0,%3,%2\n" 167 " subq %0,%3,%0\n" 168 " stq_c %0,%1\n" 169 " beq %0,2f\n" 170 ".subsection 2\n" 171 "2: br 1b\n" 172 ".previous" 173 :"=&r" (temp), "=m" (v->counter), "=&r" (result) 174 :"Ir" (i), "m" (v->counter) : "memory"); 175 smp_mb(); 176 return result; 177 } 178 179 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) 180 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 181 182 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) 183 #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 184 185 /** 186 * atomic_add_unless - add unless the number is a given value 187 * @v: pointer of type atomic_t 188 * @a: the amount to add to v... 189 * @u: ...unless v is equal to u. 190 * 191 * Atomically adds @a to @v, so long as it was not @u. 192 * Returns non-zero if @v was not @u, and zero otherwise. 193 */ 194 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) 195 { 196 int c, old; 197 c = atomic_read(v); 198 for (;;) { 199 if (unlikely(c == (u))) 200 break; 201 old = atomic_cmpxchg((v), c, c + (a)); 202 if (likely(old == c)) 203 break; 204 c = old; 205 } 206 return c != (u); 207 } 208 209 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 210 211 /** 212 * atomic64_add_unless - add unless the number is a given value 213 * @v: pointer of type atomic64_t 214 * @a: the amount to add to v... 215 * @u: ...unless v is equal to u. 216 * 217 * Atomically adds @a to @v, so long as it was not @u. 218 * Returns non-zero if @v was not @u, and zero otherwise. 219 */ 220 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) 221 { 222 long c, old; 223 c = atomic64_read(v); 224 for (;;) { 225 if (unlikely(c == (u))) 226 break; 227 old = atomic64_cmpxchg((v), c, c + (a)); 228 if (likely(old == c)) 229 break; 230 c = old; 231 } 232 return c != (u); 233 } 234 235 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) 236 237 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) 238 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) 239 240 #define atomic_dec_return(v) atomic_sub_return(1,(v)) 241 #define atomic64_dec_return(v) atomic64_sub_return(1,(v)) 242 243 #define atomic_inc_return(v) atomic_add_return(1,(v)) 244 #define atomic64_inc_return(v) atomic64_add_return(1,(v)) 245 246 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) 247 #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0) 248 249 #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) 250 #define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0) 251 252 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) 253 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) 254 255 #define atomic_inc(v) atomic_add(1,(v)) 256 #define atomic64_inc(v) atomic64_add(1,(v)) 257 258 #define atomic_dec(v) atomic_sub(1,(v)) 259 #define atomic64_dec(v) atomic64_sub(1,(v)) 260 261 #define smp_mb__before_atomic_dec() smp_mb() 262 #define smp_mb__after_atomic_dec() smp_mb() 263 #define smp_mb__before_atomic_inc() smp_mb() 264 #define smp_mb__after_atomic_inc() smp_mb() 265 266 #include <asm-generic/atomic.h> 267 #endif /* _ALPHA_ATOMIC_H */ 268