Path: blob/master/arch/x86/include/asm/cmpxchg_32.h
10821 views
#ifndef _ASM_X86_CMPXCHG_32_H1#define _ASM_X86_CMPXCHG_32_H23#include <linux/bitops.h> /* for LOCK_PREFIX */45/*6* Note: if you use set64_bit(), __cmpxchg64(), or their variants, you7* you need to test for the feature in boot_cpu_data.8*/910extern void __xchg_wrong_size(void);1112/*13* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.14* Since this is generally used to protect other memory information, we15* use "asm volatile" and "memory" clobbers to prevent gcc from moving16* information around.17*/18#define __xchg(x, ptr, size) \19({ \20__typeof(*(ptr)) __x = (x); \21switch (size) { \22case 1: \23{ \24volatile u8 *__ptr = (volatile u8 *)(ptr); \25asm volatile("xchgb %0,%1" \26: "=q" (__x), "+m" (*__ptr) \27: "0" (__x) \28: "memory"); \29break; \30} \31case 2: \32{ \33volatile u16 *__ptr = (volatile u16 *)(ptr); \34asm volatile("xchgw %0,%1" \35: "=r" (__x), "+m" (*__ptr) \36: "0" (__x) \37: "memory"); \38break; \39} \40case 4: \41{ \42volatile u32 *__ptr = (volatile u32 *)(ptr); \43asm volatile("xchgl %0,%1" \44: "=r" (__x), "+m" (*__ptr) \45: "0" (__x) \46: "memory"); \47break; \48} \49default: \50__xchg_wrong_size(); \51} \52__x; \53})5455#define xchg(ptr, v) \56__xchg((v), (ptr), sizeof(*ptr))5758/*59* CMPXCHG8B only writes to the target if we had the previous60* value in registers, otherwise it acts as a read and gives us the61* "new previous" value. That is why there is a loop. Preloading62* EDX:EAX is a performance optimization: in the common case it means63* we need only one locked operation.64*65* A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very66* least an FPU save and/or %cr0.ts manipulation.67*68* cmpxchg8b must be used with the lock prefix here to allow the69* instruction to be executed atomically. We need to have the reader70* side to see the coherent 64bit value.71*/72static inline void set_64bit(volatile u64 *ptr, u64 value)73{74u32 low = value;75u32 high = value >> 32;76u64 prev = *ptr;7778asm volatile("\n1:\t"79LOCK_PREFIX "cmpxchg8b %0\n\t"80"jnz 1b"81: "=m" (*ptr), "+A" (prev)82: "b" (low), "c" (high)83: "memory");84}8586extern void __cmpxchg_wrong_size(void);8788/*89* Atomic compare and exchange. Compare OLD with MEM, if identical,90* store NEW in MEM. Return the initial value in MEM. Success is91* indicated by comparing RETURN with OLD.92*/93#define __raw_cmpxchg(ptr, old, new, size, lock) \94({ \95__typeof__(*(ptr)) __ret; \96__typeof__(*(ptr)) __old = (old); \97__typeof__(*(ptr)) __new = (new); \98switch (size) { \99case 1: \100{ \101volatile u8 *__ptr = (volatile u8 *)(ptr); \102asm volatile(lock "cmpxchgb %2,%1" \103: "=a" (__ret), "+m" (*__ptr) \104: "q" (__new), "0" (__old) \105: "memory"); \106break; \107} \108case 2: \109{ \110volatile u16 *__ptr = (volatile u16 *)(ptr); \111asm volatile(lock "cmpxchgw %2,%1" \112: "=a" (__ret), "+m" (*__ptr) \113: "r" (__new), "0" (__old) \114: "memory"); \115break; \116} \117case 4: \118{ \119volatile u32 *__ptr = (volatile u32 *)(ptr); \120asm volatile(lock "cmpxchgl %2,%1" \121: "=a" (__ret), "+m" (*__ptr) \122: "r" (__new), "0" (__old) \123: "memory"); \124break; \125} \126default: \127__cmpxchg_wrong_size(); \128} \129__ret; \130})131132#define __cmpxchg(ptr, old, new, size) \133__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)134135#define __sync_cmpxchg(ptr, old, new, size) \136__raw_cmpxchg((ptr), (old), (new), (size), "lock; ")137138#define __cmpxchg_local(ptr, old, new, size) \139__raw_cmpxchg((ptr), (old), (new), (size), "")140141#ifdef CONFIG_X86_CMPXCHG142#define __HAVE_ARCH_CMPXCHG 1143144#define cmpxchg(ptr, old, new) \145__cmpxchg((ptr), (old), (new), sizeof(*ptr))146147#define sync_cmpxchg(ptr, old, new) \148__sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))149150#define cmpxchg_local(ptr, old, new) \151__cmpxchg_local((ptr), (old), (new), sizeof(*ptr))152#endif153154#ifdef CONFIG_X86_CMPXCHG64155#define cmpxchg64(ptr, o, n) \156((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \157(unsigned long long)(n)))158#define cmpxchg64_local(ptr, o, n) \159((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \160(unsigned long long)(n)))161#endif162163static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)164{165u64 prev;166asm volatile(LOCK_PREFIX "cmpxchg8b %1"167: "=A" (prev),168"+m" (*ptr)169: "b" ((u32)new),170"c" ((u32)(new >> 32)),171"0" (old)172: "memory");173return prev;174}175176static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)177{178u64 prev;179asm volatile("cmpxchg8b %1"180: "=A" (prev),181"+m" (*ptr)182: "b" ((u32)new),183"c" ((u32)(new >> 32)),184"0" (old)185: "memory");186return prev;187}188189#ifndef CONFIG_X86_CMPXCHG190/*191* Building a kernel capable running on 80386. It may be necessary to192* simulate the cmpxchg on the 80386 CPU. For that purpose we define193* a function for each of the sizes we support.194*/195196extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);197extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);198extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);199200static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,201unsigned long new, int size)202{203switch (size) {204case 1:205return cmpxchg_386_u8(ptr, old, new);206case 2:207return cmpxchg_386_u16(ptr, old, new);208case 4:209return cmpxchg_386_u32(ptr, old, new);210}211return old;212}213214#define cmpxchg(ptr, o, n) \215({ \216__typeof__(*(ptr)) __ret; \217if (likely(boot_cpu_data.x86 > 3)) \218__ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \219(unsigned long)(o), (unsigned long)(n), \220sizeof(*(ptr))); \221else \222__ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \223(unsigned long)(o), (unsigned long)(n), \224sizeof(*(ptr))); \225__ret; \226})227#define cmpxchg_local(ptr, o, n) \228({ \229__typeof__(*(ptr)) __ret; \230if (likely(boot_cpu_data.x86 > 3)) \231__ret = (__typeof__(*(ptr)))__cmpxchg_local((ptr), \232(unsigned long)(o), (unsigned long)(n), \233sizeof(*(ptr))); \234else \235__ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \236(unsigned long)(o), (unsigned long)(n), \237sizeof(*(ptr))); \238__ret; \239})240#endif241242#ifndef CONFIG_X86_CMPXCHG64243/*244* Building a kernel capable running on 80386 and 80486. It may be necessary245* to simulate the cmpxchg8b on the 80386 and 80486 CPU.246*/247248#define cmpxchg64(ptr, o, n) \249({ \250__typeof__(*(ptr)) __ret; \251__typeof__(*(ptr)) __old = (o); \252__typeof__(*(ptr)) __new = (n); \253alternative_io(LOCK_PREFIX_HERE \254"call cmpxchg8b_emu", \255"lock; cmpxchg8b (%%esi)" , \256X86_FEATURE_CX8, \257"=A" (__ret), \258"S" ((ptr)), "0" (__old), \259"b" ((unsigned int)__new), \260"c" ((unsigned int)(__new>>32)) \261: "memory"); \262__ret; })263264265#define cmpxchg64_local(ptr, o, n) \266({ \267__typeof__(*(ptr)) __ret; \268__typeof__(*(ptr)) __old = (o); \269__typeof__(*(ptr)) __new = (n); \270alternative_io("call cmpxchg8b_emu", \271"cmpxchg8b (%%esi)" , \272X86_FEATURE_CX8, \273"=A" (__ret), \274"S" ((ptr)), "0" (__old), \275"b" ((unsigned int)__new), \276"c" ((unsigned int)(__new>>32)) \277: "memory"); \278__ret; })279280#endif281282#endif /* _ASM_X86_CMPXCHG_32_H */283284285