1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef TOOLS_ASM_X86_CMPXCHG_H
3 #define TOOLS_ASM_X86_CMPXCHG_H
4 
5 #include <linux/compiler.h>
6 
7 /*
8  * Non-existant functions to indicate usage errors at link time
9  * (or compile-time if the compiler implements __compiletime_error().
10  */
11 extern void __cmpxchg_wrong_size(void)
12 	__compiletime_error("Bad argument size for cmpxchg");
13 
14 /*
15  * Constants for operation sizes. On 32-bit, the 64-bit size it set to
16  * -1 because sizeof will never return -1, thereby making those switch
17  * case statements guaranteeed dead code which the compiler will
18  * eliminate, and allowing the "missing symbol in the default case" to
19  * indicate a usage error.
20  */
21 #define __X86_CASE_B	1
22 #define __X86_CASE_W	2
23 #define __X86_CASE_L	4
24 #ifdef __x86_64__
25 #define __X86_CASE_Q	8
26 #else
27 #define	__X86_CASE_Q	-1		/* sizeof will never return -1 */
28 #endif
29 
30 /*
31  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
32  * store NEW in MEM.  Return the initial value in MEM.  Success is
33  * indicated by comparing RETURN with OLD.
34  */
35 #define __raw_cmpxchg(ptr, old, new, size, lock)			\
36 ({									\
37 	__typeof__(*(ptr)) __ret;					\
38 	__typeof__(*(ptr)) __old = (old);				\
39 	__typeof__(*(ptr)) __new = (new);				\
40 	switch (size) {							\
41 	case __X86_CASE_B:						\
42 	{								\
43 		volatile u8 *__ptr = (volatile u8 *)(ptr);		\
44 		asm volatile(lock "cmpxchgb %2,%1"			\
45 			     : "=a" (__ret), "+m" (*__ptr)		\
46 			     : "q" (__new), "0" (__old)			\
47 			     : "memory");				\
48 		break;							\
49 	}								\
50 	case __X86_CASE_W:						\
51 	{								\
52 		volatile u16 *__ptr = (volatile u16 *)(ptr);		\
53 		asm volatile(lock "cmpxchgw %2,%1"			\
54 			     : "=a" (__ret), "+m" (*__ptr)		\
55 			     : "r" (__new), "0" (__old)			\
56 			     : "memory");				\
57 		break;							\
58 	}								\
59 	case __X86_CASE_L:						\
60 	{								\
61 		volatile u32 *__ptr = (volatile u32 *)(ptr);		\
62 		asm volatile(lock "cmpxchgl %2,%1"			\
63 			     : "=a" (__ret), "+m" (*__ptr)		\
64 			     : "r" (__new), "0" (__old)			\
65 			     : "memory");				\
66 		break;							\
67 	}								\
68 	case __X86_CASE_Q:						\
69 	{								\
70 		volatile u64 *__ptr = (volatile u64 *)(ptr);		\
71 		asm volatile(lock "cmpxchgq %2,%1"			\
72 			     : "=a" (__ret), "+m" (*__ptr)		\
73 			     : "r" (__new), "0" (__old)			\
74 			     : "memory");				\
75 		break;							\
76 	}								\
77 	default:							\
78 		__cmpxchg_wrong_size();					\
79 	}								\
80 	__ret;								\
81 })
82 
83 #define __cmpxchg(ptr, old, new, size)					\
84 	__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
85 
86 #define cmpxchg(ptr, old, new)						\
87 	__cmpxchg(ptr, old, new, sizeof(*(ptr)))
88 
89 
90 #endif	/* TOOLS_ASM_X86_CMPXCHG_H */
91