cmpxchg.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ALPHA_CMPXCHG_H
  3. #define _ALPHA_CMPXCHG_H
  4. /*
  5. * Atomic exchange.
  6. * Since it can be used to implement critical sections
  7. * it must clobber "memory" (also for interrupts in UP).
  8. */
  9. static inline unsigned long
  10. ____xchg_u8(volatile char *m, unsigned long val)
  11. {
  12. unsigned long ret, tmp, addr64;
  13. __asm__ __volatile__(
  14. " andnot %4,7,%3\n"
  15. " insbl %1,%4,%1\n"
  16. "1: ldq_l %2,0(%3)\n"
  17. " extbl %2,%4,%0\n"
  18. " mskbl %2,%4,%2\n"
  19. " or %1,%2,%2\n"
  20. " stq_c %2,0(%3)\n"
  21. " beq %2,2f\n"
  22. ".subsection 2\n"
  23. "2: br 1b\n"
  24. ".previous"
  25. : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
  26. : "r" ((long)m), "1" (val) : "memory");
  27. return ret;
  28. }
  29. static inline unsigned long
  30. ____xchg_u16(volatile short *m, unsigned long val)
  31. {
  32. unsigned long ret, tmp, addr64;
  33. __asm__ __volatile__(
  34. " andnot %4,7,%3\n"
  35. " inswl %1,%4,%1\n"
  36. "1: ldq_l %2,0(%3)\n"
  37. " extwl %2,%4,%0\n"
  38. " mskwl %2,%4,%2\n"
  39. " or %1,%2,%2\n"
  40. " stq_c %2,0(%3)\n"
  41. " beq %2,2f\n"
  42. ".subsection 2\n"
  43. "2: br 1b\n"
  44. ".previous"
  45. : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
  46. : "r" ((long)m), "1" (val) : "memory");
  47. return ret;
  48. }
  49. static inline unsigned long
  50. ____xchg_u32(volatile int *m, unsigned long val)
  51. {
  52. unsigned long dummy;
  53. __asm__ __volatile__(
  54. "1: ldl_l %0,%4\n"
  55. " bis $31,%3,%1\n"
  56. " stl_c %1,%2\n"
  57. " beq %1,2f\n"
  58. ".subsection 2\n"
  59. "2: br 1b\n"
  60. ".previous"
  61. : "=&r" (val), "=&r" (dummy), "=m" (*m)
  62. : "rI" (val), "m" (*m) : "memory");
  63. return val;
  64. }
  65. static inline unsigned long
  66. ____xchg_u64(volatile long *m, unsigned long val)
  67. {
  68. unsigned long dummy;
  69. __asm__ __volatile__(
  70. "1: ldq_l %0,%4\n"
  71. " bis $31,%3,%1\n"
  72. " stq_c %1,%2\n"
  73. " beq %1,2f\n"
  74. ".subsection 2\n"
  75. "2: br 1b\n"
  76. ".previous"
  77. : "=&r" (val), "=&r" (dummy), "=m" (*m)
  78. : "rI" (val), "m" (*m) : "memory");
  79. return val;
  80. }
  81. /* This function doesn't exist, so you'll get a linker error
  82. if something tries to do an invalid xchg(). */
  83. extern void __xchg_called_with_bad_pointer(void);
  84. static __always_inline unsigned long
  85. ____xchg(volatile void *ptr, unsigned long x, int size)
  86. {
  87. return
  88. size == 1 ? ____xchg_u8(ptr, x) :
  89. size == 2 ? ____xchg_u16(ptr, x) :
  90. size == 4 ? ____xchg_u32(ptr, x) :
  91. size == 8 ? ____xchg_u64(ptr, x) :
  92. (__xchg_called_with_bad_pointer(), x);
  93. }
  94. /*
  95. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  96. * store NEW in MEM. Return the initial value in MEM. Success is
  97. * indicated by comparing RETURN with OLD.
  98. */
  99. static inline unsigned long
  100. ____cmpxchg_u8(volatile char *m, unsigned char old, unsigned char new)
  101. {
  102. unsigned long prev, tmp, cmp, addr64;
  103. __asm__ __volatile__(
  104. " andnot %5,7,%4\n"
  105. " insbl %1,%5,%1\n"
  106. "1: ldq_l %2,0(%4)\n"
  107. " extbl %2,%5,%0\n"
  108. " cmpeq %0,%6,%3\n"
  109. " beq %3,2f\n"
  110. " mskbl %2,%5,%2\n"
  111. " or %1,%2,%2\n"
  112. " stq_c %2,0(%4)\n"
  113. " beq %2,3f\n"
  114. "2:\n"
  115. ".subsection 2\n"
  116. "3: br 1b\n"
  117. ".previous"
  118. : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
  119. : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
  120. return prev;
  121. }
  122. static inline unsigned long
  123. ____cmpxchg_u16(volatile short *m, unsigned short old, unsigned short new)
  124. {
  125. unsigned long prev, tmp, cmp, addr64;
  126. __asm__ __volatile__(
  127. " andnot %5,7,%4\n"
  128. " inswl %1,%5,%1\n"
  129. "1: ldq_l %2,0(%4)\n"
  130. " extwl %2,%5,%0\n"
  131. " cmpeq %0,%6,%3\n"
  132. " beq %3,2f\n"
  133. " mskwl %2,%5,%2\n"
  134. " or %1,%2,%2\n"
  135. " stq_c %2,0(%4)\n"
  136. " beq %2,3f\n"
  137. "2:\n"
  138. ".subsection 2\n"
  139. "3: br 1b\n"
  140. ".previous"
  141. : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
  142. : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
  143. return prev;
  144. }
  145. static inline unsigned long
  146. ____cmpxchg_u32(volatile int *m, int old, int new)
  147. {
  148. unsigned long prev, cmp;
  149. __asm__ __volatile__(
  150. "1: ldl_l %0,%5\n"
  151. " cmpeq %0,%3,%1\n"
  152. " beq %1,2f\n"
  153. " mov %4,%1\n"
  154. " stl_c %1,%2\n"
  155. " beq %1,3f\n"
  156. "2:\n"
  157. ".subsection 2\n"
  158. "3: br 1b\n"
  159. ".previous"
  160. : "=&r"(prev), "=&r"(cmp), "=m"(*m)
  161. : "r"((long) old), "r"(new), "m"(*m) : "memory");
  162. return prev;
  163. }
  164. static inline unsigned long
  165. ____cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
  166. {
  167. unsigned long prev, cmp;
  168. __asm__ __volatile__(
  169. "1: ldq_l %0,%5\n"
  170. " cmpeq %0,%3,%1\n"
  171. " beq %1,2f\n"
  172. " mov %4,%1\n"
  173. " stq_c %1,%2\n"
  174. " beq %1,3f\n"
  175. "2:\n"
  176. ".subsection 2\n"
  177. "3: br 1b\n"
  178. ".previous"
  179. : "=&r"(prev), "=&r"(cmp), "=m"(*m)
  180. : "r"((long) old), "r"(new), "m"(*m) : "memory");
  181. return prev;
  182. }
  183. /* This function doesn't exist, so you'll get a linker error
  184. if something tries to do an invalid cmpxchg(). */
  185. extern void __cmpxchg_called_with_bad_pointer(void);
  186. static __always_inline unsigned long
  187. ____cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
  188. int size)
  189. {
  190. return
  191. size == 1 ? ____cmpxchg_u8(ptr, old, new) :
  192. size == 2 ? ____cmpxchg_u16(ptr, old, new) :
  193. size == 4 ? ____cmpxchg_u32(ptr, old, new) :
  194. size == 8 ? ____cmpxchg_u64(ptr, old, new) :
  195. (__cmpxchg_called_with_bad_pointer(), old);
  196. }
  197. #define xchg_local(ptr, x) \
  198. ({ \
  199. __typeof__(*(ptr)) _x_ = (x); \
  200. (__typeof__(*(ptr))) ____xchg((ptr), (unsigned long)_x_, \
  201. sizeof(*(ptr))); \
  202. })
  203. #define arch_cmpxchg_local(ptr, o, n) \
  204. ({ \
  205. __typeof__(*(ptr)) _o_ = (o); \
  206. __typeof__(*(ptr)) _n_ = (n); \
  207. (__typeof__(*(ptr))) ____cmpxchg((ptr), (unsigned long)_o_, \
  208. (unsigned long)_n_, \
  209. sizeof(*(ptr))); \
  210. })
  211. #define arch_cmpxchg64_local(ptr, o, n) \
  212. ({ \
  213. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  214. cmpxchg_local((ptr), (o), (n)); \
  215. })
  216. /*
  217. * The leading and the trailing memory barriers guarantee that these
  218. * operations are fully ordered.
  219. */
  220. #define arch_xchg(ptr, x) \
  221. ({ \
  222. __typeof__(*(ptr)) __ret; \
  223. __typeof__(*(ptr)) _x_ = (x); \
  224. smp_mb(); \
  225. __ret = (__typeof__(*(ptr))) \
  226. ____xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
  227. smp_mb(); \
  228. __ret; \
  229. })
  230. #define arch_cmpxchg(ptr, o, n) \
  231. ({ \
  232. __typeof__(*(ptr)) __ret; \
  233. __typeof__(*(ptr)) _o_ = (o); \
  234. __typeof__(*(ptr)) _n_ = (n); \
  235. smp_mb(); \
  236. __ret = (__typeof__(*(ptr))) ____cmpxchg((ptr), \
  237. (unsigned long)_o_, (unsigned long)_n_, sizeof(*(ptr)));\
  238. smp_mb(); \
  239. __ret; \
  240. })
  241. #define arch_cmpxchg64(ptr, o, n) \
  242. ({ \
  243. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  244. arch_cmpxchg((ptr), (o), (n)); \
  245. })
  246. #endif /* _ALPHA_CMPXCHG_H */