atomic64_32.c 5.1 KB

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