atomic.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * PowerPC atomic operations
  3. */
  4. #ifndef _ASM_PPC_ATOMIC_H_
  5. #define _ASM_PPC_ATOMIC_H_
  6. typedef struct { volatile int counter; } atomic_t;
  7. #ifdef __KERNEL__
  8. #define ATOMIC_INIT(i) { (i) }
  9. #define atomic_read(v) ((v)->counter)
  10. #define atomic_set(v,i) (((v)->counter) = (i))
  11. extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
  12. #ifdef CONFIG_SMP
  13. #define SMP_SYNC "sync"
  14. #define SMP_ISYNC "\n\tisync"
  15. #else
  16. #define SMP_SYNC ""
  17. #define SMP_ISYNC
  18. #endif
  19. /* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx.
  20. * The old ATOMIC_SYNC_FIX covered some but not all of this.
  21. */
  22. #ifdef CONFIG_IBM405_ERR77
  23. #define PPC405_ERR77(ra,rb) "dcbt " #ra "," #rb ";"
  24. #else
  25. #define PPC405_ERR77(ra,rb)
  26. #endif
  27. static __inline__ void atomic_add(int a, atomic_t *v)
  28. {
  29. int t;
  30. __asm__ __volatile__(
  31. "1: lwarx %0,0,%3 # atomic_add\n\
  32. add %0,%2,%0\n"
  33. PPC405_ERR77(0,%3)
  34. " stwcx. %0,0,%3 \n\
  35. bne- 1b"
  36. : "=&r" (t), "=m" (v->counter)
  37. : "r" (a), "r" (&v->counter), "m" (v->counter)
  38. : "cc");
  39. }
  40. static __inline__ int atomic_add_return(int a, atomic_t *v)
  41. {
  42. int t;
  43. __asm__ __volatile__(
  44. "1: lwarx %0,0,%2 # atomic_add_return\n\
  45. add %0,%1,%0\n"
  46. PPC405_ERR77(0,%2)
  47. " stwcx. %0,0,%2 \n\
  48. bne- 1b"
  49. SMP_ISYNC
  50. : "=&r" (t)
  51. : "r" (a), "r" (&v->counter)
  52. : "cc", "memory");
  53. return t;
  54. }
  55. #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
  56. static __inline__ void atomic_sub(int a, atomic_t *v)
  57. {
  58. int t;
  59. __asm__ __volatile__(
  60. "1: lwarx %0,0,%3 # atomic_sub\n\
  61. subf %0,%2,%0\n"
  62. PPC405_ERR77(0,%3)
  63. " stwcx. %0,0,%3 \n\
  64. bne- 1b"
  65. : "=&r" (t), "=m" (v->counter)
  66. : "r" (a), "r" (&v->counter), "m" (v->counter)
  67. : "cc");
  68. }
  69. static __inline__ int atomic_sub_return(int a, atomic_t *v)
  70. {
  71. int t;
  72. __asm__ __volatile__(
  73. "1: lwarx %0,0,%2 # atomic_sub_return\n\
  74. subf %0,%1,%0\n"
  75. PPC405_ERR77(0,%2)
  76. " stwcx. %0,0,%2 \n\
  77. bne- 1b"
  78. SMP_ISYNC
  79. : "=&r" (t)
  80. : "r" (a), "r" (&v->counter)
  81. : "cc", "memory");
  82. return t;
  83. }
  84. static __inline__ void atomic_inc(atomic_t *v)
  85. {
  86. int t;
  87. __asm__ __volatile__(
  88. "1: lwarx %0,0,%2 # atomic_inc\n\
  89. addic %0,%0,1\n"
  90. PPC405_ERR77(0,%2)
  91. " stwcx. %0,0,%2 \n\
  92. bne- 1b"
  93. : "=&r" (t), "=m" (v->counter)
  94. : "r" (&v->counter), "m" (v->counter)
  95. : "cc");
  96. }
  97. static __inline__ int atomic_inc_return(atomic_t *v)
  98. {
  99. int t;
  100. __asm__ __volatile__(
  101. "1: lwarx %0,0,%1 # atomic_inc_return\n\
  102. addic %0,%0,1\n"
  103. PPC405_ERR77(0,%1)
  104. " stwcx. %0,0,%1 \n\
  105. bne- 1b"
  106. SMP_ISYNC
  107. : "=&r" (t)
  108. : "r" (&v->counter)
  109. : "cc", "memory");
  110. return t;
  111. }
  112. /*
  113. * atomic_inc_and_test - increment and test
  114. * @v: pointer of type atomic_t
  115. *
  116. * Atomically increments @v by 1
  117. * and returns true if the result is zero, or false for all
  118. * other cases.
  119. */
  120. #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
  121. static __inline__ void atomic_dec(atomic_t *v)
  122. {
  123. int t;
  124. __asm__ __volatile__(
  125. "1: lwarx %0,0,%2 # atomic_dec\n\
  126. addic %0,%0,-1\n"
  127. PPC405_ERR77(0,%2)\
  128. " stwcx. %0,0,%2\n\
  129. bne- 1b"
  130. : "=&r" (t), "=m" (v->counter)
  131. : "r" (&v->counter), "m" (v->counter)
  132. : "cc");
  133. }
  134. static __inline__ int atomic_dec_return(atomic_t *v)
  135. {
  136. int t;
  137. __asm__ __volatile__(
  138. "1: lwarx %0,0,%1 # atomic_dec_return\n\
  139. addic %0,%0,-1\n"
  140. PPC405_ERR77(0,%1)
  141. " stwcx. %0,0,%1\n\
  142. bne- 1b"
  143. SMP_ISYNC
  144. : "=&r" (t)
  145. : "r" (&v->counter)
  146. : "cc", "memory");
  147. return t;
  148. }
  149. #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0)
  150. #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0)
  151. /*
  152. * Atomically test *v and decrement if it is greater than 0.
  153. * The function returns the old value of *v minus 1.
  154. */
  155. static __inline__ int atomic_dec_if_positive(atomic_t *v)
  156. {
  157. int t;
  158. __asm__ __volatile__(
  159. "1: lwarx %0,0,%1 # atomic_dec_if_positive\n\
  160. addic. %0,%0,-1\n\
  161. blt- 2f\n"
  162. PPC405_ERR77(0,%1)
  163. " stwcx. %0,0,%1\n\
  164. bne- 1b"
  165. SMP_ISYNC
  166. "\n\
  167. 2:" : "=&r" (t)
  168. : "r" (&v->counter)
  169. : "cc", "memory");
  170. return t;
  171. }
  172. #define __MB __asm__ __volatile__ (SMP_SYNC : : : "memory")
  173. #define smp_mb__before_atomic_dec() __MB
  174. #define smp_mb__after_atomic_dec() __MB
  175. #define smp_mb__before_atomic_inc() __MB
  176. #define smp_mb__after_atomic_inc() __MB
  177. #endif /* __KERNEL__ */
  178. #endif /* _ASM_PPC_ATOMIC_H_ */