xref: /linux/tools/arch/x86/include/asm/cmpxchg.h (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
23337e682SArnaldo Carvalho de Melo #ifndef TOOLS_ASM_X86_CMPXCHG_H
33337e682SArnaldo Carvalho de Melo #define TOOLS_ASM_X86_CMPXCHG_H
43337e682SArnaldo Carvalho de Melo 
53337e682SArnaldo Carvalho de Melo #include <linux/compiler.h>
63337e682SArnaldo Carvalho de Melo 
73337e682SArnaldo Carvalho de Melo /*
83337e682SArnaldo Carvalho de Melo  * Non-existant functions to indicate usage errors at link time
93337e682SArnaldo Carvalho de Melo  * (or compile-time if the compiler implements __compiletime_error().
103337e682SArnaldo Carvalho de Melo  */
113337e682SArnaldo Carvalho de Melo extern void __cmpxchg_wrong_size(void)
123337e682SArnaldo Carvalho de Melo 	__compiletime_error("Bad argument size for cmpxchg");
133337e682SArnaldo Carvalho de Melo 
143337e682SArnaldo Carvalho de Melo /*
153337e682SArnaldo Carvalho de Melo  * Constants for operation sizes. On 32-bit, the 64-bit size it set to
163337e682SArnaldo Carvalho de Melo  * -1 because sizeof will never return -1, thereby making those switch
173337e682SArnaldo Carvalho de Melo  * case statements guaranteeed dead code which the compiler will
183337e682SArnaldo Carvalho de Melo  * eliminate, and allowing the "missing symbol in the default case" to
193337e682SArnaldo Carvalho de Melo  * indicate a usage error.
203337e682SArnaldo Carvalho de Melo  */
213337e682SArnaldo Carvalho de Melo #define __X86_CASE_B	1
223337e682SArnaldo Carvalho de Melo #define __X86_CASE_W	2
233337e682SArnaldo Carvalho de Melo #define __X86_CASE_L	4
243337e682SArnaldo Carvalho de Melo #ifdef __x86_64__
253337e682SArnaldo Carvalho de Melo #define __X86_CASE_Q	8
263337e682SArnaldo Carvalho de Melo #else
273337e682SArnaldo Carvalho de Melo #define	__X86_CASE_Q	-1		/* sizeof will never return -1 */
283337e682SArnaldo Carvalho de Melo #endif
293337e682SArnaldo Carvalho de Melo 
303337e682SArnaldo Carvalho de Melo /*
313337e682SArnaldo Carvalho de Melo  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
323337e682SArnaldo Carvalho de Melo  * store NEW in MEM.  Return the initial value in MEM.  Success is
333337e682SArnaldo Carvalho de Melo  * indicated by comparing RETURN with OLD.
343337e682SArnaldo Carvalho de Melo  */
353337e682SArnaldo Carvalho de Melo #define __raw_cmpxchg(ptr, old, new, size, lock)			\
363337e682SArnaldo Carvalho de Melo ({									\
373337e682SArnaldo Carvalho de Melo 	__typeof__(*(ptr)) __ret;					\
383337e682SArnaldo Carvalho de Melo 	__typeof__(*(ptr)) __old = (old);				\
393337e682SArnaldo Carvalho de Melo 	__typeof__(*(ptr)) __new = (new);				\
403337e682SArnaldo Carvalho de Melo 	switch (size) {							\
413337e682SArnaldo Carvalho de Melo 	case __X86_CASE_B:						\
423337e682SArnaldo Carvalho de Melo 	{								\
433337e682SArnaldo Carvalho de Melo 		volatile u8 *__ptr = (volatile u8 *)(ptr);		\
443337e682SArnaldo Carvalho de Melo 		asm volatile(lock "cmpxchgb %2,%1"			\
453337e682SArnaldo Carvalho de Melo 			     : "=a" (__ret), "+m" (*__ptr)		\
463337e682SArnaldo Carvalho de Melo 			     : "q" (__new), "0" (__old)			\
473337e682SArnaldo Carvalho de Melo 			     : "memory");				\
483337e682SArnaldo Carvalho de Melo 		break;							\
493337e682SArnaldo Carvalho de Melo 	}								\
503337e682SArnaldo Carvalho de Melo 	case __X86_CASE_W:						\
513337e682SArnaldo Carvalho de Melo 	{								\
523337e682SArnaldo Carvalho de Melo 		volatile u16 *__ptr = (volatile u16 *)(ptr);		\
533337e682SArnaldo Carvalho de Melo 		asm volatile(lock "cmpxchgw %2,%1"			\
543337e682SArnaldo Carvalho de Melo 			     : "=a" (__ret), "+m" (*__ptr)		\
553337e682SArnaldo Carvalho de Melo 			     : "r" (__new), "0" (__old)			\
563337e682SArnaldo Carvalho de Melo 			     : "memory");				\
573337e682SArnaldo Carvalho de Melo 		break;							\
583337e682SArnaldo Carvalho de Melo 	}								\
593337e682SArnaldo Carvalho de Melo 	case __X86_CASE_L:						\
603337e682SArnaldo Carvalho de Melo 	{								\
613337e682SArnaldo Carvalho de Melo 		volatile u32 *__ptr = (volatile u32 *)(ptr);		\
623337e682SArnaldo Carvalho de Melo 		asm volatile(lock "cmpxchgl %2,%1"			\
633337e682SArnaldo Carvalho de Melo 			     : "=a" (__ret), "+m" (*__ptr)		\
643337e682SArnaldo Carvalho de Melo 			     : "r" (__new), "0" (__old)			\
653337e682SArnaldo Carvalho de Melo 			     : "memory");				\
663337e682SArnaldo Carvalho de Melo 		break;							\
673337e682SArnaldo Carvalho de Melo 	}								\
683337e682SArnaldo Carvalho de Melo 	case __X86_CASE_Q:						\
693337e682SArnaldo Carvalho de Melo 	{								\
703337e682SArnaldo Carvalho de Melo 		volatile u64 *__ptr = (volatile u64 *)(ptr);		\
713337e682SArnaldo Carvalho de Melo 		asm volatile(lock "cmpxchgq %2,%1"			\
723337e682SArnaldo Carvalho de Melo 			     : "=a" (__ret), "+m" (*__ptr)		\
733337e682SArnaldo Carvalho de Melo 			     : "r" (__new), "0" (__old)			\
743337e682SArnaldo Carvalho de Melo 			     : "memory");				\
753337e682SArnaldo Carvalho de Melo 		break;							\
763337e682SArnaldo Carvalho de Melo 	}								\
773337e682SArnaldo Carvalho de Melo 	default:							\
783337e682SArnaldo Carvalho de Melo 		__cmpxchg_wrong_size();					\
793337e682SArnaldo Carvalho de Melo 	}								\
803337e682SArnaldo Carvalho de Melo 	__ret;								\
813337e682SArnaldo Carvalho de Melo })
823337e682SArnaldo Carvalho de Melo 
833337e682SArnaldo Carvalho de Melo #define __cmpxchg(ptr, old, new, size)					\
843337e682SArnaldo Carvalho de Melo 	__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
853337e682SArnaldo Carvalho de Melo 
863337e682SArnaldo Carvalho de Melo #define cmpxchg(ptr, old, new)						\
873337e682SArnaldo Carvalho de Melo 	__cmpxchg(ptr, old, new, sizeof(*(ptr)))
883337e682SArnaldo Carvalho de Melo 
893337e682SArnaldo Carvalho de Melo 
903337e682SArnaldo Carvalho de Melo #endif	/* TOOLS_ASM_X86_CMPXCHG_H */
91