xref: /OK3568_Linux_fs/kernel/arch/x86/include/asm/cmpxchg.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef ASM_X86_CMPXCHG_H
3*4882a593Smuzhiyun #define ASM_X86_CMPXCHG_H
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #include <linux/compiler.h>
6*4882a593Smuzhiyun #include <asm/cpufeatures.h>
7*4882a593Smuzhiyun #include <asm/alternative.h> /* Provides LOCK_PREFIX */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun  * Non-existent functions to indicate usage errors at link time
11*4882a593Smuzhiyun  * (or compile-time if the compiler implements __compiletime_error().
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun extern void __xchg_wrong_size(void)
14*4882a593Smuzhiyun 	__compiletime_error("Bad argument size for xchg");
15*4882a593Smuzhiyun extern void __cmpxchg_wrong_size(void)
16*4882a593Smuzhiyun 	__compiletime_error("Bad argument size for cmpxchg");
17*4882a593Smuzhiyun extern void __xadd_wrong_size(void)
18*4882a593Smuzhiyun 	__compiletime_error("Bad argument size for xadd");
19*4882a593Smuzhiyun extern void __add_wrong_size(void)
20*4882a593Smuzhiyun 	__compiletime_error("Bad argument size for add");
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * Constants for operation sizes. On 32-bit, the 64-bit size it set to
24*4882a593Smuzhiyun  * -1 because sizeof will never return -1, thereby making those switch
25*4882a593Smuzhiyun  * case statements guaranteeed dead code which the compiler will
26*4882a593Smuzhiyun  * eliminate, and allowing the "missing symbol in the default case" to
27*4882a593Smuzhiyun  * indicate a usage error.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun #define __X86_CASE_B	1
30*4882a593Smuzhiyun #define __X86_CASE_W	2
31*4882a593Smuzhiyun #define __X86_CASE_L	4
32*4882a593Smuzhiyun #ifdef CONFIG_64BIT
33*4882a593Smuzhiyun #define __X86_CASE_Q	8
34*4882a593Smuzhiyun #else
35*4882a593Smuzhiyun #define	__X86_CASE_Q	-1		/* sizeof will never return -1 */
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun  * An exchange-type operation, which takes a value and a pointer, and
40*4882a593Smuzhiyun  * returns the old value.
41*4882a593Smuzhiyun  */
42*4882a593Smuzhiyun #define __xchg_op(ptr, arg, op, lock)					\
43*4882a593Smuzhiyun 	({								\
44*4882a593Smuzhiyun 	        __typeof__ (*(ptr)) __ret = (arg);			\
45*4882a593Smuzhiyun 		switch (sizeof(*(ptr))) {				\
46*4882a593Smuzhiyun 		case __X86_CASE_B:					\
47*4882a593Smuzhiyun 			asm volatile (lock #op "b %b0, %1\n"		\
48*4882a593Smuzhiyun 				      : "+q" (__ret), "+m" (*(ptr))	\
49*4882a593Smuzhiyun 				      : : "memory", "cc");		\
50*4882a593Smuzhiyun 			break;						\
51*4882a593Smuzhiyun 		case __X86_CASE_W:					\
52*4882a593Smuzhiyun 			asm volatile (lock #op "w %w0, %1\n"		\
53*4882a593Smuzhiyun 				      : "+r" (__ret), "+m" (*(ptr))	\
54*4882a593Smuzhiyun 				      : : "memory", "cc");		\
55*4882a593Smuzhiyun 			break;						\
56*4882a593Smuzhiyun 		case __X86_CASE_L:					\
57*4882a593Smuzhiyun 			asm volatile (lock #op "l %0, %1\n"		\
58*4882a593Smuzhiyun 				      : "+r" (__ret), "+m" (*(ptr))	\
59*4882a593Smuzhiyun 				      : : "memory", "cc");		\
60*4882a593Smuzhiyun 			break;						\
61*4882a593Smuzhiyun 		case __X86_CASE_Q:					\
62*4882a593Smuzhiyun 			asm volatile (lock #op "q %q0, %1\n"		\
63*4882a593Smuzhiyun 				      : "+r" (__ret), "+m" (*(ptr))	\
64*4882a593Smuzhiyun 				      : : "memory", "cc");		\
65*4882a593Smuzhiyun 			break;						\
66*4882a593Smuzhiyun 		default:						\
67*4882a593Smuzhiyun 			__ ## op ## _wrong_size();			\
68*4882a593Smuzhiyun 		}							\
69*4882a593Smuzhiyun 		__ret;							\
70*4882a593Smuzhiyun 	})
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
74*4882a593Smuzhiyun  * Since this is generally used to protect other memory information, we
75*4882a593Smuzhiyun  * use "asm volatile" and "memory" clobbers to prevent gcc from moving
76*4882a593Smuzhiyun  * information around.
77*4882a593Smuzhiyun  */
78*4882a593Smuzhiyun #define arch_xchg(ptr, v)	__xchg_op((ptr), (v), xchg, "")
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
82*4882a593Smuzhiyun  * store NEW in MEM.  Return the initial value in MEM.  Success is
83*4882a593Smuzhiyun  * indicated by comparing RETURN with OLD.
84*4882a593Smuzhiyun  */
85*4882a593Smuzhiyun #define __raw_cmpxchg(ptr, old, new, size, lock)			\
86*4882a593Smuzhiyun ({									\
87*4882a593Smuzhiyun 	__typeof__(*(ptr)) __ret;					\
88*4882a593Smuzhiyun 	__typeof__(*(ptr)) __old = (old);				\
89*4882a593Smuzhiyun 	__typeof__(*(ptr)) __new = (new);				\
90*4882a593Smuzhiyun 	switch (size) {							\
91*4882a593Smuzhiyun 	case __X86_CASE_B:						\
92*4882a593Smuzhiyun 	{								\
93*4882a593Smuzhiyun 		volatile u8 *__ptr = (volatile u8 *)(ptr);		\
94*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgb %2,%1"			\
95*4882a593Smuzhiyun 			     : "=a" (__ret), "+m" (*__ptr)		\
96*4882a593Smuzhiyun 			     : "q" (__new), "0" (__old)			\
97*4882a593Smuzhiyun 			     : "memory");				\
98*4882a593Smuzhiyun 		break;							\
99*4882a593Smuzhiyun 	}								\
100*4882a593Smuzhiyun 	case __X86_CASE_W:						\
101*4882a593Smuzhiyun 	{								\
102*4882a593Smuzhiyun 		volatile u16 *__ptr = (volatile u16 *)(ptr);		\
103*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgw %2,%1"			\
104*4882a593Smuzhiyun 			     : "=a" (__ret), "+m" (*__ptr)		\
105*4882a593Smuzhiyun 			     : "r" (__new), "0" (__old)			\
106*4882a593Smuzhiyun 			     : "memory");				\
107*4882a593Smuzhiyun 		break;							\
108*4882a593Smuzhiyun 	}								\
109*4882a593Smuzhiyun 	case __X86_CASE_L:						\
110*4882a593Smuzhiyun 	{								\
111*4882a593Smuzhiyun 		volatile u32 *__ptr = (volatile u32 *)(ptr);		\
112*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgl %2,%1"			\
113*4882a593Smuzhiyun 			     : "=a" (__ret), "+m" (*__ptr)		\
114*4882a593Smuzhiyun 			     : "r" (__new), "0" (__old)			\
115*4882a593Smuzhiyun 			     : "memory");				\
116*4882a593Smuzhiyun 		break;							\
117*4882a593Smuzhiyun 	}								\
118*4882a593Smuzhiyun 	case __X86_CASE_Q:						\
119*4882a593Smuzhiyun 	{								\
120*4882a593Smuzhiyun 		volatile u64 *__ptr = (volatile u64 *)(ptr);		\
121*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgq %2,%1"			\
122*4882a593Smuzhiyun 			     : "=a" (__ret), "+m" (*__ptr)		\
123*4882a593Smuzhiyun 			     : "r" (__new), "0" (__old)			\
124*4882a593Smuzhiyun 			     : "memory");				\
125*4882a593Smuzhiyun 		break;							\
126*4882a593Smuzhiyun 	}								\
127*4882a593Smuzhiyun 	default:							\
128*4882a593Smuzhiyun 		__cmpxchg_wrong_size();					\
129*4882a593Smuzhiyun 	}								\
130*4882a593Smuzhiyun 	__ret;								\
131*4882a593Smuzhiyun })
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun #define __cmpxchg(ptr, old, new, size)					\
134*4882a593Smuzhiyun 	__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun #define __sync_cmpxchg(ptr, old, new, size)				\
137*4882a593Smuzhiyun 	__raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #define __cmpxchg_local(ptr, old, new, size)				\
140*4882a593Smuzhiyun 	__raw_cmpxchg((ptr), (old), (new), (size), "")
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #ifdef CONFIG_X86_32
143*4882a593Smuzhiyun # include <asm/cmpxchg_32.h>
144*4882a593Smuzhiyun #else
145*4882a593Smuzhiyun # include <asm/cmpxchg_64.h>
146*4882a593Smuzhiyun #endif
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun #define arch_cmpxchg(ptr, old, new)					\
149*4882a593Smuzhiyun 	__cmpxchg(ptr, old, new, sizeof(*(ptr)))
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun #define arch_sync_cmpxchg(ptr, old, new)				\
152*4882a593Smuzhiyun 	__sync_cmpxchg(ptr, old, new, sizeof(*(ptr)))
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #define arch_cmpxchg_local(ptr, old, new)				\
155*4882a593Smuzhiyun 	__cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun #define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock)		\
159*4882a593Smuzhiyun ({									\
160*4882a593Smuzhiyun 	bool success;							\
161*4882a593Smuzhiyun 	__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold);		\
162*4882a593Smuzhiyun 	__typeof__(*(_ptr)) __old = *_old;				\
163*4882a593Smuzhiyun 	__typeof__(*(_ptr)) __new = (_new);				\
164*4882a593Smuzhiyun 	switch (size) {							\
165*4882a593Smuzhiyun 	case __X86_CASE_B:						\
166*4882a593Smuzhiyun 	{								\
167*4882a593Smuzhiyun 		volatile u8 *__ptr = (volatile u8 *)(_ptr);		\
168*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgb %[new], %[ptr]"		\
169*4882a593Smuzhiyun 			     CC_SET(z)					\
170*4882a593Smuzhiyun 			     : CC_OUT(z) (success),			\
171*4882a593Smuzhiyun 			       [ptr] "+m" (*__ptr),			\
172*4882a593Smuzhiyun 			       [old] "+a" (__old)			\
173*4882a593Smuzhiyun 			     : [new] "q" (__new)			\
174*4882a593Smuzhiyun 			     : "memory");				\
175*4882a593Smuzhiyun 		break;							\
176*4882a593Smuzhiyun 	}								\
177*4882a593Smuzhiyun 	case __X86_CASE_W:						\
178*4882a593Smuzhiyun 	{								\
179*4882a593Smuzhiyun 		volatile u16 *__ptr = (volatile u16 *)(_ptr);		\
180*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgw %[new], %[ptr]"		\
181*4882a593Smuzhiyun 			     CC_SET(z)					\
182*4882a593Smuzhiyun 			     : CC_OUT(z) (success),			\
183*4882a593Smuzhiyun 			       [ptr] "+m" (*__ptr),			\
184*4882a593Smuzhiyun 			       [old] "+a" (__old)			\
185*4882a593Smuzhiyun 			     : [new] "r" (__new)			\
186*4882a593Smuzhiyun 			     : "memory");				\
187*4882a593Smuzhiyun 		break;							\
188*4882a593Smuzhiyun 	}								\
189*4882a593Smuzhiyun 	case __X86_CASE_L:						\
190*4882a593Smuzhiyun 	{								\
191*4882a593Smuzhiyun 		volatile u32 *__ptr = (volatile u32 *)(_ptr);		\
192*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgl %[new], %[ptr]"		\
193*4882a593Smuzhiyun 			     CC_SET(z)					\
194*4882a593Smuzhiyun 			     : CC_OUT(z) (success),			\
195*4882a593Smuzhiyun 			       [ptr] "+m" (*__ptr),			\
196*4882a593Smuzhiyun 			       [old] "+a" (__old)			\
197*4882a593Smuzhiyun 			     : [new] "r" (__new)			\
198*4882a593Smuzhiyun 			     : "memory");				\
199*4882a593Smuzhiyun 		break;							\
200*4882a593Smuzhiyun 	}								\
201*4882a593Smuzhiyun 	case __X86_CASE_Q:						\
202*4882a593Smuzhiyun 	{								\
203*4882a593Smuzhiyun 		volatile u64 *__ptr = (volatile u64 *)(_ptr);		\
204*4882a593Smuzhiyun 		asm volatile(lock "cmpxchgq %[new], %[ptr]"		\
205*4882a593Smuzhiyun 			     CC_SET(z)					\
206*4882a593Smuzhiyun 			     : CC_OUT(z) (success),			\
207*4882a593Smuzhiyun 			       [ptr] "+m" (*__ptr),			\
208*4882a593Smuzhiyun 			       [old] "+a" (__old)			\
209*4882a593Smuzhiyun 			     : [new] "r" (__new)			\
210*4882a593Smuzhiyun 			     : "memory");				\
211*4882a593Smuzhiyun 		break;							\
212*4882a593Smuzhiyun 	}								\
213*4882a593Smuzhiyun 	default:							\
214*4882a593Smuzhiyun 		__cmpxchg_wrong_size();					\
215*4882a593Smuzhiyun 	}								\
216*4882a593Smuzhiyun 	if (unlikely(!success))						\
217*4882a593Smuzhiyun 		*_old = __old;						\
218*4882a593Smuzhiyun 	likely(success);						\
219*4882a593Smuzhiyun })
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun #define __try_cmpxchg(ptr, pold, new, size)				\
222*4882a593Smuzhiyun 	__raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX)
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun #define try_cmpxchg(ptr, pold, new) 					\
225*4882a593Smuzhiyun 	__try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun  * xadd() adds "inc" to "*ptr" and atomically returns the previous
229*4882a593Smuzhiyun  * value of "*ptr".
230*4882a593Smuzhiyun  *
231*4882a593Smuzhiyun  * xadd() is locked when multiple CPUs are online
232*4882a593Smuzhiyun  */
233*4882a593Smuzhiyun #define __xadd(ptr, inc, lock)	__xchg_op((ptr), (inc), xadd, lock)
234*4882a593Smuzhiyun #define xadd(ptr, inc)		__xadd((ptr), (inc), LOCK_PREFIX)
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun #define __cmpxchg_double(pfx, p1, p2, o1, o2, n1, n2)			\
237*4882a593Smuzhiyun ({									\
238*4882a593Smuzhiyun 	bool __ret;							\
239*4882a593Smuzhiyun 	__typeof__(*(p1)) __old1 = (o1), __new1 = (n1);			\
240*4882a593Smuzhiyun 	__typeof__(*(p2)) __old2 = (o2), __new2 = (n2);			\
241*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(p1)) != sizeof(long));			\
242*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long));			\
243*4882a593Smuzhiyun 	VM_BUG_ON((unsigned long)(p1) % (2 * sizeof(long)));		\
244*4882a593Smuzhiyun 	VM_BUG_ON((unsigned long)((p1) + 1) != (unsigned long)(p2));	\
245*4882a593Smuzhiyun 	asm volatile(pfx "cmpxchg%c5b %1"				\
246*4882a593Smuzhiyun 		     CC_SET(e)						\
247*4882a593Smuzhiyun 		     : CC_OUT(e) (__ret),				\
248*4882a593Smuzhiyun 		       "+m" (*(p1)), "+m" (*(p2)),			\
249*4882a593Smuzhiyun 		       "+a" (__old1), "+d" (__old2)			\
250*4882a593Smuzhiyun 		     : "i" (2 * sizeof(long)),				\
251*4882a593Smuzhiyun 		       "b" (__new1), "c" (__new2));			\
252*4882a593Smuzhiyun 	__ret;								\
253*4882a593Smuzhiyun })
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun #define arch_cmpxchg_double(p1, p2, o1, o2, n1, n2) \
256*4882a593Smuzhiyun 	__cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2)
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun #define arch_cmpxchg_double_local(p1, p2, o1, o2, n1, n2) \
259*4882a593Smuzhiyun 	__cmpxchg_double(, p1, p2, o1, o2, n1, n2)
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun #endif	/* ASM_X86_CMPXCHG_H */
262