1 #ifndef __ARCH_I386_ATOMIC__ 2 #define __ARCH_I386_ATOMIC__ 3 4 #include <linux/compiler.h> 5 #include <asm/processor.h> 6 #include <asm/cmpxchg.h> 7 8 /* 9 * Atomic operations that C can't guarantee us. Useful for 10 * resource counting etc.. 11 */ 12 13 /* 14 * Make sure gcc doesn't try to be clever and move things around 15 * on us. We need to use _exactly_ the address the user gave us, 16 * not some alias that contains the same information. 17 */ 18 typedef struct { int counter; } atomic_t; 19 20 #define ATOMIC_INIT(i) { (i) } 21 22 /** 23 * atomic_read - read atomic variable 24 * @v: pointer of type atomic_t 25 * 26 * Atomically reads the value of @v. 27 */ 28 #define atomic_read(v) ((v)->counter) 29 30 /** 31 * atomic_set - set atomic variable 32 * @v: pointer of type atomic_t 33 * @i: required value 34 * 35 * Atomically sets the value of @v to @i. 36 */ 37 #define atomic_set(v,i) (((v)->counter) = (i)) 38 39 /** 40 * atomic_add - add integer to atomic variable 41 * @i: integer value to add 42 * @v: pointer of type atomic_t 43 * 44 * Atomically adds @i to @v. 45 */ 46 static __inline__ void atomic_add(int i, atomic_t *v) 47 { 48 __asm__ __volatile__( 49 LOCK_PREFIX "addl %1,%0" 50 :"+m" (v->counter) 51 :"ir" (i)); 52 } 53 54 /** 55 * atomic_sub - subtract integer from atomic variable 56 * @i: integer value to subtract 57 * @v: pointer of type atomic_t 58 * 59 * Atomically subtracts @i from @v. 60 */ 61 static __inline__ void atomic_sub(int i, atomic_t *v) 62 { 63 __asm__ __volatile__( 64 LOCK_PREFIX "subl %1,%0" 65 :"+m" (v->counter) 66 :"ir" (i)); 67 } 68 69 /** 70 * atomic_sub_and_test - subtract value from variable and test result 71 * @i: integer value to subtract 72 * @v: pointer of type atomic_t 73 * 74 * Atomically subtracts @i from @v and returns 75 * true if the result is zero, or false for all 76 * other cases. 77 */ 78 static __inline__ int atomic_sub_and_test(int i, atomic_t *v) 79 { 80 unsigned char c; 81 82 __asm__ __volatile__( 83 LOCK_PREFIX "subl %2,%0; sete %1" 84 :"+m" (v->counter), "=qm" (c) 85 :"ir" (i) : "memory"); 86 return c; 87 } 88 89 /** 90 * atomic_inc - increment atomic variable 91 * @v: pointer of type atomic_t 92 * 93 * Atomically increments @v by 1. 94 */ 95 static __inline__ void atomic_inc(atomic_t *v) 96 { 97 __asm__ __volatile__( 98 LOCK_PREFIX "incl %0" 99 :"+m" (v->counter)); 100 } 101 102 /** 103 * atomic_dec - decrement atomic variable 104 * @v: pointer of type atomic_t 105 * 106 * Atomically decrements @v by 1. 107 */ 108 static __inline__ void atomic_dec(atomic_t *v) 109 { 110 __asm__ __volatile__( 111 LOCK_PREFIX "decl %0" 112 :"+m" (v->counter)); 113 } 114 115 /** 116 * atomic_dec_and_test - decrement and test 117 * @v: pointer of type atomic_t 118 * 119 * Atomically decrements @v by 1 and 120 * returns true if the result is 0, or false for all other 121 * cases. 122 */ 123 static __inline__ int atomic_dec_and_test(atomic_t *v) 124 { 125 unsigned char c; 126 127 __asm__ __volatile__( 128 LOCK_PREFIX "decl %0; sete %1" 129 :"+m" (v->counter), "=qm" (c) 130 : : "memory"); 131 return c != 0; 132 } 133 134 /** 135 * atomic_inc_and_test - increment and test 136 * @v: pointer of type atomic_t 137 * 138 * Atomically increments @v by 1 139 * and returns true if the result is zero, or false for all 140 * other cases. 141 */ 142 static __inline__ int atomic_inc_and_test(atomic_t *v) 143 { 144 unsigned char c; 145 146 __asm__ __volatile__( 147 LOCK_PREFIX "incl %0; sete %1" 148 :"+m" (v->counter), "=qm" (c) 149 : : "memory"); 150 return c != 0; 151 } 152 153 /** 154 * atomic_add_negative - add and test if negative 155 * @v: pointer of type atomic_t 156 * @i: integer value to add 157 * 158 * Atomically adds @i to @v and returns true 159 * if the result is negative, or false when 160 * result is greater than or equal to zero. 161 */ 162 static __inline__ int atomic_add_negative(int i, atomic_t *v) 163 { 164 unsigned char c; 165 166 __asm__ __volatile__( 167 LOCK_PREFIX "addl %2,%0; sets %1" 168 :"+m" (v->counter), "=qm" (c) 169 :"ir" (i) : "memory"); 170 return c; 171 } 172 173 /** 174 * atomic_add_return - add integer and return 175 * @v: pointer of type atomic_t 176 * @i: integer value to add 177 * 178 * Atomically adds @i to @v and returns @i + @v 179 */ 180 static __inline__ int atomic_add_return(int i, atomic_t *v) 181 { 182 int __i; 183 #ifdef CONFIG_M386 184 unsigned long flags; 185 if(unlikely(boot_cpu_data.x86 <= 3)) 186 goto no_xadd; 187 #endif 188 /* Modern 486+ processor */ 189 __i = i; 190 __asm__ __volatile__( 191 LOCK_PREFIX "xaddl %0, %1" 192 :"+r" (i), "+m" (v->counter) 193 : : "memory"); 194 return i + __i; 195 196 #ifdef CONFIG_M386 197 no_xadd: /* Legacy 386 processor */ 198 local_irq_save(flags); 199 __i = atomic_read(v); 200 atomic_set(v, i + __i); 201 local_irq_restore(flags); 202 return i + __i; 203 #endif 204 } 205 206 /** 207 * atomic_sub_return - subtract integer and return 208 * @v: pointer of type atomic_t 209 * @i: integer value to subtract 210 * 211 * Atomically subtracts @i from @v and returns @v - @i 212 */ 213 static __inline__ int atomic_sub_return(int i, atomic_t *v) 214 { 215 return atomic_add_return(-i,v); 216 } 217 218 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 219 #define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) 220 221 /** 222 * atomic_add_unless - add unless the number is already a given value 223 * @v: pointer of type atomic_t 224 * @a: the amount to add to v... 225 * @u: ...unless v is equal to u. 226 * 227 * Atomically adds @a to @v, so long as @v was not already @u. 228 * Returns non-zero if @v was not @u, and zero otherwise. 229 */ 230 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) 231 { 232 int c, old; 233 c = atomic_read(v); 234 for (;;) { 235 if (unlikely(c == (u))) 236 break; 237 old = atomic_cmpxchg((v), c, c + (a)); 238 if (likely(old == c)) 239 break; 240 c = old; 241 } 242 return c != (u); 243 } 244 245 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 246 247 #define atomic_inc_return(v) (atomic_add_return(1,v)) 248 #define atomic_dec_return(v) (atomic_sub_return(1,v)) 249 250 /* These are x86-specific, used by some header files */ 251 #define atomic_clear_mask(mask, addr) \ 252 __asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \ 253 : : "r" (~(mask)),"m" (*addr) : "memory") 254 255 #define atomic_set_mask(mask, addr) \ 256 __asm__ __volatile__(LOCK_PREFIX "orl %0,%1" \ 257 : : "r" (mask),"m" (*(addr)) : "memory") 258 259 /* Atomic operations are already serializing on x86 */ 260 #define smp_mb__before_atomic_dec() barrier() 261 #define smp_mb__after_atomic_dec() barrier() 262 #define smp_mb__before_atomic_inc() barrier() 263 #define smp_mb__after_atomic_inc() barrier() 264 265 #include <asm-generic/atomic.h> 266 #endif 267