xref: /OK3568_Linux_fs/kernel/arch/sparc/include/asm/cmpxchg_64.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /* 64-bit atomic xchg() and cmpxchg() definitions.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 1996, 1997, 2000 David S. Miller (davem@redhat.com)
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #ifndef __ARCH_SPARC64_CMPXCHG__
8*4882a593Smuzhiyun #define __ARCH_SPARC64_CMPXCHG__
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun static inline unsigned long
__cmpxchg_u32(volatile int * m,int old,int new)11*4882a593Smuzhiyun __cmpxchg_u32(volatile int *m, int old, int new)
12*4882a593Smuzhiyun {
13*4882a593Smuzhiyun 	__asm__ __volatile__("cas [%2], %3, %0"
14*4882a593Smuzhiyun 			     : "=&r" (new)
15*4882a593Smuzhiyun 			     : "0" (new), "r" (m), "r" (old)
16*4882a593Smuzhiyun 			     : "memory");
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 	return new;
19*4882a593Smuzhiyun }
20*4882a593Smuzhiyun 
xchg32(__volatile__ unsigned int * m,unsigned int val)21*4882a593Smuzhiyun static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	unsigned long tmp1, tmp2;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	__asm__ __volatile__(
26*4882a593Smuzhiyun "	mov		%0, %1\n"
27*4882a593Smuzhiyun "1:	lduw		[%4], %2\n"
28*4882a593Smuzhiyun "	cas		[%4], %2, %0\n"
29*4882a593Smuzhiyun "	cmp		%2, %0\n"
30*4882a593Smuzhiyun "	bne,a,pn	%%icc, 1b\n"
31*4882a593Smuzhiyun "	 mov		%1, %0\n"
32*4882a593Smuzhiyun 	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
33*4882a593Smuzhiyun 	: "0" (val), "r" (m)
34*4882a593Smuzhiyun 	: "cc", "memory");
35*4882a593Smuzhiyun 	return val;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
xchg64(__volatile__ unsigned long * m,unsigned long val)38*4882a593Smuzhiyun static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	unsigned long tmp1, tmp2;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	__asm__ __volatile__(
43*4882a593Smuzhiyun "	mov		%0, %1\n"
44*4882a593Smuzhiyun "1:	ldx		[%4], %2\n"
45*4882a593Smuzhiyun "	casx		[%4], %2, %0\n"
46*4882a593Smuzhiyun "	cmp		%2, %0\n"
47*4882a593Smuzhiyun "	bne,a,pn	%%xcc, 1b\n"
48*4882a593Smuzhiyun "	 mov		%1, %0\n"
49*4882a593Smuzhiyun 	: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
50*4882a593Smuzhiyun 	: "0" (val), "r" (m)
51*4882a593Smuzhiyun 	: "cc", "memory");
52*4882a593Smuzhiyun 	return val;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define xchg(ptr,x)							\
56*4882a593Smuzhiyun ({	__typeof__(*(ptr)) __ret;					\
57*4882a593Smuzhiyun 	__ret = (__typeof__(*(ptr)))					\
58*4882a593Smuzhiyun 		__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)));	\
59*4882a593Smuzhiyun 	__ret;								\
60*4882a593Smuzhiyun })
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun void __xchg_called_with_bad_pointer(void);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun  * Use 4 byte cas instruction to achieve 2 byte xchg. Main logic
66*4882a593Smuzhiyun  * here is to get the bit shift of the byte we are interested in.
67*4882a593Smuzhiyun  * The XOR is handy for reversing the bits for big-endian byte order.
68*4882a593Smuzhiyun  */
69*4882a593Smuzhiyun static inline unsigned long
xchg16(__volatile__ unsigned short * m,unsigned short val)70*4882a593Smuzhiyun xchg16(__volatile__ unsigned short *m, unsigned short val)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	unsigned long maddr = (unsigned long)m;
73*4882a593Smuzhiyun 	int bit_shift = (((unsigned long)m & 2) ^ 2) << 3;
74*4882a593Smuzhiyun 	unsigned int mask = 0xffff << bit_shift;
75*4882a593Smuzhiyun 	unsigned int *ptr = (unsigned int  *) (maddr & ~2);
76*4882a593Smuzhiyun 	unsigned int old32, new32, load32;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* Read the old value */
79*4882a593Smuzhiyun 	load32 = *ptr;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	do {
82*4882a593Smuzhiyun 		old32 = load32;
83*4882a593Smuzhiyun 		new32 = (load32 & (~mask)) | val << bit_shift;
84*4882a593Smuzhiyun 		load32 = __cmpxchg_u32(ptr, old32, new32);
85*4882a593Smuzhiyun 	} while (load32 != old32);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	return (load32 & mask) >> bit_shift;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
__xchg(unsigned long x,__volatile__ void * ptr,int size)90*4882a593Smuzhiyun static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
91*4882a593Smuzhiyun 				       int size)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	switch (size) {
94*4882a593Smuzhiyun 	case 2:
95*4882a593Smuzhiyun 		return xchg16(ptr, x);
96*4882a593Smuzhiyun 	case 4:
97*4882a593Smuzhiyun 		return xchg32(ptr, x);
98*4882a593Smuzhiyun 	case 8:
99*4882a593Smuzhiyun 		return xchg64(ptr, x);
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 	__xchg_called_with_bad_pointer();
102*4882a593Smuzhiyun 	return x;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
107*4882a593Smuzhiyun  * store NEW in MEM.  Return the initial value in MEM.  Success is
108*4882a593Smuzhiyun  * indicated by comparing RETURN with OLD.
109*4882a593Smuzhiyun  */
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun #include <asm-generic/cmpxchg-local.h>
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static inline unsigned long
__cmpxchg_u64(volatile long * m,unsigned long old,unsigned long new)115*4882a593Smuzhiyun __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	__asm__ __volatile__("casx [%2], %3, %0"
118*4882a593Smuzhiyun 			     : "=&r" (new)
119*4882a593Smuzhiyun 			     : "0" (new), "r" (m), "r" (old)
120*4882a593Smuzhiyun 			     : "memory");
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return new;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * Use 4 byte cas instruction to achieve 1 byte cmpxchg. Main logic
127*4882a593Smuzhiyun  * here is to get the bit shift of the byte we are interested in.
128*4882a593Smuzhiyun  * The XOR is handy for reversing the bits for big-endian byte order
129*4882a593Smuzhiyun  */
130*4882a593Smuzhiyun static inline unsigned long
__cmpxchg_u8(volatile unsigned char * m,unsigned char old,unsigned char new)131*4882a593Smuzhiyun __cmpxchg_u8(volatile unsigned char *m, unsigned char old, unsigned char new)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	unsigned long maddr = (unsigned long)m;
134*4882a593Smuzhiyun 	int bit_shift = (((unsigned long)m & 3) ^ 3) << 3;
135*4882a593Smuzhiyun 	unsigned int mask = 0xff << bit_shift;
136*4882a593Smuzhiyun 	unsigned int *ptr = (unsigned int *) (maddr & ~3);
137*4882a593Smuzhiyun 	unsigned int old32, new32, load;
138*4882a593Smuzhiyun 	unsigned int load32 = *ptr;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	do {
141*4882a593Smuzhiyun 		new32 = (load32 & ~mask) | (new << bit_shift);
142*4882a593Smuzhiyun 		old32 = (load32 & ~mask) | (old << bit_shift);
143*4882a593Smuzhiyun 		load32 = __cmpxchg_u32(ptr, old32, new32);
144*4882a593Smuzhiyun 		if (load32 == old32)
145*4882a593Smuzhiyun 			return old;
146*4882a593Smuzhiyun 		load = (load32 & mask) >> bit_shift;
147*4882a593Smuzhiyun 	} while (load == old);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return load;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun /* This function doesn't exist, so you'll get a linker error
153*4882a593Smuzhiyun    if something tries to do an invalid cmpxchg().  */
154*4882a593Smuzhiyun void __cmpxchg_called_with_bad_pointer(void);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun static inline unsigned long
__cmpxchg(volatile void * ptr,unsigned long old,unsigned long new,int size)157*4882a593Smuzhiyun __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	switch (size) {
160*4882a593Smuzhiyun 		case 1:
161*4882a593Smuzhiyun 			return __cmpxchg_u8(ptr, old, new);
162*4882a593Smuzhiyun 		case 4:
163*4882a593Smuzhiyun 			return __cmpxchg_u32(ptr, old, new);
164*4882a593Smuzhiyun 		case 8:
165*4882a593Smuzhiyun 			return __cmpxchg_u64(ptr, old, new);
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 	__cmpxchg_called_with_bad_pointer();
168*4882a593Smuzhiyun 	return old;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun #define cmpxchg(ptr,o,n)						 \
172*4882a593Smuzhiyun   ({									 \
173*4882a593Smuzhiyun      __typeof__(*(ptr)) _o_ = (o);					 \
174*4882a593Smuzhiyun      __typeof__(*(ptr)) _n_ = (n);					 \
175*4882a593Smuzhiyun      (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
176*4882a593Smuzhiyun 				    (unsigned long)_n_, sizeof(*(ptr))); \
177*4882a593Smuzhiyun   })
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun  * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
181*4882a593Smuzhiyun  * them available.
182*4882a593Smuzhiyun  */
183*4882a593Smuzhiyun 
__cmpxchg_local(volatile void * ptr,unsigned long old,unsigned long new,int size)184*4882a593Smuzhiyun static inline unsigned long __cmpxchg_local(volatile void *ptr,
185*4882a593Smuzhiyun 				      unsigned long old,
186*4882a593Smuzhiyun 				      unsigned long new, int size)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	switch (size) {
189*4882a593Smuzhiyun 	case 4:
190*4882a593Smuzhiyun 	case 8:	return __cmpxchg(ptr, old, new, size);
191*4882a593Smuzhiyun 	default:
192*4882a593Smuzhiyun 		return __cmpxchg_local_generic(ptr, old, new, size);
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return old;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun #define cmpxchg_local(ptr, o, n)				  	\
199*4882a593Smuzhiyun 	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
200*4882a593Smuzhiyun 			(unsigned long)(n), sizeof(*(ptr))))
201*4882a593Smuzhiyun #define cmpxchg64_local(ptr, o, n)					\
202*4882a593Smuzhiyun   ({									\
203*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
204*4882a593Smuzhiyun 	cmpxchg_local((ptr), (o), (n));					\
205*4882a593Smuzhiyun   })
206*4882a593Smuzhiyun #define cmpxchg64(ptr, o, n)	cmpxchg64_local((ptr), (o), (n))
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun #endif /* __ARCH_SPARC64_CMPXCHG__ */
209