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