cmpxchg.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Based on arch/arm/include/asm/cmpxchg.h
  4. *
  5. * Copyright (C) 2012 ARM Ltd.
  6. */
  7. #ifndef __ASM_CMPXCHG_H
  8. #define __ASM_CMPXCHG_H
  9. #include <linux/build_bug.h>
  10. #include <linux/compiler.h>
  11. #include <asm/barrier.h>
  12. #include <asm/lse.h>
  13. /*
  14. * We need separate acquire parameters for ll/sc and lse, since the full
  15. * barrier case is generated as release+dmb for the former and
  16. * acquire+release for the latter.
  17. */
  18. #define __XCHG_CASE(w, sfx, name, sz, mb, nop_lse, acq, acq_lse, rel, cl) \
  19. static inline u##sz __xchg_case_##name##sz(u##sz x, volatile void *ptr) \
  20. { \
  21. u##sz ret; \
  22. unsigned long tmp; \
  23. \
  24. asm volatile(ARM64_LSE_ATOMIC_INSN( \
  25. /* LL/SC */ \
  26. " prfm pstl1strm, %2\n" \
  27. "1: ld" #acq "xr" #sfx "\t%" #w "0, %2\n" \
  28. " st" #rel "xr" #sfx "\t%w1, %" #w "3, %2\n" \
  29. " cbnz %w1, 1b\n" \
  30. " " #mb, \
  31. /* LSE atomics */ \
  32. " swp" #acq_lse #rel #sfx "\t%" #w "3, %" #w "0, %2\n" \
  33. __nops(3) \
  34. " " #nop_lse) \
  35. : "=&r" (ret), "=&r" (tmp), "+Q" (*(u##sz *)ptr) \
  36. : "r" (x) \
  37. : cl); \
  38. \
  39. return ret; \
  40. }
  41. __XCHG_CASE(w, b, , 8, , , , , , )
  42. __XCHG_CASE(w, h, , 16, , , , , , )
  43. __XCHG_CASE(w, , , 32, , , , , , )
  44. __XCHG_CASE( , , , 64, , , , , , )
  45. __XCHG_CASE(w, b, acq_, 8, , , a, a, , "memory")
  46. __XCHG_CASE(w, h, acq_, 16, , , a, a, , "memory")
  47. __XCHG_CASE(w, , acq_, 32, , , a, a, , "memory")
  48. __XCHG_CASE( , , acq_, 64, , , a, a, , "memory")
  49. __XCHG_CASE(w, b, rel_, 8, , , , , l, "memory")
  50. __XCHG_CASE(w, h, rel_, 16, , , , , l, "memory")
  51. __XCHG_CASE(w, , rel_, 32, , , , , l, "memory")
  52. __XCHG_CASE( , , rel_, 64, , , , , l, "memory")
  53. __XCHG_CASE(w, b, mb_, 8, dmb ish, nop, , a, l, "memory")
  54. __XCHG_CASE(w, h, mb_, 16, dmb ish, nop, , a, l, "memory")
  55. __XCHG_CASE(w, , mb_, 32, dmb ish, nop, , a, l, "memory")
  56. __XCHG_CASE( , , mb_, 64, dmb ish, nop, , a, l, "memory")
  57. #undef __XCHG_CASE
  58. #define __XCHG_GEN(sfx) \
  59. static __always_inline unsigned long __xchg##sfx(unsigned long x, \
  60. volatile void *ptr, \
  61. int size) \
  62. { \
  63. switch (size) { \
  64. case 1: \
  65. return __xchg_case##sfx##_8(x, ptr); \
  66. case 2: \
  67. return __xchg_case##sfx##_16(x, ptr); \
  68. case 4: \
  69. return __xchg_case##sfx##_32(x, ptr); \
  70. case 8: \
  71. return __xchg_case##sfx##_64(x, ptr); \
  72. default: \
  73. BUILD_BUG(); \
  74. } \
  75. \
  76. unreachable(); \
  77. }
  78. __XCHG_GEN()
  79. __XCHG_GEN(_acq)
  80. __XCHG_GEN(_rel)
  81. __XCHG_GEN(_mb)
  82. #undef __XCHG_GEN
  83. #define __xchg_wrapper(sfx, ptr, x) \
  84. ({ \
  85. __typeof__(*(ptr)) __ret; \
  86. __ret = (__typeof__(*(ptr))) \
  87. __xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \
  88. __ret; \
  89. })
  90. /* xchg */
  91. #define arch_xchg_relaxed(...) __xchg_wrapper( , __VA_ARGS__)
  92. #define arch_xchg_acquire(...) __xchg_wrapper(_acq, __VA_ARGS__)
  93. #define arch_xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__)
  94. #define arch_xchg(...) __xchg_wrapper( _mb, __VA_ARGS__)
  95. #define __CMPXCHG_CASE(name, sz) \
  96. static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr, \
  97. u##sz old, \
  98. u##sz new) \
  99. { \
  100. return __lse_ll_sc_body(_cmpxchg_case_##name##sz, \
  101. ptr, old, new); \
  102. }
  103. __CMPXCHG_CASE( , 8)
  104. __CMPXCHG_CASE( , 16)
  105. __CMPXCHG_CASE( , 32)
  106. __CMPXCHG_CASE( , 64)
  107. __CMPXCHG_CASE(acq_, 8)
  108. __CMPXCHG_CASE(acq_, 16)
  109. __CMPXCHG_CASE(acq_, 32)
  110. __CMPXCHG_CASE(acq_, 64)
  111. __CMPXCHG_CASE(rel_, 8)
  112. __CMPXCHG_CASE(rel_, 16)
  113. __CMPXCHG_CASE(rel_, 32)
  114. __CMPXCHG_CASE(rel_, 64)
  115. __CMPXCHG_CASE(mb_, 8)
  116. __CMPXCHG_CASE(mb_, 16)
  117. __CMPXCHG_CASE(mb_, 32)
  118. __CMPXCHG_CASE(mb_, 64)
  119. #undef __CMPXCHG_CASE
  120. #define __CMPXCHG_DBL(name) \
  121. static inline long __cmpxchg_double##name(unsigned long old1, \
  122. unsigned long old2, \
  123. unsigned long new1, \
  124. unsigned long new2, \
  125. volatile void *ptr) \
  126. { \
  127. return __lse_ll_sc_body(_cmpxchg_double##name, \
  128. old1, old2, new1, new2, ptr); \
  129. }
  130. __CMPXCHG_DBL( )
  131. __CMPXCHG_DBL(_mb)
  132. #undef __CMPXCHG_DBL
  133. #define __CMPXCHG_GEN(sfx) \
  134. static __always_inline unsigned long __cmpxchg##sfx(volatile void *ptr, \
  135. unsigned long old, \
  136. unsigned long new, \
  137. int size) \
  138. { \
  139. switch (size) { \
  140. case 1: \
  141. return __cmpxchg_case##sfx##_8(ptr, old, new); \
  142. case 2: \
  143. return __cmpxchg_case##sfx##_16(ptr, old, new); \
  144. case 4: \
  145. return __cmpxchg_case##sfx##_32(ptr, old, new); \
  146. case 8: \
  147. return __cmpxchg_case##sfx##_64(ptr, old, new); \
  148. default: \
  149. BUILD_BUG(); \
  150. } \
  151. \
  152. unreachable(); \
  153. }
  154. __CMPXCHG_GEN()
  155. __CMPXCHG_GEN(_acq)
  156. __CMPXCHG_GEN(_rel)
  157. __CMPXCHG_GEN(_mb)
  158. #undef __CMPXCHG_GEN
  159. #define __cmpxchg_wrapper(sfx, ptr, o, n) \
  160. ({ \
  161. __typeof__(*(ptr)) __ret; \
  162. __ret = (__typeof__(*(ptr))) \
  163. __cmpxchg##sfx((ptr), (unsigned long)(o), \
  164. (unsigned long)(n), sizeof(*(ptr))); \
  165. __ret; \
  166. })
  167. /* cmpxchg */
  168. #define arch_cmpxchg_relaxed(...) __cmpxchg_wrapper( , __VA_ARGS__)
  169. #define arch_cmpxchg_acquire(...) __cmpxchg_wrapper(_acq, __VA_ARGS__)
  170. #define arch_cmpxchg_release(...) __cmpxchg_wrapper(_rel, __VA_ARGS__)
  171. #define arch_cmpxchg(...) __cmpxchg_wrapper( _mb, __VA_ARGS__)
  172. #define arch_cmpxchg_local arch_cmpxchg_relaxed
  173. /* cmpxchg64 */
  174. #define arch_cmpxchg64_relaxed arch_cmpxchg_relaxed
  175. #define arch_cmpxchg64_acquire arch_cmpxchg_acquire
  176. #define arch_cmpxchg64_release arch_cmpxchg_release
  177. #define arch_cmpxchg64 arch_cmpxchg
  178. #define arch_cmpxchg64_local arch_cmpxchg_local
  179. /* cmpxchg_double */
  180. #define system_has_cmpxchg_double() 1
  181. #define __cmpxchg_double_check(ptr1, ptr2) \
  182. ({ \
  183. if (sizeof(*(ptr1)) != 8) \
  184. BUILD_BUG(); \
  185. VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \
  186. })
  187. #define arch_cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
  188. ({ \
  189. int __ret; \
  190. __cmpxchg_double_check(ptr1, ptr2); \
  191. __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \
  192. (unsigned long)(n1), (unsigned long)(n2), \
  193. ptr1); \
  194. __ret; \
  195. })
  196. #define arch_cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
  197. ({ \
  198. int __ret; \
  199. __cmpxchg_double_check(ptr1, ptr2); \
  200. __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \
  201. (unsigned long)(n1), (unsigned long)(n2), \
  202. ptr1); \
  203. __ret; \
  204. })
  205. #define __CMPWAIT_CASE(w, sfx, sz) \
  206. static inline void __cmpwait_case_##sz(volatile void *ptr, \
  207. unsigned long val) \
  208. { \
  209. unsigned long tmp; \
  210. \
  211. asm volatile( \
  212. " sevl\n" \
  213. " wfe\n" \
  214. " ldxr" #sfx "\t%" #w "[tmp], %[v]\n" \
  215. " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \
  216. " cbnz %" #w "[tmp], 1f\n" \
  217. " wfe\n" \
  218. "1:" \
  219. : [tmp] "=&r" (tmp), [v] "+Q" (*(u##sz *)ptr) \
  220. : [val] "r" (val)); \
  221. }
  222. __CMPWAIT_CASE(w, b, 8);
  223. __CMPWAIT_CASE(w, h, 16);
  224. __CMPWAIT_CASE(w, , 32);
  225. __CMPWAIT_CASE( , , 64);
  226. #undef __CMPWAIT_CASE
  227. #define __CMPWAIT_GEN(sfx) \
  228. static __always_inline void __cmpwait##sfx(volatile void *ptr, \
  229. unsigned long val, \
  230. int size) \
  231. { \
  232. switch (size) { \
  233. case 1: \
  234. return __cmpwait_case##sfx##_8(ptr, (u8)val); \
  235. case 2: \
  236. return __cmpwait_case##sfx##_16(ptr, (u16)val); \
  237. case 4: \
  238. return __cmpwait_case##sfx##_32(ptr, val); \
  239. case 8: \
  240. return __cmpwait_case##sfx##_64(ptr, val); \
  241. default: \
  242. BUILD_BUG(); \
  243. } \
  244. \
  245. unreachable(); \
  246. }
  247. __CMPWAIT_GEN()
  248. #undef __CMPWAIT_GEN
  249. #define __cmpwait_relaxed(ptr, val) \
  250. __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr)))
  251. #endif /* __ASM_CMPXCHG_H */