cmpxchg.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #ifndef __ASM_CMPXCHG_H
  2. #define __ASM_CMPXCHG_H
  3. #include <linux/bitops.h> /* for LOCK_PREFIX */
  4. #define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
  5. struct __xchg_dummy { unsigned long a[100]; };
  6. #define __xg(x) ((struct __xchg_dummy *)(x))
  7. #ifdef CONFIG_X86_CMPXCHG64
  8. /*
  9. * The semantics of XCHGCMP8B are a bit strange, this is why
  10. * there is a loop and the loading of %%eax and %%edx has to
  11. * be inside. This inlines well in most cases, the cached
  12. * cost is around ~38 cycles. (in the future we might want
  13. * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
  14. * might have an implicit FPU-save as a cost, so it's not
  15. * clear which path to go.)
  16. *
  17. * cmpxchg8b must be used with the lock prefix here to allow
  18. * the instruction to be executed atomically, see page 3-102
  19. * of the instruction set reference 24319102.pdf. We need
  20. * the reader side to see the coherent 64bit value.
  21. */
  22. static inline void __set_64bit (unsigned long long * ptr,
  23. unsigned int low, unsigned int high)
  24. {
  25. __asm__ __volatile__ (
  26. "\n1:\t"
  27. "movl (%0), %%eax\n\t"
  28. "movl 4(%0), %%edx\n\t"
  29. "lock cmpxchg8b (%0)\n\t"
  30. "jnz 1b"
  31. : /* no outputs */
  32. : "D"(ptr),
  33. "b"(low),
  34. "c"(high)
  35. : "ax","dx","memory");
  36. }
  37. static inline void __set_64bit_constant (unsigned long long *ptr,
  38. unsigned long long value)
  39. {
  40. __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
  41. }
  42. #define ll_low(x) *(((unsigned int*)&(x))+0)
  43. #define ll_high(x) *(((unsigned int*)&(x))+1)
  44. static inline void __set_64bit_var (unsigned long long *ptr,
  45. unsigned long long value)
  46. {
  47. __set_64bit(ptr,ll_low(value), ll_high(value));
  48. }
  49. #define set_64bit(ptr,value) \
  50. (__builtin_constant_p(value) ? \
  51. __set_64bit_constant(ptr, value) : \
  52. __set_64bit_var(ptr, value) )
  53. #define _set_64bit(ptr,value) \
  54. (__builtin_constant_p(value) ? \
  55. __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
  56. __set_64bit(ptr, ll_low(value), ll_high(value)) )
  57. #endif
  58. /*
  59. * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
  60. * Note 2: xchg has side effect, so that attribute volatile is necessary,
  61. * but generally the primitive is invalid, *ptr is output argument. --ANK
  62. */
  63. static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
  64. {
  65. switch (size) {
  66. case 1:
  67. __asm__ __volatile__("xchgb %b0,%1"
  68. :"=q" (x)
  69. :"m" (*__xg(ptr)), "0" (x)
  70. :"memory");
  71. break;
  72. case 2:
  73. __asm__ __volatile__("xchgw %w0,%1"
  74. :"=r" (x)
  75. :"m" (*__xg(ptr)), "0" (x)
  76. :"memory");
  77. break;
  78. case 4:
  79. __asm__ __volatile__("xchgl %0,%1"
  80. :"=r" (x)
  81. :"m" (*__xg(ptr)), "0" (x)
  82. :"memory");
  83. break;
  84. }
  85. return x;
  86. }
  87. /*
  88. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  89. * store NEW in MEM. Return the initial value in MEM. Success is
  90. * indicated by comparing RETURN with OLD.
  91. */
  92. #ifdef CONFIG_X86_CMPXCHG
  93. #define __HAVE_ARCH_CMPXCHG 1
  94. #define cmpxchg(ptr,o,n)\
  95. ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
  96. (unsigned long)(n),sizeof(*(ptr))))
  97. #define sync_cmpxchg(ptr,o,n)\
  98. ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
  99. (unsigned long)(n),sizeof(*(ptr))))
  100. #define cmpxchg_local(ptr,o,n)\
  101. ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
  102. (unsigned long)(n),sizeof(*(ptr))))
  103. #endif
  104. static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
  105. unsigned long new, int size)
  106. {
  107. unsigned long prev;
  108. switch (size) {
  109. case 1:
  110. __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
  111. : "=a"(prev)
  112. : "q"(new), "m"(*__xg(ptr)), "0"(old)
  113. : "memory");
  114. return prev;
  115. case 2:
  116. __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
  117. : "=a"(prev)
  118. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  119. : "memory");
  120. return prev;
  121. case 4:
  122. __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
  123. : "=a"(prev)
  124. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  125. : "memory");
  126. return prev;
  127. }
  128. return old;
  129. }
  130. /*
  131. * Always use locked operations when touching memory shared with a
  132. * hypervisor, since the system may be SMP even if the guest kernel
  133. * isn't.
  134. */
  135. static inline unsigned long __sync_cmpxchg(volatile void *ptr,
  136. unsigned long old,
  137. unsigned long new, int size)
  138. {
  139. unsigned long prev;
  140. switch (size) {
  141. case 1:
  142. __asm__ __volatile__("lock; cmpxchgb %b1,%2"
  143. : "=a"(prev)
  144. : "q"(new), "m"(*__xg(ptr)), "0"(old)
  145. : "memory");
  146. return prev;
  147. case 2:
  148. __asm__ __volatile__("lock; cmpxchgw %w1,%2"
  149. : "=a"(prev)
  150. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  151. : "memory");
  152. return prev;
  153. case 4:
  154. __asm__ __volatile__("lock; cmpxchgl %1,%2"
  155. : "=a"(prev)
  156. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  157. : "memory");
  158. return prev;
  159. }
  160. return old;
  161. }
  162. static inline unsigned long __cmpxchg_local(volatile void *ptr,
  163. unsigned long old, unsigned long new, int size)
  164. {
  165. unsigned long prev;
  166. switch (size) {
  167. case 1:
  168. __asm__ __volatile__("cmpxchgb %b1,%2"
  169. : "=a"(prev)
  170. : "q"(new), "m"(*__xg(ptr)), "0"(old)
  171. : "memory");
  172. return prev;
  173. case 2:
  174. __asm__ __volatile__("cmpxchgw %w1,%2"
  175. : "=a"(prev)
  176. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  177. : "memory");
  178. return prev;
  179. case 4:
  180. __asm__ __volatile__("cmpxchgl %1,%2"
  181. : "=a"(prev)
  182. : "r"(new), "m"(*__xg(ptr)), "0"(old)
  183. : "memory");
  184. return prev;
  185. }
  186. return old;
  187. }
  188. #ifndef CONFIG_X86_CMPXCHG
  189. /*
  190. * Building a kernel capable running on 80386. It may be necessary to
  191. * simulate the cmpxchg on the 80386 CPU. For that purpose we define
  192. * a function for each of the sizes we support.
  193. */
  194. extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
  195. extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
  196. extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
  197. static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
  198. unsigned long new, int size)
  199. {
  200. switch (size) {
  201. case 1:
  202. return cmpxchg_386_u8(ptr, old, new);
  203. case 2:
  204. return cmpxchg_386_u16(ptr, old, new);
  205. case 4:
  206. return cmpxchg_386_u32(ptr, old, new);
  207. }
  208. return old;
  209. }
  210. #define cmpxchg(ptr,o,n) \
  211. ({ \
  212. __typeof__(*(ptr)) __ret; \
  213. if (likely(boot_cpu_data.x86 > 3)) \
  214. __ret = __cmpxchg((ptr), (unsigned long)(o), \
  215. (unsigned long)(n), sizeof(*(ptr))); \
  216. else \
  217. __ret = cmpxchg_386((ptr), (unsigned long)(o), \
  218. (unsigned long)(n), sizeof(*(ptr))); \
  219. __ret; \
  220. })
  221. #define cmpxchg_local(ptr,o,n) \
  222. ({ \
  223. __typeof__(*(ptr)) __ret; \
  224. if (likely(boot_cpu_data.x86 > 3)) \
  225. __ret = __cmpxchg_local((ptr), (unsigned long)(o), \
  226. (unsigned long)(n), sizeof(*(ptr))); \
  227. else \
  228. __ret = cmpxchg_386((ptr), (unsigned long)(o), \
  229. (unsigned long)(n), sizeof(*(ptr))); \
  230. __ret; \
  231. })
  232. #endif
  233. #ifdef CONFIG_X86_CMPXCHG64
  234. static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
  235. unsigned long long new)
  236. {
  237. unsigned long long prev;
  238. __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
  239. : "=A"(prev)
  240. : "b"((unsigned long)new),
  241. "c"((unsigned long)(new >> 32)),
  242. "m"(*__xg(ptr)),
  243. "0"(old)
  244. : "memory");
  245. return prev;
  246. }
  247. static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
  248. unsigned long long old, unsigned long long new)
  249. {
  250. unsigned long long prev;
  251. __asm__ __volatile__("cmpxchg8b %3"
  252. : "=A"(prev)
  253. : "b"((unsigned long)new),
  254. "c"((unsigned long)(new >> 32)),
  255. "m"(*__xg(ptr)),
  256. "0"(old)
  257. : "memory");
  258. return prev;
  259. }
  260. #define cmpxchg64(ptr,o,n)\
  261. ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
  262. (unsigned long long)(n)))
  263. #define cmpxchg64_local(ptr,o,n)\
  264. ((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
  265. (unsigned long long)(n)))
  266. #endif
  267. #endif