cmpxchg_32.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #ifndef _ASM_X86_CMPXCHG_32_H
  2. #define _ASM_X86_CMPXCHG_32_H
  3. #include <linux/bitops.h> /* for LOCK_PREFIX */
  4. /*
  5. * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
  6. * you need to test for the feature in boot_cpu_data.
  7. */
  8. extern void __xchg_wrong_size(void);
  9. /*
  10. * Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
  11. * Since this is generally used to protect other memory information, we
  12. * use "asm volatile" and "memory" clobbers to prevent gcc from moving
  13. * information around.
  14. */
  15. #define __xchg(x, ptr, size) \
  16. ({ \
  17. __typeof(*(ptr)) __x = (x); \
  18. switch (size) { \
  19. case 1: \
  20. { \
  21. volatile u8 *__ptr = (volatile u8 *)(ptr); \
  22. asm volatile("xchgb %0,%1" \
  23. : "=q" (__x), "+m" (*__ptr) \
  24. : "0" (__x) \
  25. : "memory"); \
  26. break; \
  27. } \
  28. case 2: \
  29. { \
  30. volatile u16 *__ptr = (volatile u16 *)(ptr); \
  31. asm volatile("xchgw %0,%1" \
  32. : "=r" (__x), "+m" (*__ptr) \
  33. : "0" (__x) \
  34. : "memory"); \
  35. break; \
  36. } \
  37. case 4: \
  38. { \
  39. volatile u32 *__ptr = (volatile u32 *)(ptr); \
  40. asm volatile("xchgl %0,%1" \
  41. : "=r" (__x), "+m" (*__ptr) \
  42. : "0" (__x) \
  43. : "memory"); \
  44. break; \
  45. } \
  46. default: \
  47. __xchg_wrong_size(); \
  48. } \
  49. __x; \
  50. })
  51. #define xchg(ptr, v) \
  52. __xchg((v), (ptr), sizeof(*ptr))
  53. /*
  54. * CMPXCHG8B only writes to the target if we had the previous
  55. * value in registers, otherwise it acts as a read and gives us the
  56. * "new previous" value. That is why there is a loop. Preloading
  57. * EDX:EAX is a performance optimization: in the common case it means
  58. * we need only one locked operation.
  59. *
  60. * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
  61. * least an FPU save and/or %cr0.ts manipulation.
  62. *
  63. * cmpxchg8b must be used with the lock prefix here to allow the
  64. * instruction to be executed atomically. We need to have the reader
  65. * side to see the coherent 64bit value.
  66. */
  67. static inline void set_64bit(volatile u64 *ptr, u64 value)
  68. {
  69. u32 low = value;
  70. u32 high = value >> 32;
  71. u64 prev = *ptr;
  72. asm volatile("\n1:\t"
  73. LOCK_PREFIX "cmpxchg8b %0\n\t"
  74. "jnz 1b"
  75. : "=m" (*ptr), "+A" (prev)
  76. : "b" (low), "c" (high)
  77. : "memory");
  78. }
  79. extern void __cmpxchg_wrong_size(void);
  80. /*
  81. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  82. * store NEW in MEM. Return the initial value in MEM. Success is
  83. * indicated by comparing RETURN with OLD.
  84. */
  85. #define __raw_cmpxchg(ptr, old, new, size, lock) \
  86. ({ \
  87. __typeof__(*(ptr)) __ret; \
  88. __typeof__(*(ptr)) __old = (old); \
  89. __typeof__(*(ptr)) __new = (new); \
  90. switch (size) { \
  91. case 1: \
  92. { \
  93. volatile u8 *__ptr = (volatile u8 *)(ptr); \
  94. asm volatile(lock "cmpxchgb %2,%1" \
  95. : "=a" (__ret), "+m" (*__ptr) \
  96. : "q" (__new), "0" (__old) \
  97. : "memory"); \
  98. break; \
  99. } \
  100. case 2: \
  101. { \
  102. volatile u16 *__ptr = (volatile u16 *)(ptr); \
  103. asm volatile(lock "cmpxchgw %2,%1" \
  104. : "=a" (__ret), "+m" (*__ptr) \
  105. : "r" (__new), "0" (__old) \
  106. : "memory"); \
  107. break; \
  108. } \
  109. case 4: \
  110. { \
  111. volatile u32 *__ptr = (volatile u32 *)(ptr); \
  112. asm volatile(lock "cmpxchgl %2,%1" \
  113. : "=a" (__ret), "+m" (*__ptr) \
  114. : "r" (__new), "0" (__old) \
  115. : "memory"); \
  116. break; \
  117. } \
  118. default: \
  119. __cmpxchg_wrong_size(); \
  120. } \
  121. __ret; \
  122. })
  123. #define __cmpxchg(ptr, old, new, size) \
  124. __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
  125. #define __sync_cmpxchg(ptr, old, new, size) \
  126. __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
  127. #define __cmpxchg_local(ptr, old, new, size) \
  128. __raw_cmpxchg((ptr), (old), (new), (size), "")
  129. #ifdef CONFIG_X86_CMPXCHG
  130. #define __HAVE_ARCH_CMPXCHG 1
  131. #define cmpxchg(ptr, old, new) \
  132. __cmpxchg((ptr), (old), (new), sizeof(*ptr))
  133. #define sync_cmpxchg(ptr, old, new) \
  134. __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
  135. #define cmpxchg_local(ptr, old, new) \
  136. __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
  137. #endif
  138. #ifdef CONFIG_X86_CMPXCHG64
  139. #define cmpxchg64(ptr, o, n) \
  140. ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
  141. (unsigned long long)(n)))
  142. #define cmpxchg64_local(ptr, o, n) \
  143. ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
  144. (unsigned long long)(n)))
  145. #endif
  146. static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
  147. {
  148. u64 prev;
  149. asm volatile(LOCK_PREFIX "cmpxchg8b %1"
  150. : "=A" (prev),
  151. "+m" (*ptr)
  152. : "b" ((u32)new),
  153. "c" ((u32)(new >> 32)),
  154. "0" (old)
  155. : "memory");
  156. return prev;
  157. }
  158. static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
  159. {
  160. u64 prev;
  161. asm volatile("cmpxchg8b %1"
  162. : "=A" (prev),
  163. "+m" (*ptr)
  164. : "b" ((u32)new),
  165. "c" ((u32)(new >> 32)),
  166. "0" (old)
  167. : "memory");
  168. return prev;
  169. }
  170. #ifndef CONFIG_X86_CMPXCHG
  171. /*
  172. * Building a kernel capable running on 80386. It may be necessary to
  173. * simulate the cmpxchg on the 80386 CPU. For that purpose we define
  174. * a function for each of the sizes we support.
  175. */
  176. extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
  177. extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
  178. extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
  179. static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
  180. unsigned long new, int size)
  181. {
  182. switch (size) {
  183. case 1:
  184. return cmpxchg_386_u8(ptr, old, new);
  185. case 2:
  186. return cmpxchg_386_u16(ptr, old, new);
  187. case 4:
  188. return cmpxchg_386_u32(ptr, old, new);
  189. }
  190. return old;
  191. }
  192. #define cmpxchg(ptr, o, n) \
  193. ({ \
  194. __typeof__(*(ptr)) __ret; \
  195. if (likely(boot_cpu_data.x86 > 3)) \
  196. __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \
  197. (unsigned long)(o), (unsigned long)(n), \
  198. sizeof(*(ptr))); \
  199. else \
  200. __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
  201. (unsigned long)(o), (unsigned long)(n), \
  202. sizeof(*(ptr))); \
  203. __ret; \
  204. })
  205. #define cmpxchg_local(ptr, o, n) \
  206. ({ \
  207. __typeof__(*(ptr)) __ret; \
  208. if (likely(boot_cpu_data.x86 > 3)) \
  209. __ret = (__typeof__(*(ptr)))__cmpxchg_local((ptr), \
  210. (unsigned long)(o), (unsigned long)(n), \
  211. sizeof(*(ptr))); \
  212. else \
  213. __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
  214. (unsigned long)(o), (unsigned long)(n), \
  215. sizeof(*(ptr))); \
  216. __ret; \
  217. })
  218. #endif
  219. #ifndef CONFIG_X86_CMPXCHG64
  220. /*
  221. * Building a kernel capable running on 80386 and 80486. It may be necessary
  222. * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
  223. */
  224. #define cmpxchg64(ptr, o, n) \
  225. ({ \
  226. __typeof__(*(ptr)) __ret; \
  227. __typeof__(*(ptr)) __old = (o); \
  228. __typeof__(*(ptr)) __new = (n); \
  229. alternative_io(LOCK_PREFIX_HERE \
  230. "call cmpxchg8b_emu", \
  231. "lock; cmpxchg8b (%%esi)" , \
  232. X86_FEATURE_CX8, \
  233. "=A" (__ret), \
  234. "S" ((ptr)), "0" (__old), \
  235. "b" ((unsigned int)__new), \
  236. "c" ((unsigned int)(__new>>32)) \
  237. : "memory"); \
  238. __ret; })
  239. #define cmpxchg64_local(ptr, o, n) \
  240. ({ \
  241. __typeof__(*(ptr)) __ret; \
  242. __typeof__(*(ptr)) __old = (o); \
  243. __typeof__(*(ptr)) __new = (n); \
  244. alternative_io("call cmpxchg8b_emu", \
  245. "cmpxchg8b (%%esi)" , \
  246. X86_FEATURE_CX8, \
  247. "=A" (__ret), \
  248. "S" ((ptr)), "0" (__old), \
  249. "b" ((unsigned int)__new), \
  250. "c" ((unsigned int)(__new>>32)) \
  251. : "memory"); \
  252. __ret; })
  253. #endif
  254. #endif /* _ASM_X86_CMPXCHG_32_H */