atomic64_32.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include <linux/compiler.h>
  2. #include <linux/types.h>
  3. #include <asm/processor.h>
  4. #include <asm/cmpxchg.h>
  5. #include <asm/atomic.h>
  6. static noinline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new)
  7. {
  8. u32 low = new;
  9. u32 high = new >> 32;
  10. asm volatile(
  11. LOCK_PREFIX "cmpxchg8b %1\n"
  12. : "+A" (old), "+m" (*ptr)
  13. : "b" (low), "c" (high)
  14. );
  15. return old;
  16. }
  17. u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val)
  18. {
  19. return cmpxchg8b(&ptr->counter, old_val, new_val);
  20. }
  21. /**
  22. * atomic64_xchg - xchg atomic64 variable
  23. * @ptr: pointer to type atomic64_t
  24. * @new_val: value to assign
  25. *
  26. * Atomically xchgs the value of @ptr to @new_val and returns
  27. * the old value.
  28. */
  29. u64 atomic64_xchg(atomic64_t *ptr, u64 new_val)
  30. {
  31. u64 old_val;
  32. do {
  33. old_val = atomic_read(ptr);
  34. } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
  35. return old_val;
  36. }
  37. /**
  38. * atomic64_set - set atomic64 variable
  39. * @ptr: pointer to type atomic64_t
  40. * @new_val: value to assign
  41. *
  42. * Atomically sets the value of @ptr to @new_val.
  43. */
  44. void atomic64_set(atomic64_t *ptr, u64 new_val)
  45. {
  46. atomic64_xchg(ptr, new_val);
  47. }
  48. /**
  49. * atomic64_read - read atomic64 variable
  50. * @ptr: pointer to type atomic64_t
  51. *
  52. * Atomically reads the value of @ptr and returns it.
  53. */
  54. u64 atomic64_read(atomic64_t *ptr)
  55. {
  56. u64 old = 1LL << 32;
  57. return cmpxchg8b(&ptr->counter, old, old);
  58. }
  59. /**
  60. * atomic64_add_return - add and return
  61. * @delta: integer value to add
  62. * @ptr: pointer to type atomic64_t
  63. *
  64. * Atomically adds @delta to @ptr and returns @delta + *@ptr
  65. */
  66. noinline u64 atomic64_add_return(u64 delta, atomic64_t *ptr)
  67. {
  68. /*
  69. * Try first with a (probably incorrect) assumption about
  70. * what we have there. We'll do two loops most likely,
  71. * but we'll get an ownership MESI transaction straight away
  72. * instead of a read transaction followed by a
  73. * flush-for-ownership transaction:
  74. */
  75. u64 old_val, new_val, real_val = 1ULL << 32;
  76. do {
  77. old_val = real_val;
  78. new_val = old_val + delta;
  79. real_val = atomic64_cmpxchg(ptr, old_val, new_val);
  80. } while (real_val != old_val);
  81. return new_val;
  82. }
  83. u64 atomic64_sub_return(u64 delta, atomic64_t *ptr)
  84. {
  85. return atomic64_add_return(-delta, ptr);
  86. }
  87. u64 atomic64_inc_return(atomic64_t *ptr)
  88. {
  89. return atomic64_add_return(1, ptr);
  90. }
  91. u64 atomic64_dec_return(atomic64_t *ptr)
  92. {
  93. return atomic64_sub_return(1, ptr);
  94. }
  95. /**
  96. * atomic64_add - add integer to atomic64 variable
  97. * @delta: integer value to add
  98. * @ptr: pointer to type atomic64_t
  99. *
  100. * Atomically adds @delta to @ptr.
  101. */
  102. void atomic64_add(u64 delta, atomic64_t *ptr)
  103. {
  104. atomic64_add_return(delta, ptr);
  105. }
  106. /**
  107. * atomic64_sub - subtract the atomic64 variable
  108. * @delta: integer value to subtract
  109. * @ptr: pointer to type atomic64_t
  110. *
  111. * Atomically subtracts @delta from @ptr.
  112. */
  113. void atomic64_sub(u64 delta, atomic64_t *ptr)
  114. {
  115. atomic64_add(-delta, ptr);
  116. }
  117. /**
  118. * atomic64_sub_and_test - subtract value from variable and test result
  119. * @delta: integer value to subtract
  120. * @ptr: pointer to type atomic64_t
  121. *
  122. * Atomically subtracts @delta from @ptr and returns
  123. * true if the result is zero, or false for all
  124. * other cases.
  125. */
  126. int atomic64_sub_and_test(u64 delta, atomic64_t *ptr)
  127. {
  128. u64 old_val = atomic64_sub_return(delta, ptr);
  129. return old_val == 0;
  130. }
  131. /**
  132. * atomic64_inc - increment atomic64 variable
  133. * @ptr: pointer to type atomic64_t
  134. *
  135. * Atomically increments @ptr by 1.
  136. */
  137. void atomic64_inc(atomic64_t *ptr)
  138. {
  139. atomic64_add(1, ptr);
  140. }
  141. /**
  142. * atomic64_dec - decrement atomic64 variable
  143. * @ptr: pointer to type atomic64_t
  144. *
  145. * Atomically decrements @ptr by 1.
  146. */
  147. void atomic64_dec(atomic64_t *ptr)
  148. {
  149. atomic64_sub(1, ptr);
  150. }
  151. /**
  152. * atomic64_dec_and_test - decrement and test
  153. * @ptr: pointer to type atomic64_t
  154. *
  155. * Atomically decrements @ptr by 1 and
  156. * returns true if the result is 0, or false for all other
  157. * cases.
  158. */
  159. int atomic64_dec_and_test(atomic64_t *ptr)
  160. {
  161. return atomic64_sub_and_test(1, ptr);
  162. }
  163. /**
  164. * atomic64_inc_and_test - increment and test
  165. * @ptr: pointer to type atomic64_t
  166. *
  167. * Atomically increments @ptr by 1
  168. * and returns true if the result is zero, or false for all
  169. * other cases.
  170. */
  171. int atomic64_inc_and_test(atomic64_t *ptr)
  172. {
  173. return atomic64_sub_and_test(-1, ptr);
  174. }
  175. /**
  176. * atomic64_add_negative - add and test if negative
  177. * @delta: integer value to add
  178. * @ptr: pointer to type atomic64_t
  179. *
  180. * Atomically adds @delta to @ptr and returns true
  181. * if the result is negative, or false when
  182. * result is greater than or equal to zero.
  183. */
  184. int atomic64_add_negative(u64 delta, atomic64_t *ptr)
  185. {
  186. long long old_val = atomic64_add_return(delta, ptr);
  187. return old_val < 0;
  188. }