xref: /OK3568_Linux_fs/kernel/arch/powerpc/include/asm/cmpxchg.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef _ASM_POWERPC_CMPXCHG_H_
3*4882a593Smuzhiyun #define _ASM_POWERPC_CMPXCHG_H_
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #ifdef __KERNEL__
6*4882a593Smuzhiyun #include <linux/compiler.h>
7*4882a593Smuzhiyun #include <asm/synch.h>
8*4882a593Smuzhiyun #include <linux/bug.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #ifdef __BIG_ENDIAN
11*4882a593Smuzhiyun #define BITOFF_CAL(size, off)	((sizeof(u32) - size - off) * BITS_PER_BYTE)
12*4882a593Smuzhiyun #else
13*4882a593Smuzhiyun #define BITOFF_CAL(size, off)	(off * BITS_PER_BYTE)
14*4882a593Smuzhiyun #endif
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define XCHG_GEN(type, sfx, cl)				\
17*4882a593Smuzhiyun static inline u32 __xchg_##type##sfx(volatile void *p, u32 val)	\
18*4882a593Smuzhiyun {								\
19*4882a593Smuzhiyun 	unsigned int prev, prev_mask, tmp, bitoff, off;		\
20*4882a593Smuzhiyun 								\
21*4882a593Smuzhiyun 	off = (unsigned long)p % sizeof(u32);			\
22*4882a593Smuzhiyun 	bitoff = BITOFF_CAL(sizeof(type), off);			\
23*4882a593Smuzhiyun 	p -= off;						\
24*4882a593Smuzhiyun 	val <<= bitoff;						\
25*4882a593Smuzhiyun 	prev_mask = (u32)(type)-1 << bitoff;			\
26*4882a593Smuzhiyun 								\
27*4882a593Smuzhiyun 	__asm__ __volatile__(					\
28*4882a593Smuzhiyun "1:	lwarx   %0,0,%3\n"					\
29*4882a593Smuzhiyun "	andc	%1,%0,%5\n"					\
30*4882a593Smuzhiyun "	or	%1,%1,%4\n"					\
31*4882a593Smuzhiyun "	stwcx.	%1,0,%3\n"					\
32*4882a593Smuzhiyun "	bne-	1b\n"						\
33*4882a593Smuzhiyun 	: "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)		\
34*4882a593Smuzhiyun 	: "r" (p), "r" (val), "r" (prev_mask)			\
35*4882a593Smuzhiyun 	: "cc", cl);						\
36*4882a593Smuzhiyun 								\
37*4882a593Smuzhiyun 	return prev >> bitoff;					\
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define CMPXCHG_GEN(type, sfx, br, br2, cl)			\
41*4882a593Smuzhiyun static inline							\
42*4882a593Smuzhiyun u32 __cmpxchg_##type##sfx(volatile void *p, u32 old, u32 new)	\
43*4882a593Smuzhiyun {								\
44*4882a593Smuzhiyun 	unsigned int prev, prev_mask, tmp, bitoff, off;		\
45*4882a593Smuzhiyun 								\
46*4882a593Smuzhiyun 	off = (unsigned long)p % sizeof(u32);			\
47*4882a593Smuzhiyun 	bitoff = BITOFF_CAL(sizeof(type), off);			\
48*4882a593Smuzhiyun 	p -= off;						\
49*4882a593Smuzhiyun 	old <<= bitoff;						\
50*4882a593Smuzhiyun 	new <<= bitoff;						\
51*4882a593Smuzhiyun 	prev_mask = (u32)(type)-1 << bitoff;			\
52*4882a593Smuzhiyun 								\
53*4882a593Smuzhiyun 	__asm__ __volatile__(					\
54*4882a593Smuzhiyun 	br							\
55*4882a593Smuzhiyun "1:	lwarx   %0,0,%3\n"					\
56*4882a593Smuzhiyun "	and	%1,%0,%6\n"					\
57*4882a593Smuzhiyun "	cmpw	0,%1,%4\n"					\
58*4882a593Smuzhiyun "	bne-	2f\n"						\
59*4882a593Smuzhiyun "	andc	%1,%0,%6\n"					\
60*4882a593Smuzhiyun "	or	%1,%1,%5\n"					\
61*4882a593Smuzhiyun "	stwcx.  %1,0,%3\n"					\
62*4882a593Smuzhiyun "	bne-    1b\n"						\
63*4882a593Smuzhiyun 	br2							\
64*4882a593Smuzhiyun 	"\n"							\
65*4882a593Smuzhiyun "2:"								\
66*4882a593Smuzhiyun 	: "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)		\
67*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new), "r" (prev_mask)	\
68*4882a593Smuzhiyun 	: "cc", cl);						\
69*4882a593Smuzhiyun 								\
70*4882a593Smuzhiyun 	return prev >> bitoff;					\
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun  * Atomic exchange
75*4882a593Smuzhiyun  *
76*4882a593Smuzhiyun  * Changes the memory location '*p' to be val and returns
77*4882a593Smuzhiyun  * the previous value stored there.
78*4882a593Smuzhiyun  */
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun XCHG_GEN(u8, _local, "memory");
81*4882a593Smuzhiyun XCHG_GEN(u8, _relaxed, "cc");
82*4882a593Smuzhiyun XCHG_GEN(u16, _local, "memory");
83*4882a593Smuzhiyun XCHG_GEN(u16, _relaxed, "cc");
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_u32_local(volatile void * p,unsigned long val)86*4882a593Smuzhiyun __xchg_u32_local(volatile void *p, unsigned long val)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	unsigned long prev;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	__asm__ __volatile__(
91*4882a593Smuzhiyun "1:	lwarx	%0,0,%2 \n"
92*4882a593Smuzhiyun "	stwcx.	%3,0,%2 \n\
93*4882a593Smuzhiyun 	bne-	1b"
94*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
95*4882a593Smuzhiyun 	: "r" (p), "r" (val)
96*4882a593Smuzhiyun 	: "cc", "memory");
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	return prev;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_u32_relaxed(u32 * p,unsigned long val)102*4882a593Smuzhiyun __xchg_u32_relaxed(u32 *p, unsigned long val)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	unsigned long prev;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	__asm__ __volatile__(
107*4882a593Smuzhiyun "1:	lwarx	%0,0,%2\n"
108*4882a593Smuzhiyun "	stwcx.	%3,0,%2\n"
109*4882a593Smuzhiyun "	bne-	1b"
110*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
111*4882a593Smuzhiyun 	: "r" (p), "r" (val)
112*4882a593Smuzhiyun 	: "cc");
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	return prev;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #ifdef CONFIG_PPC64
118*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_u64_local(volatile void * p,unsigned long val)119*4882a593Smuzhiyun __xchg_u64_local(volatile void *p, unsigned long val)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	unsigned long prev;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	__asm__ __volatile__(
124*4882a593Smuzhiyun "1:	ldarx	%0,0,%2 \n"
125*4882a593Smuzhiyun "	stdcx.	%3,0,%2 \n\
126*4882a593Smuzhiyun 	bne-	1b"
127*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
128*4882a593Smuzhiyun 	: "r" (p), "r" (val)
129*4882a593Smuzhiyun 	: "cc", "memory");
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return prev;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_u64_relaxed(u64 * p,unsigned long val)135*4882a593Smuzhiyun __xchg_u64_relaxed(u64 *p, unsigned long val)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	unsigned long prev;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	__asm__ __volatile__(
140*4882a593Smuzhiyun "1:	ldarx	%0,0,%2\n"
141*4882a593Smuzhiyun "	stdcx.	%3,0,%2\n"
142*4882a593Smuzhiyun "	bne-	1b"
143*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
144*4882a593Smuzhiyun 	: "r" (p), "r" (val)
145*4882a593Smuzhiyun 	: "cc");
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	return prev;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun #endif
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_local(void * ptr,unsigned long x,unsigned int size)152*4882a593Smuzhiyun __xchg_local(void *ptr, unsigned long x, unsigned int size)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	switch (size) {
155*4882a593Smuzhiyun 	case 1:
156*4882a593Smuzhiyun 		return __xchg_u8_local(ptr, x);
157*4882a593Smuzhiyun 	case 2:
158*4882a593Smuzhiyun 		return __xchg_u16_local(ptr, x);
159*4882a593Smuzhiyun 	case 4:
160*4882a593Smuzhiyun 		return __xchg_u32_local(ptr, x);
161*4882a593Smuzhiyun #ifdef CONFIG_PPC64
162*4882a593Smuzhiyun 	case 8:
163*4882a593Smuzhiyun 		return __xchg_u64_local(ptr, x);
164*4882a593Smuzhiyun #endif
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg");
167*4882a593Smuzhiyun 	return x;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun static __always_inline unsigned long
__xchg_relaxed(void * ptr,unsigned long x,unsigned int size)171*4882a593Smuzhiyun __xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	switch (size) {
174*4882a593Smuzhiyun 	case 1:
175*4882a593Smuzhiyun 		return __xchg_u8_relaxed(ptr, x);
176*4882a593Smuzhiyun 	case 2:
177*4882a593Smuzhiyun 		return __xchg_u16_relaxed(ptr, x);
178*4882a593Smuzhiyun 	case 4:
179*4882a593Smuzhiyun 		return __xchg_u32_relaxed(ptr, x);
180*4882a593Smuzhiyun #ifdef CONFIG_PPC64
181*4882a593Smuzhiyun 	case 8:
182*4882a593Smuzhiyun 		return __xchg_u64_relaxed(ptr, x);
183*4882a593Smuzhiyun #endif
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local");
186*4882a593Smuzhiyun 	return x;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun #define xchg_local(ptr,x)						     \
189*4882a593Smuzhiyun   ({									     \
190*4882a593Smuzhiyun      __typeof__(*(ptr)) _x_ = (x);					     \
191*4882a593Smuzhiyun      (__typeof__(*(ptr))) __xchg_local((ptr),				     \
192*4882a593Smuzhiyun      		(unsigned long)_x_, sizeof(*(ptr))); 			     \
193*4882a593Smuzhiyun   })
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun #define xchg_relaxed(ptr, x)						\
196*4882a593Smuzhiyun ({									\
197*4882a593Smuzhiyun 	__typeof__(*(ptr)) _x_ = (x);					\
198*4882a593Smuzhiyun 	(__typeof__(*(ptr))) __xchg_relaxed((ptr),			\
199*4882a593Smuzhiyun 			(unsigned long)_x_, sizeof(*(ptr)));		\
200*4882a593Smuzhiyun })
201*4882a593Smuzhiyun /*
202*4882a593Smuzhiyun  * Compare and exchange - if *p == old, set it to new,
203*4882a593Smuzhiyun  * and return the old value of *p.
204*4882a593Smuzhiyun  */
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun CMPXCHG_GEN(u8, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
207*4882a593Smuzhiyun CMPXCHG_GEN(u8, _local, , , "memory");
208*4882a593Smuzhiyun CMPXCHG_GEN(u8, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
209*4882a593Smuzhiyun CMPXCHG_GEN(u8, _relaxed, , , "cc");
210*4882a593Smuzhiyun CMPXCHG_GEN(u16, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
211*4882a593Smuzhiyun CMPXCHG_GEN(u16, _local, , , "memory");
212*4882a593Smuzhiyun CMPXCHG_GEN(u16, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
213*4882a593Smuzhiyun CMPXCHG_GEN(u16, _relaxed, , , "cc");
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u32(volatile unsigned int * p,unsigned long old,unsigned long new)216*4882a593Smuzhiyun __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	unsigned int prev;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	__asm__ __volatile__ (
221*4882a593Smuzhiyun 	PPC_ATOMIC_ENTRY_BARRIER
222*4882a593Smuzhiyun "1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
223*4882a593Smuzhiyun 	cmpw	0,%0,%3\n\
224*4882a593Smuzhiyun 	bne-	2f\n"
225*4882a593Smuzhiyun "	stwcx.	%4,0,%2\n\
226*4882a593Smuzhiyun 	bne-	1b"
227*4882a593Smuzhiyun 	PPC_ATOMIC_EXIT_BARRIER
228*4882a593Smuzhiyun 	"\n\
229*4882a593Smuzhiyun 2:"
230*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
231*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
232*4882a593Smuzhiyun 	: "cc", "memory");
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	return prev;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u32_local(volatile unsigned int * p,unsigned long old,unsigned long new)238*4882a593Smuzhiyun __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
239*4882a593Smuzhiyun 			unsigned long new)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	unsigned int prev;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	__asm__ __volatile__ (
244*4882a593Smuzhiyun "1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
245*4882a593Smuzhiyun 	cmpw	0,%0,%3\n\
246*4882a593Smuzhiyun 	bne-	2f\n"
247*4882a593Smuzhiyun "	stwcx.	%4,0,%2\n\
248*4882a593Smuzhiyun 	bne-	1b"
249*4882a593Smuzhiyun 	"\n\
250*4882a593Smuzhiyun 2:"
251*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
252*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
253*4882a593Smuzhiyun 	: "cc", "memory");
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return prev;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u32_relaxed(u32 * p,unsigned long old,unsigned long new)259*4882a593Smuzhiyun __cmpxchg_u32_relaxed(u32 *p, unsigned long old, unsigned long new)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	unsigned long prev;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	__asm__ __volatile__ (
264*4882a593Smuzhiyun "1:	lwarx	%0,0,%2		# __cmpxchg_u32_relaxed\n"
265*4882a593Smuzhiyun "	cmpw	0,%0,%3\n"
266*4882a593Smuzhiyun "	bne-	2f\n"
267*4882a593Smuzhiyun "	stwcx.	%4,0,%2\n"
268*4882a593Smuzhiyun "	bne-	1b\n"
269*4882a593Smuzhiyun "2:"
270*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
271*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
272*4882a593Smuzhiyun 	: "cc");
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return prev;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun /*
278*4882a593Smuzhiyun  * cmpxchg family don't have order guarantee if cmp part fails, therefore we
279*4882a593Smuzhiyun  * can avoid superfluous barriers if we use assembly code to implement
280*4882a593Smuzhiyun  * cmpxchg() and cmpxchg_acquire(), however we don't do the similar for
281*4882a593Smuzhiyun  * cmpxchg_release() because that will result in putting a barrier in the
282*4882a593Smuzhiyun  * middle of a ll/sc loop, which is probably a bad idea. For example, this
283*4882a593Smuzhiyun  * might cause the conditional store more likely to fail.
284*4882a593Smuzhiyun  */
285*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u32_acquire(u32 * p,unsigned long old,unsigned long new)286*4882a593Smuzhiyun __cmpxchg_u32_acquire(u32 *p, unsigned long old, unsigned long new)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	unsigned long prev;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	__asm__ __volatile__ (
291*4882a593Smuzhiyun "1:	lwarx	%0,0,%2		# __cmpxchg_u32_acquire\n"
292*4882a593Smuzhiyun "	cmpw	0,%0,%3\n"
293*4882a593Smuzhiyun "	bne-	2f\n"
294*4882a593Smuzhiyun "	stwcx.	%4,0,%2\n"
295*4882a593Smuzhiyun "	bne-	1b\n"
296*4882a593Smuzhiyun 	PPC_ACQUIRE_BARRIER
297*4882a593Smuzhiyun 	"\n"
298*4882a593Smuzhiyun "2:"
299*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
300*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
301*4882a593Smuzhiyun 	: "cc", "memory");
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return prev;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun #ifdef CONFIG_PPC64
307*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u64(volatile unsigned long * p,unsigned long old,unsigned long new)308*4882a593Smuzhiyun __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	unsigned long prev;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	__asm__ __volatile__ (
313*4882a593Smuzhiyun 	PPC_ATOMIC_ENTRY_BARRIER
314*4882a593Smuzhiyun "1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
315*4882a593Smuzhiyun 	cmpd	0,%0,%3\n\
316*4882a593Smuzhiyun 	bne-	2f\n\
317*4882a593Smuzhiyun 	stdcx.	%4,0,%2\n\
318*4882a593Smuzhiyun 	bne-	1b"
319*4882a593Smuzhiyun 	PPC_ATOMIC_EXIT_BARRIER
320*4882a593Smuzhiyun 	"\n\
321*4882a593Smuzhiyun 2:"
322*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
323*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
324*4882a593Smuzhiyun 	: "cc", "memory");
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return prev;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u64_local(volatile unsigned long * p,unsigned long old,unsigned long new)330*4882a593Smuzhiyun __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
331*4882a593Smuzhiyun 			unsigned long new)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	unsigned long prev;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	__asm__ __volatile__ (
336*4882a593Smuzhiyun "1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
337*4882a593Smuzhiyun 	cmpd	0,%0,%3\n\
338*4882a593Smuzhiyun 	bne-	2f\n\
339*4882a593Smuzhiyun 	stdcx.	%4,0,%2\n\
340*4882a593Smuzhiyun 	bne-	1b"
341*4882a593Smuzhiyun 	"\n\
342*4882a593Smuzhiyun 2:"
343*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
344*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
345*4882a593Smuzhiyun 	: "cc", "memory");
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return prev;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u64_relaxed(u64 * p,unsigned long old,unsigned long new)351*4882a593Smuzhiyun __cmpxchg_u64_relaxed(u64 *p, unsigned long old, unsigned long new)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	unsigned long prev;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	__asm__ __volatile__ (
356*4882a593Smuzhiyun "1:	ldarx	%0,0,%2		# __cmpxchg_u64_relaxed\n"
357*4882a593Smuzhiyun "	cmpd	0,%0,%3\n"
358*4882a593Smuzhiyun "	bne-	2f\n"
359*4882a593Smuzhiyun "	stdcx.	%4,0,%2\n"
360*4882a593Smuzhiyun "	bne-	1b\n"
361*4882a593Smuzhiyun "2:"
362*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
363*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
364*4882a593Smuzhiyun 	: "cc");
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return prev;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_u64_acquire(u64 * p,unsigned long old,unsigned long new)370*4882a593Smuzhiyun __cmpxchg_u64_acquire(u64 *p, unsigned long old, unsigned long new)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	unsigned long prev;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	__asm__ __volatile__ (
375*4882a593Smuzhiyun "1:	ldarx	%0,0,%2		# __cmpxchg_u64_acquire\n"
376*4882a593Smuzhiyun "	cmpd	0,%0,%3\n"
377*4882a593Smuzhiyun "	bne-	2f\n"
378*4882a593Smuzhiyun "	stdcx.	%4,0,%2\n"
379*4882a593Smuzhiyun "	bne-	1b\n"
380*4882a593Smuzhiyun 	PPC_ACQUIRE_BARRIER
381*4882a593Smuzhiyun 	"\n"
382*4882a593Smuzhiyun "2:"
383*4882a593Smuzhiyun 	: "=&r" (prev), "+m" (*p)
384*4882a593Smuzhiyun 	: "r" (p), "r" (old), "r" (new)
385*4882a593Smuzhiyun 	: "cc", "memory");
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	return prev;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun #endif
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg(volatile void * ptr,unsigned long old,unsigned long new,unsigned int size)392*4882a593Smuzhiyun __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
393*4882a593Smuzhiyun 	  unsigned int size)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	switch (size) {
396*4882a593Smuzhiyun 	case 1:
397*4882a593Smuzhiyun 		return __cmpxchg_u8(ptr, old, new);
398*4882a593Smuzhiyun 	case 2:
399*4882a593Smuzhiyun 		return __cmpxchg_u16(ptr, old, new);
400*4882a593Smuzhiyun 	case 4:
401*4882a593Smuzhiyun 		return __cmpxchg_u32(ptr, old, new);
402*4882a593Smuzhiyun #ifdef CONFIG_PPC64
403*4882a593Smuzhiyun 	case 8:
404*4882a593Smuzhiyun 		return __cmpxchg_u64(ptr, old, new);
405*4882a593Smuzhiyun #endif
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg");
408*4882a593Smuzhiyun 	return old;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_local(void * ptr,unsigned long old,unsigned long new,unsigned int size)412*4882a593Smuzhiyun __cmpxchg_local(void *ptr, unsigned long old, unsigned long new,
413*4882a593Smuzhiyun 	  unsigned int size)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	switch (size) {
416*4882a593Smuzhiyun 	case 1:
417*4882a593Smuzhiyun 		return __cmpxchg_u8_local(ptr, old, new);
418*4882a593Smuzhiyun 	case 2:
419*4882a593Smuzhiyun 		return __cmpxchg_u16_local(ptr, old, new);
420*4882a593Smuzhiyun 	case 4:
421*4882a593Smuzhiyun 		return __cmpxchg_u32_local(ptr, old, new);
422*4882a593Smuzhiyun #ifdef CONFIG_PPC64
423*4882a593Smuzhiyun 	case 8:
424*4882a593Smuzhiyun 		return __cmpxchg_u64_local(ptr, old, new);
425*4882a593Smuzhiyun #endif
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_local");
428*4882a593Smuzhiyun 	return old;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_relaxed(void * ptr,unsigned long old,unsigned long new,unsigned int size)432*4882a593Smuzhiyun __cmpxchg_relaxed(void *ptr, unsigned long old, unsigned long new,
433*4882a593Smuzhiyun 		  unsigned int size)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	switch (size) {
436*4882a593Smuzhiyun 	case 1:
437*4882a593Smuzhiyun 		return __cmpxchg_u8_relaxed(ptr, old, new);
438*4882a593Smuzhiyun 	case 2:
439*4882a593Smuzhiyun 		return __cmpxchg_u16_relaxed(ptr, old, new);
440*4882a593Smuzhiyun 	case 4:
441*4882a593Smuzhiyun 		return __cmpxchg_u32_relaxed(ptr, old, new);
442*4882a593Smuzhiyun #ifdef CONFIG_PPC64
443*4882a593Smuzhiyun 	case 8:
444*4882a593Smuzhiyun 		return __cmpxchg_u64_relaxed(ptr, old, new);
445*4882a593Smuzhiyun #endif
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_relaxed");
448*4882a593Smuzhiyun 	return old;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static __always_inline unsigned long
__cmpxchg_acquire(void * ptr,unsigned long old,unsigned long new,unsigned int size)452*4882a593Smuzhiyun __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
453*4882a593Smuzhiyun 		  unsigned int size)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	switch (size) {
456*4882a593Smuzhiyun 	case 1:
457*4882a593Smuzhiyun 		return __cmpxchg_u8_acquire(ptr, old, new);
458*4882a593Smuzhiyun 	case 2:
459*4882a593Smuzhiyun 		return __cmpxchg_u16_acquire(ptr, old, new);
460*4882a593Smuzhiyun 	case 4:
461*4882a593Smuzhiyun 		return __cmpxchg_u32_acquire(ptr, old, new);
462*4882a593Smuzhiyun #ifdef CONFIG_PPC64
463*4882a593Smuzhiyun 	case 8:
464*4882a593Smuzhiyun 		return __cmpxchg_u64_acquire(ptr, old, new);
465*4882a593Smuzhiyun #endif
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_acquire");
468*4882a593Smuzhiyun 	return old;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun #define cmpxchg(ptr, o, n)						 \
471*4882a593Smuzhiyun   ({									 \
472*4882a593Smuzhiyun      __typeof__(*(ptr)) _o_ = (o);					 \
473*4882a593Smuzhiyun      __typeof__(*(ptr)) _n_ = (n);					 \
474*4882a593Smuzhiyun      (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
475*4882a593Smuzhiyun 				    (unsigned long)_n_, sizeof(*(ptr))); \
476*4882a593Smuzhiyun   })
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun #define cmpxchg_local(ptr, o, n)					 \
480*4882a593Smuzhiyun   ({									 \
481*4882a593Smuzhiyun      __typeof__(*(ptr)) _o_ = (o);					 \
482*4882a593Smuzhiyun      __typeof__(*(ptr)) _n_ = (n);					 \
483*4882a593Smuzhiyun      (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
484*4882a593Smuzhiyun 				    (unsigned long)_n_, sizeof(*(ptr))); \
485*4882a593Smuzhiyun   })
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun #define cmpxchg_relaxed(ptr, o, n)					\
488*4882a593Smuzhiyun ({									\
489*4882a593Smuzhiyun 	__typeof__(*(ptr)) _o_ = (o);					\
490*4882a593Smuzhiyun 	__typeof__(*(ptr)) _n_ = (n);					\
491*4882a593Smuzhiyun 	(__typeof__(*(ptr))) __cmpxchg_relaxed((ptr),			\
492*4882a593Smuzhiyun 			(unsigned long)_o_, (unsigned long)_n_,		\
493*4882a593Smuzhiyun 			sizeof(*(ptr)));				\
494*4882a593Smuzhiyun })
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun #define cmpxchg_acquire(ptr, o, n)					\
497*4882a593Smuzhiyun ({									\
498*4882a593Smuzhiyun 	__typeof__(*(ptr)) _o_ = (o);					\
499*4882a593Smuzhiyun 	__typeof__(*(ptr)) _n_ = (n);					\
500*4882a593Smuzhiyun 	(__typeof__(*(ptr))) __cmpxchg_acquire((ptr),			\
501*4882a593Smuzhiyun 			(unsigned long)_o_, (unsigned long)_n_,		\
502*4882a593Smuzhiyun 			sizeof(*(ptr)));				\
503*4882a593Smuzhiyun })
504*4882a593Smuzhiyun #ifdef CONFIG_PPC64
505*4882a593Smuzhiyun #define cmpxchg64(ptr, o, n)						\
506*4882a593Smuzhiyun   ({									\
507*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
508*4882a593Smuzhiyun 	cmpxchg((ptr), (o), (n));					\
509*4882a593Smuzhiyun   })
510*4882a593Smuzhiyun #define cmpxchg64_local(ptr, o, n)					\
511*4882a593Smuzhiyun   ({									\
512*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
513*4882a593Smuzhiyun 	cmpxchg_local((ptr), (o), (n));					\
514*4882a593Smuzhiyun   })
515*4882a593Smuzhiyun #define cmpxchg64_relaxed(ptr, o, n)					\
516*4882a593Smuzhiyun ({									\
517*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
518*4882a593Smuzhiyun 	cmpxchg_relaxed((ptr), (o), (n));				\
519*4882a593Smuzhiyun })
520*4882a593Smuzhiyun #define cmpxchg64_acquire(ptr, o, n)					\
521*4882a593Smuzhiyun ({									\
522*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
523*4882a593Smuzhiyun 	cmpxchg_acquire((ptr), (o), (n));				\
524*4882a593Smuzhiyun })
525*4882a593Smuzhiyun #else
526*4882a593Smuzhiyun #include <asm-generic/cmpxchg-local.h>
527*4882a593Smuzhiyun #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
528*4882a593Smuzhiyun #endif
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun #endif /* __KERNEL__ */
531*4882a593Smuzhiyun #endif /* _ASM_POWERPC_CMPXCHG_H_ */
532