1 #ifndef _ASM_X86_CMPXCHG_32_H 2 #define _ASM_X86_CMPXCHG_32_H 3 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 9 /* 10 * CMPXCHG8B only writes to the target if we had the previous 11 * value in registers, otherwise it acts as a read and gives us the 12 * "new previous" value. That is why there is a loop. Preloading 13 * EDX:EAX is a performance optimization: in the common case it means 14 * we need only one locked operation. 15 * 16 * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very 17 * least an FPU save and/or %cr0.ts manipulation. 18 * 19 * cmpxchg8b must be used with the lock prefix here to allow the 20 * instruction to be executed atomically. We need to have the reader 21 * side to see the coherent 64bit value. 22 */ 23 static inline void set_64bit(volatile u64 *ptr, u64 value) 24 { 25 u32 low = value; 26 u32 high = value >> 32; 27 u64 prev = *ptr; 28 29 asm volatile("\n1:\t" 30 LOCK_PREFIX "cmpxchg8b %0\n\t" 31 "jnz 1b" 32 : "=m" (*ptr), "+A" (prev) 33 : "b" (low), "c" (high) 34 : "memory"); 35 } 36 37 #ifdef CONFIG_X86_CMPXCHG64 38 #define cmpxchg64(ptr, o, n) \ 39 ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ 40 (unsigned long long)(n))) 41 #define cmpxchg64_local(ptr, o, n) \ 42 ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ 43 (unsigned long long)(n))) 44 #endif 45 46 static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new) 47 { 48 u64 prev; 49 asm volatile(LOCK_PREFIX "cmpxchg8b %1" 50 : "=A" (prev), 51 "+m" (*ptr) 52 : "b" ((u32)new), 53 "c" ((u32)(new >> 32)), 54 "0" (old) 55 : "memory"); 56 return prev; 57 } 58 59 static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new) 60 { 61 u64 prev; 62 asm volatile("cmpxchg8b %1" 63 : "=A" (prev), 64 "+m" (*ptr) 65 : "b" ((u32)new), 66 "c" ((u32)(new >> 32)), 67 "0" (old) 68 : "memory"); 69 return prev; 70 } 71 72 #ifndef CONFIG_X86_CMPXCHG64 73 /* 74 * Building a kernel capable running on 80386 and 80486. It may be necessary 75 * to simulate the cmpxchg8b on the 80386 and 80486 CPU. 76 */ 77 78 #define cmpxchg64(ptr, o, n) \ 79 ({ \ 80 __typeof__(*(ptr)) __ret; \ 81 __typeof__(*(ptr)) __old = (o); \ 82 __typeof__(*(ptr)) __new = (n); \ 83 alternative_io(LOCK_PREFIX_HERE \ 84 "call cmpxchg8b_emu", \ 85 "lock; cmpxchg8b (%%esi)" , \ 86 X86_FEATURE_CX8, \ 87 "=A" (__ret), \ 88 "S" ((ptr)), "0" (__old), \ 89 "b" ((unsigned int)__new), \ 90 "c" ((unsigned int)(__new>>32)) \ 91 : "memory"); \ 92 __ret; }) 93 94 95 #define cmpxchg64_local(ptr, o, n) \ 96 ({ \ 97 __typeof__(*(ptr)) __ret; \ 98 __typeof__(*(ptr)) __old = (o); \ 99 __typeof__(*(ptr)) __new = (n); \ 100 alternative_io("call cmpxchg8b_emu", \ 101 "cmpxchg8b (%%esi)" , \ 102 X86_FEATURE_CX8, \ 103 "=A" (__ret), \ 104 "S" ((ptr)), "0" (__old), \ 105 "b" ((unsigned int)__new), \ 106 "c" ((unsigned int)(__new>>32)) \ 107 : "memory"); \ 108 __ret; }) 109 110 #endif 111 112 #define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX8) 113 114 #endif /* _ASM_X86_CMPXCHG_32_H */ 115