 b08ee5f7e4
			
		
	
	
	b08ee5f7e4
	
	
	
		
			
			Both the 32-bit and 64-bit cmpxchg.h header define __HAVE_ARCH_CMPXCHG and there's ifdeffery which checks it. But since both bitness define it, we can just as well move it up to the main cmpxchg header and simpify a bit of code in doing that. Signed-off-by: Borislav Petkov <bp@suse.de> Link: http://lkml.kernel.org/r/20140711104338.GB17083@pd.tnic Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
		
			
				
	
	
		
			114 lines
		
	
	
	
		
			3.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
	
		
			3.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| #ifndef _ASM_X86_CMPXCHG_32_H
 | |
| #define _ASM_X86_CMPXCHG_32_H
 | |
| 
 | |
| /*
 | |
|  * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
 | |
|  *       you need to test for the feature in boot_cpu_data.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * CMPXCHG8B only writes to the target if we had the previous
 | |
|  * value in registers, otherwise it acts as a read and gives us the
 | |
|  * "new previous" value.  That is why there is a loop.  Preloading
 | |
|  * EDX:EAX is a performance optimization: in the common case it means
 | |
|  * we need only one locked operation.
 | |
|  *
 | |
|  * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
 | |
|  * least an FPU save and/or %cr0.ts manipulation.
 | |
|  *
 | |
|  * cmpxchg8b must be used with the lock prefix here to allow the
 | |
|  * instruction to be executed atomically.  We need to have the reader
 | |
|  * side to see the coherent 64bit value.
 | |
|  */
 | |
| static inline void set_64bit(volatile u64 *ptr, u64 value)
 | |
| {
 | |
| 	u32 low  = value;
 | |
| 	u32 high = value >> 32;
 | |
| 	u64 prev = *ptr;
 | |
| 
 | |
| 	asm volatile("\n1:\t"
 | |
| 		     LOCK_PREFIX "cmpxchg8b %0\n\t"
 | |
| 		     "jnz 1b"
 | |
| 		     : "=m" (*ptr), "+A" (prev)
 | |
| 		     : "b" (low), "c" (high)
 | |
| 		     : "memory");
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_X86_CMPXCHG64
 | |
| #define cmpxchg64(ptr, o, n)						\
 | |
| 	((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
 | |
| 					 (unsigned long long)(n)))
 | |
| #define cmpxchg64_local(ptr, o, n)					\
 | |
| 	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
 | |
| 					       (unsigned long long)(n)))
 | |
| #endif
 | |
| 
 | |
| static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
 | |
| {
 | |
| 	u64 prev;
 | |
| 	asm volatile(LOCK_PREFIX "cmpxchg8b %1"
 | |
| 		     : "=A" (prev),
 | |
| 		       "+m" (*ptr)
 | |
| 		     : "b" ((u32)new),
 | |
| 		       "c" ((u32)(new >> 32)),
 | |
| 		       "0" (old)
 | |
| 		     : "memory");
 | |
| 	return prev;
 | |
| }
 | |
| 
 | |
| static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
 | |
| {
 | |
| 	u64 prev;
 | |
| 	asm volatile("cmpxchg8b %1"
 | |
| 		     : "=A" (prev),
 | |
| 		       "+m" (*ptr)
 | |
| 		     : "b" ((u32)new),
 | |
| 		       "c" ((u32)(new >> 32)),
 | |
| 		       "0" (old)
 | |
| 		     : "memory");
 | |
| 	return prev;
 | |
| }
 | |
| 
 | |
| #ifndef CONFIG_X86_CMPXCHG64
 | |
| /*
 | |
|  * Building a kernel capable running on 80386 and 80486. It may be necessary
 | |
|  * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
 | |
|  */
 | |
| 
 | |
| #define cmpxchg64(ptr, o, n)					\
 | |
| ({								\
 | |
| 	__typeof__(*(ptr)) __ret;				\
 | |
| 	__typeof__(*(ptr)) __old = (o);				\
 | |
| 	__typeof__(*(ptr)) __new = (n);				\
 | |
| 	alternative_io(LOCK_PREFIX_HERE				\
 | |
| 			"call cmpxchg8b_emu",			\
 | |
| 			"lock; cmpxchg8b (%%esi)" ,		\
 | |
| 		       X86_FEATURE_CX8,				\
 | |
| 		       "=A" (__ret),				\
 | |
| 		       "S" ((ptr)), "0" (__old),		\
 | |
| 		       "b" ((unsigned int)__new),		\
 | |
| 		       "c" ((unsigned int)(__new>>32))		\
 | |
| 		       : "memory");				\
 | |
| 	__ret; })
 | |
| 
 | |
| 
 | |
| #define cmpxchg64_local(ptr, o, n)				\
 | |
| ({								\
 | |
| 	__typeof__(*(ptr)) __ret;				\
 | |
| 	__typeof__(*(ptr)) __old = (o);				\
 | |
| 	__typeof__(*(ptr)) __new = (n);				\
 | |
| 	alternative_io("call cmpxchg8b_emu",			\
 | |
| 		       "cmpxchg8b (%%esi)" ,			\
 | |
| 		       X86_FEATURE_CX8,				\
 | |
| 		       "=A" (__ret),				\
 | |
| 		       "S" ((ptr)), "0" (__old),		\
 | |
| 		       "b" ((unsigned int)__new),		\
 | |
| 		       "c" ((unsigned int)(__new>>32))		\
 | |
| 		       : "memory");				\
 | |
| 	__ret; })
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #define system_has_cmpxchg_double() cpu_has_cx8
 | |
| 
 | |
| #endif /* _ASM_X86_CMPXCHG_32_H */
 |