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 */ 21typedef struct { volatile int counter; } atomic_t; 22typedef 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 39static __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 54static __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 69static __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 84static __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 */ 103static __inline__ long 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 122static __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 141static __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 160static __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 */ 194static __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 */ 220static __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