at v2.6.27 479 lines 9.3 kB view raw
1#ifndef _ASM_POWERPC_ATOMIC_H_ 2#define _ASM_POWERPC_ATOMIC_H_ 3 4/* 5 * PowerPC atomic operations 6 */ 7 8typedef struct { int counter; } atomic_t; 9 10#ifdef __KERNEL__ 11#include <linux/compiler.h> 12#include <asm/synch.h> 13#include <asm/asm-compat.h> 14#include <asm/system.h> 15 16#define ATOMIC_INIT(i) { (i) } 17 18static __inline__ int atomic_read(const atomic_t *v) 19{ 20 int t; 21 22 __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); 23 24 return t; 25} 26 27static __inline__ void atomic_set(atomic_t *v, int i) 28{ 29 __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); 30} 31 32static __inline__ void atomic_add(int a, atomic_t *v) 33{ 34 int t; 35 36 __asm__ __volatile__( 37"1: lwarx %0,0,%3 # atomic_add\n\ 38 add %0,%2,%0\n" 39 PPC405_ERR77(0,%3) 40" stwcx. %0,0,%3 \n\ 41 bne- 1b" 42 : "=&r" (t), "+m" (v->counter) 43 : "r" (a), "r" (&v->counter) 44 : "cc"); 45} 46 47static __inline__ int atomic_add_return(int a, atomic_t *v) 48{ 49 int t; 50 51 __asm__ __volatile__( 52 LWSYNC_ON_SMP 53"1: lwarx %0,0,%2 # atomic_add_return\n\ 54 add %0,%1,%0\n" 55 PPC405_ERR77(0,%2) 56" stwcx. %0,0,%2 \n\ 57 bne- 1b" 58 ISYNC_ON_SMP 59 : "=&r" (t) 60 : "r" (a), "r" (&v->counter) 61 : "cc", "memory"); 62 63 return t; 64} 65 66#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) 67 68static __inline__ void atomic_sub(int a, atomic_t *v) 69{ 70 int t; 71 72 __asm__ __volatile__( 73"1: lwarx %0,0,%3 # atomic_sub\n\ 74 subf %0,%2,%0\n" 75 PPC405_ERR77(0,%3) 76" stwcx. %0,0,%3 \n\ 77 bne- 1b" 78 : "=&r" (t), "+m" (v->counter) 79 : "r" (a), "r" (&v->counter) 80 : "cc"); 81} 82 83static __inline__ int atomic_sub_return(int a, atomic_t *v) 84{ 85 int t; 86 87 __asm__ __volatile__( 88 LWSYNC_ON_SMP 89"1: lwarx %0,0,%2 # atomic_sub_return\n\ 90 subf %0,%1,%0\n" 91 PPC405_ERR77(0,%2) 92" stwcx. %0,0,%2 \n\ 93 bne- 1b" 94 ISYNC_ON_SMP 95 : "=&r" (t) 96 : "r" (a), "r" (&v->counter) 97 : "cc", "memory"); 98 99 return t; 100} 101 102static __inline__ void atomic_inc(atomic_t *v) 103{ 104 int t; 105 106 __asm__ __volatile__( 107"1: lwarx %0,0,%2 # atomic_inc\n\ 108 addic %0,%0,1\n" 109 PPC405_ERR77(0,%2) 110" stwcx. %0,0,%2 \n\ 111 bne- 1b" 112 : "=&r" (t), "+m" (v->counter) 113 : "r" (&v->counter) 114 : "cc"); 115} 116 117static __inline__ int atomic_inc_return(atomic_t *v) 118{ 119 int t; 120 121 __asm__ __volatile__( 122 LWSYNC_ON_SMP 123"1: lwarx %0,0,%1 # atomic_inc_return\n\ 124 addic %0,%0,1\n" 125 PPC405_ERR77(0,%1) 126" stwcx. %0,0,%1 \n\ 127 bne- 1b" 128 ISYNC_ON_SMP 129 : "=&r" (t) 130 : "r" (&v->counter) 131 : "cc", "memory"); 132 133 return t; 134} 135 136/* 137 * atomic_inc_and_test - increment and test 138 * @v: pointer of type atomic_t 139 * 140 * Atomically increments @v by 1 141 * and returns true if the result is zero, or false for all 142 * other cases. 143 */ 144#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) 145 146static __inline__ void atomic_dec(atomic_t *v) 147{ 148 int t; 149 150 __asm__ __volatile__( 151"1: lwarx %0,0,%2 # atomic_dec\n\ 152 addic %0,%0,-1\n" 153 PPC405_ERR77(0,%2)\ 154" stwcx. %0,0,%2\n\ 155 bne- 1b" 156 : "=&r" (t), "+m" (v->counter) 157 : "r" (&v->counter) 158 : "cc"); 159} 160 161static __inline__ int atomic_dec_return(atomic_t *v) 162{ 163 int t; 164 165 __asm__ __volatile__( 166 LWSYNC_ON_SMP 167"1: lwarx %0,0,%1 # atomic_dec_return\n\ 168 addic %0,%0,-1\n" 169 PPC405_ERR77(0,%1) 170" stwcx. %0,0,%1\n\ 171 bne- 1b" 172 ISYNC_ON_SMP 173 : "=&r" (t) 174 : "r" (&v->counter) 175 : "cc", "memory"); 176 177 return t; 178} 179 180#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) 181#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 182 183/** 184 * atomic_add_unless - add unless the number is a given value 185 * @v: pointer of type atomic_t 186 * @a: the amount to add to v... 187 * @u: ...unless v is equal to u. 188 * 189 * Atomically adds @a to @v, so long as it was not @u. 190 * Returns non-zero if @v was not @u, and zero otherwise. 191 */ 192static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) 193{ 194 int t; 195 196 __asm__ __volatile__ ( 197 LWSYNC_ON_SMP 198"1: lwarx %0,0,%1 # atomic_add_unless\n\ 199 cmpw 0,%0,%3 \n\ 200 beq- 2f \n\ 201 add %0,%2,%0 \n" 202 PPC405_ERR77(0,%2) 203" stwcx. %0,0,%1 \n\ 204 bne- 1b \n" 205 ISYNC_ON_SMP 206" subf %0,%2,%0 \n\ 2072:" 208 : "=&r" (t) 209 : "r" (&v->counter), "r" (a), "r" (u) 210 : "cc", "memory"); 211 212 return t != u; 213} 214 215#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 216 217#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) 218#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) 219 220/* 221 * Atomically test *v and decrement if it is greater than 0. 222 * The function returns the old value of *v minus 1, even if 223 * the atomic variable, v, was not decremented. 224 */ 225static __inline__ int atomic_dec_if_positive(atomic_t *v) 226{ 227 int t; 228 229 __asm__ __volatile__( 230 LWSYNC_ON_SMP 231"1: lwarx %0,0,%1 # atomic_dec_if_positive\n\ 232 cmpwi %0,1\n\ 233 addi %0,%0,-1\n\ 234 blt- 2f\n" 235 PPC405_ERR77(0,%1) 236" stwcx. %0,0,%1\n\ 237 bne- 1b" 238 ISYNC_ON_SMP 239 "\n\ 2402:" : "=&b" (t) 241 : "r" (&v->counter) 242 : "cc", "memory"); 243 244 return t; 245} 246 247#define smp_mb__before_atomic_dec() smp_mb() 248#define smp_mb__after_atomic_dec() smp_mb() 249#define smp_mb__before_atomic_inc() smp_mb() 250#define smp_mb__after_atomic_inc() smp_mb() 251 252#ifdef __powerpc64__ 253 254typedef struct { long counter; } atomic64_t; 255 256#define ATOMIC64_INIT(i) { (i) } 257 258static __inline__ long atomic64_read(const atomic64_t *v) 259{ 260 long t; 261 262 __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter)); 263 264 return t; 265} 266 267static __inline__ void atomic64_set(atomic64_t *v, long i) 268{ 269 __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); 270} 271 272static __inline__ void atomic64_add(long a, atomic64_t *v) 273{ 274 long t; 275 276 __asm__ __volatile__( 277"1: ldarx %0,0,%3 # atomic64_add\n\ 278 add %0,%2,%0\n\ 279 stdcx. %0,0,%3 \n\ 280 bne- 1b" 281 : "=&r" (t), "+m" (v->counter) 282 : "r" (a), "r" (&v->counter) 283 : "cc"); 284} 285 286static __inline__ long atomic64_add_return(long a, atomic64_t *v) 287{ 288 long t; 289 290 __asm__ __volatile__( 291 LWSYNC_ON_SMP 292"1: ldarx %0,0,%2 # atomic64_add_return\n\ 293 add %0,%1,%0\n\ 294 stdcx. %0,0,%2 \n\ 295 bne- 1b" 296 ISYNC_ON_SMP 297 : "=&r" (t) 298 : "r" (a), "r" (&v->counter) 299 : "cc", "memory"); 300 301 return t; 302} 303 304#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) 305 306static __inline__ void atomic64_sub(long a, atomic64_t *v) 307{ 308 long t; 309 310 __asm__ __volatile__( 311"1: ldarx %0,0,%3 # atomic64_sub\n\ 312 subf %0,%2,%0\n\ 313 stdcx. %0,0,%3 \n\ 314 bne- 1b" 315 : "=&r" (t), "+m" (v->counter) 316 : "r" (a), "r" (&v->counter) 317 : "cc"); 318} 319 320static __inline__ long atomic64_sub_return(long a, atomic64_t *v) 321{ 322 long t; 323 324 __asm__ __volatile__( 325 LWSYNC_ON_SMP 326"1: ldarx %0,0,%2 # atomic64_sub_return\n\ 327 subf %0,%1,%0\n\ 328 stdcx. %0,0,%2 \n\ 329 bne- 1b" 330 ISYNC_ON_SMP 331 : "=&r" (t) 332 : "r" (a), "r" (&v->counter) 333 : "cc", "memory"); 334 335 return t; 336} 337 338static __inline__ void atomic64_inc(atomic64_t *v) 339{ 340 long t; 341 342 __asm__ __volatile__( 343"1: ldarx %0,0,%2 # atomic64_inc\n\ 344 addic %0,%0,1\n\ 345 stdcx. %0,0,%2 \n\ 346 bne- 1b" 347 : "=&r" (t), "+m" (v->counter) 348 : "r" (&v->counter) 349 : "cc"); 350} 351 352static __inline__ long atomic64_inc_return(atomic64_t *v) 353{ 354 long t; 355 356 __asm__ __volatile__( 357 LWSYNC_ON_SMP 358"1: ldarx %0,0,%1 # atomic64_inc_return\n\ 359 addic %0,%0,1\n\ 360 stdcx. %0,0,%1 \n\ 361 bne- 1b" 362 ISYNC_ON_SMP 363 : "=&r" (t) 364 : "r" (&v->counter) 365 : "cc", "memory"); 366 367 return t; 368} 369 370/* 371 * atomic64_inc_and_test - increment and test 372 * @v: pointer of type atomic64_t 373 * 374 * Atomically increments @v by 1 375 * and returns true if the result is zero, or false for all 376 * other cases. 377 */ 378#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) 379 380static __inline__ void atomic64_dec(atomic64_t *v) 381{ 382 long t; 383 384 __asm__ __volatile__( 385"1: ldarx %0,0,%2 # atomic64_dec\n\ 386 addic %0,%0,-1\n\ 387 stdcx. %0,0,%2\n\ 388 bne- 1b" 389 : "=&r" (t), "+m" (v->counter) 390 : "r" (&v->counter) 391 : "cc"); 392} 393 394static __inline__ long atomic64_dec_return(atomic64_t *v) 395{ 396 long t; 397 398 __asm__ __volatile__( 399 LWSYNC_ON_SMP 400"1: ldarx %0,0,%1 # atomic64_dec_return\n\ 401 addic %0,%0,-1\n\ 402 stdcx. %0,0,%1\n\ 403 bne- 1b" 404 ISYNC_ON_SMP 405 : "=&r" (t) 406 : "r" (&v->counter) 407 : "cc", "memory"); 408 409 return t; 410} 411 412#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) 413#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) 414 415/* 416 * Atomically test *v and decrement if it is greater than 0. 417 * The function returns the old value of *v minus 1. 418 */ 419static __inline__ long atomic64_dec_if_positive(atomic64_t *v) 420{ 421 long t; 422 423 __asm__ __volatile__( 424 LWSYNC_ON_SMP 425"1: ldarx %0,0,%1 # atomic64_dec_if_positive\n\ 426 addic. %0,%0,-1\n\ 427 blt- 2f\n\ 428 stdcx. %0,0,%1\n\ 429 bne- 1b" 430 ISYNC_ON_SMP 431 "\n\ 4322:" : "=&r" (t) 433 : "r" (&v->counter) 434 : "cc", "memory"); 435 436 return t; 437} 438 439#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) 440#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 441 442/** 443 * atomic64_add_unless - add unless the number is a given value 444 * @v: pointer of type atomic64_t 445 * @a: the amount to add to v... 446 * @u: ...unless v is equal to u. 447 * 448 * Atomically adds @a to @v, so long as it was not @u. 449 * Returns non-zero if @v was not @u, and zero otherwise. 450 */ 451static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) 452{ 453 long t; 454 455 __asm__ __volatile__ ( 456 LWSYNC_ON_SMP 457"1: ldarx %0,0,%1 # atomic_add_unless\n\ 458 cmpd 0,%0,%3 \n\ 459 beq- 2f \n\ 460 add %0,%2,%0 \n" 461" stdcx. %0,0,%1 \n\ 462 bne- 1b \n" 463 ISYNC_ON_SMP 464" subf %0,%2,%0 \n\ 4652:" 466 : "=&r" (t) 467 : "r" (&v->counter), "r" (a), "r" (u) 468 : "cc", "memory"); 469 470 return t != u; 471} 472 473#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) 474 475#endif /* __powerpc64__ */ 476 477#include <asm-generic/atomic.h> 478#endif /* __KERNEL__ */ 479#endif /* _ASM_POWERPC_ATOMIC_H_ */