1
0

cmpxchg.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Based on arch/arm/include/asm/cmpxchg.h
  3. *
  4. * Copyright (C) 2012 ARM Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #ifndef __ASM_CMPXCHG_H
  19. #define __ASM_CMPXCHG_H
  20. #include <linux/build_bug.h>
  21. #include <linux/compiler.h>
  22. #include <asm/atomic.h>
  23. #include <asm/barrier.h>
  24. #include <asm/lse.h>
  25. /*
  26. * We need separate acquire parameters for ll/sc and lse, since the full
  27. * barrier case is generated as release+dmb for the former and
  28. * acquire+release for the latter.
  29. */
  30. #define __XCHG_CASE(w, sfx, name, sz, mb, nop_lse, acq, acq_lse, rel, cl) \
  31. static inline u##sz __xchg_case_##name##sz(u##sz x, volatile void *ptr) \
  32. { \
  33. u##sz ret; \
  34. unsigned long tmp; \
  35. \
  36. asm volatile(ARM64_LSE_ATOMIC_INSN( \
  37. /* LL/SC */ \
  38. " prfm pstl1strm, %2\n" \
  39. "1: ld" #acq "xr" #sfx "\t%" #w "0, %2\n" \
  40. " st" #rel "xr" #sfx "\t%w1, %" #w "3, %2\n" \
  41. " cbnz %w1, 1b\n" \
  42. " " #mb, \
  43. /* LSE atomics */ \
  44. " swp" #acq_lse #rel #sfx "\t%" #w "3, %" #w "0, %2\n" \
  45. __nops(3) \
  46. " " #nop_lse) \
  47. : "=&r" (ret), "=&r" (tmp), "+Q" (*(u##sz *)ptr) \
  48. : "r" (x) \
  49. : cl); \
  50. \
  51. return ret; \
  52. }
  53. __XCHG_CASE(w, b, , 8, , , , , , )
  54. __XCHG_CASE(w, h, , 16, , , , , , )
  55. __XCHG_CASE(w, , , 32, , , , , , )
  56. __XCHG_CASE( , , , 64, , , , , , )
  57. __XCHG_CASE(w, b, acq_, 8, , , a, a, , "memory")
  58. __XCHG_CASE(w, h, acq_, 16, , , a, a, , "memory")
  59. __XCHG_CASE(w, , acq_, 32, , , a, a, , "memory")
  60. __XCHG_CASE( , , acq_, 64, , , a, a, , "memory")
  61. __XCHG_CASE(w, b, rel_, 8, , , , , l, "memory")
  62. __XCHG_CASE(w, h, rel_, 16, , , , , l, "memory")
  63. __XCHG_CASE(w, , rel_, 32, , , , , l, "memory")
  64. __XCHG_CASE( , , rel_, 64, , , , , l, "memory")
  65. __XCHG_CASE(w, b, mb_, 8, dmb ish, nop, , a, l, "memory")
  66. __XCHG_CASE(w, h, mb_, 16, dmb ish, nop, , a, l, "memory")
  67. __XCHG_CASE(w, , mb_, 32, dmb ish, nop, , a, l, "memory")
  68. __XCHG_CASE( , , mb_, 64, dmb ish, nop, , a, l, "memory")
  69. #undef __XCHG_CASE
  70. #define __XCHG_GEN(sfx) \
  71. static __always_inline unsigned long __xchg##sfx(unsigned long x, \
  72. volatile void *ptr, \
  73. int size) \
  74. { \
  75. switch (size) { \
  76. case 1: \
  77. return __xchg_case##sfx##_8(x, ptr); \
  78. case 2: \
  79. return __xchg_case##sfx##_16(x, ptr); \
  80. case 4: \
  81. return __xchg_case##sfx##_32(x, ptr); \
  82. case 8: \
  83. return __xchg_case##sfx##_64(x, ptr); \
  84. default: \
  85. BUILD_BUG(); \
  86. } \
  87. \
  88. unreachable(); \
  89. }
  90. __XCHG_GEN()
  91. __XCHG_GEN(_acq)
  92. __XCHG_GEN(_rel)
  93. __XCHG_GEN(_mb)
  94. #undef __XCHG_GEN
  95. #define __xchg_wrapper(sfx, ptr, x) \
  96. ({ \
  97. __typeof__(*(ptr)) __ret; \
  98. __ret = (__typeof__(*(ptr))) \
  99. __xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \
  100. __ret; \
  101. })
  102. /* xchg */
  103. #define xchg_relaxed(...) __xchg_wrapper( , __VA_ARGS__)
  104. #define xchg_acquire(...) __xchg_wrapper(_acq, __VA_ARGS__)
  105. #define xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__)
  106. #define xchg(...) __xchg_wrapper( _mb, __VA_ARGS__)
  107. #define __CMPXCHG_GEN(sfx) \
  108. static __always_inline unsigned long __cmpxchg##sfx(volatile void *ptr, \
  109. unsigned long old, \
  110. unsigned long new, \
  111. int size) \
  112. { \
  113. switch (size) { \
  114. case 1: \
  115. return __cmpxchg_case##sfx##_8(ptr, (u8)old, new); \
  116. case 2: \
  117. return __cmpxchg_case##sfx##_16(ptr, (u16)old, new); \
  118. case 4: \
  119. return __cmpxchg_case##sfx##_32(ptr, old, new); \
  120. case 8: \
  121. return __cmpxchg_case##sfx##_64(ptr, old, new); \
  122. default: \
  123. BUILD_BUG(); \
  124. } \
  125. \
  126. unreachable(); \
  127. }
  128. __CMPXCHG_GEN()
  129. __CMPXCHG_GEN(_acq)
  130. __CMPXCHG_GEN(_rel)
  131. __CMPXCHG_GEN(_mb)
  132. #undef __CMPXCHG_GEN
  133. #define __cmpxchg_wrapper(sfx, ptr, o, n) \
  134. ({ \
  135. __typeof__(*(ptr)) __ret; \
  136. __ret = (__typeof__(*(ptr))) \
  137. __cmpxchg##sfx((ptr), (unsigned long)(o), \
  138. (unsigned long)(n), sizeof(*(ptr))); \
  139. __ret; \
  140. })
  141. /* cmpxchg */
  142. #define cmpxchg_relaxed(...) __cmpxchg_wrapper( , __VA_ARGS__)
  143. #define cmpxchg_acquire(...) __cmpxchg_wrapper(_acq, __VA_ARGS__)
  144. #define cmpxchg_release(...) __cmpxchg_wrapper(_rel, __VA_ARGS__)
  145. #define cmpxchg(...) __cmpxchg_wrapper( _mb, __VA_ARGS__)
  146. #define cmpxchg_local cmpxchg_relaxed
  147. /* cmpxchg64 */
  148. #define cmpxchg64_relaxed cmpxchg_relaxed
  149. #define cmpxchg64_acquire cmpxchg_acquire
  150. #define cmpxchg64_release cmpxchg_release
  151. #define cmpxchg64 cmpxchg
  152. #define cmpxchg64_local cmpxchg_local
  153. /* cmpxchg_double */
  154. #define system_has_cmpxchg_double() 1
  155. #define __cmpxchg_double_check(ptr1, ptr2) \
  156. ({ \
  157. if (sizeof(*(ptr1)) != 8) \
  158. BUILD_BUG(); \
  159. VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \
  160. })
  161. #define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
  162. ({\
  163. int __ret;\
  164. __cmpxchg_double_check(ptr1, ptr2); \
  165. __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \
  166. (unsigned long)(n1), (unsigned long)(n2), \
  167. ptr1); \
  168. __ret; \
  169. })
  170. #define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
  171. ({\
  172. int __ret;\
  173. __cmpxchg_double_check(ptr1, ptr2); \
  174. __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \
  175. (unsigned long)(n1), (unsigned long)(n2), \
  176. ptr1); \
  177. __ret; \
  178. })
  179. #define __CMPWAIT_CASE(w, sfx, sz) \
  180. static inline void __cmpwait_case_##sz(volatile void *ptr, \
  181. unsigned long val) \
  182. { \
  183. unsigned long tmp; \
  184. \
  185. asm volatile( \
  186. " sevl\n" \
  187. " wfe\n" \
  188. " ldxr" #sfx "\t%" #w "[tmp], %[v]\n" \
  189. " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \
  190. " cbnz %" #w "[tmp], 1f\n" \
  191. " wfe\n" \
  192. "1:" \
  193. : [tmp] "=&r" (tmp), [v] "+Q" (*(unsigned long *)ptr) \
  194. : [val] "r" (val)); \
  195. }
  196. __CMPWAIT_CASE(w, b, 8);
  197. __CMPWAIT_CASE(w, h, 16);
  198. __CMPWAIT_CASE(w, , 32);
  199. __CMPWAIT_CASE( , , 64);
  200. #undef __CMPWAIT_CASE
  201. #define __CMPWAIT_GEN(sfx) \
  202. static __always_inline void __cmpwait##sfx(volatile void *ptr, \
  203. unsigned long val, \
  204. int size) \
  205. { \
  206. switch (size) { \
  207. case 1: \
  208. return __cmpwait_case##sfx##_8(ptr, (u8)val); \
  209. case 2: \
  210. return __cmpwait_case##sfx##_16(ptr, (u16)val); \
  211. case 4: \
  212. return __cmpwait_case##sfx##_32(ptr, val); \
  213. case 8: \
  214. return __cmpwait_case##sfx##_64(ptr, val); \
  215. default: \
  216. BUILD_BUG(); \
  217. } \
  218. \
  219. unreachable(); \
  220. }
  221. __CMPWAIT_GEN()
  222. #undef __CMPWAIT_GEN
  223. #define __cmpwait_relaxed(ptr, val) \
  224. __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr)))
  225. #endif /* __ASM_CMPXCHG_H */