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