xref: /openbmc/linux/arch/csky/include/asm/atomic.h (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
16b160e05SGuo Ren /* SPDX-License-Identifier: GPL-2.0 */
26b160e05SGuo Ren 
36b160e05SGuo Ren #ifndef __ASM_CSKY_ATOMIC_H
46b160e05SGuo Ren #define __ASM_CSKY_ATOMIC_H
56b160e05SGuo Ren 
66b160e05SGuo Ren #ifdef CONFIG_SMP
76b160e05SGuo Ren #include <asm-generic/atomic64.h>
86b160e05SGuo Ren 
96b160e05SGuo Ren #include <asm/cmpxchg.h>
106b160e05SGuo Ren #include <asm/barrier.h>
116b160e05SGuo Ren 
126b160e05SGuo Ren #define __atomic_acquire_fence()	__bar_brarw()
136b160e05SGuo Ren 
146b160e05SGuo Ren #define __atomic_release_fence()	__bar_brwaw()
156b160e05SGuo Ren 
arch_atomic_read(const atomic_t * v)166b160e05SGuo Ren static __always_inline int arch_atomic_read(const atomic_t *v)
176b160e05SGuo Ren {
186b160e05SGuo Ren 	return READ_ONCE(v->counter);
196b160e05SGuo Ren }
arch_atomic_set(atomic_t * v,int i)206b160e05SGuo Ren static __always_inline void arch_atomic_set(atomic_t *v, int i)
216b160e05SGuo Ren {
226b160e05SGuo Ren 	WRITE_ONCE(v->counter, i);
236b160e05SGuo Ren }
246b160e05SGuo Ren 
256b160e05SGuo Ren #define ATOMIC_OP(op)							\
266b160e05SGuo Ren static __always_inline							\
276b160e05SGuo Ren void arch_atomic_##op(int i, atomic_t *v)				\
286b160e05SGuo Ren {									\
296b160e05SGuo Ren 	unsigned long tmp;						\
306b160e05SGuo Ren 	__asm__ __volatile__ (						\
316b160e05SGuo Ren 	"1:	ldex.w		%0, (%2)	\n"			\
326b160e05SGuo Ren 	"	" #op "		%0, %1		\n"			\
336b160e05SGuo Ren 	"	stex.w		%0, (%2)	\n"			\
346b160e05SGuo Ren 	"	bez		%0, 1b		\n"			\
356b160e05SGuo Ren 	: "=&r" (tmp)							\
366b160e05SGuo Ren 	: "r" (i), "r" (&v->counter)					\
376b160e05SGuo Ren 	: "memory");							\
386b160e05SGuo Ren }
396b160e05SGuo Ren 
406b160e05SGuo Ren ATOMIC_OP(add)
ATOMIC_OP(sub)416b160e05SGuo Ren ATOMIC_OP(sub)
426b160e05SGuo Ren ATOMIC_OP(and)
436b160e05SGuo Ren ATOMIC_OP( or)
446b160e05SGuo Ren ATOMIC_OP(xor)
456b160e05SGuo Ren 
466b160e05SGuo Ren #undef ATOMIC_OP
476b160e05SGuo Ren 
486b160e05SGuo Ren #define ATOMIC_FETCH_OP(op)						\
496b160e05SGuo Ren static __always_inline							\
506b160e05SGuo Ren int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v)		\
516b160e05SGuo Ren {									\
526b160e05SGuo Ren 	register int ret, tmp;						\
536b160e05SGuo Ren 	__asm__ __volatile__ (						\
546b160e05SGuo Ren 	"1:	ldex.w		%0, (%3) \n"				\
556b160e05SGuo Ren 	"	mov		%1, %0   \n"				\
566b160e05SGuo Ren 	"	" #op "		%0, %2   \n"				\
576b160e05SGuo Ren 	"	stex.w		%0, (%3) \n"				\
586b160e05SGuo Ren 	"	bez		%0, 1b   \n"				\
596b160e05SGuo Ren 		: "=&r" (tmp), "=&r" (ret)				\
606b160e05SGuo Ren 		: "r" (i), "r"(&v->counter) 				\
616b160e05SGuo Ren 		: "memory");						\
626b160e05SGuo Ren 	return ret;							\
636b160e05SGuo Ren }
646b160e05SGuo Ren 
656b160e05SGuo Ren #define ATOMIC_OP_RETURN(op, c_op)					\
666b160e05SGuo Ren static __always_inline							\
676b160e05SGuo Ren int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)		\
686b160e05SGuo Ren {									\
696b160e05SGuo Ren 	return arch_atomic_fetch_##op##_relaxed(i, v) c_op i;		\
706b160e05SGuo Ren }
716b160e05SGuo Ren 
726b160e05SGuo Ren #define ATOMIC_OPS(op, c_op)						\
736b160e05SGuo Ren 	ATOMIC_FETCH_OP(op)						\
746b160e05SGuo Ren 	ATOMIC_OP_RETURN(op, c_op)
756b160e05SGuo Ren 
766b160e05SGuo Ren ATOMIC_OPS(add, +)
776b160e05SGuo Ren ATOMIC_OPS(sub, -)
786b160e05SGuo Ren 
796b160e05SGuo Ren #define arch_atomic_fetch_add_relaxed	arch_atomic_fetch_add_relaxed
806b160e05SGuo Ren #define arch_atomic_fetch_sub_relaxed	arch_atomic_fetch_sub_relaxed
816b160e05SGuo Ren 
826b160e05SGuo Ren #define arch_atomic_add_return_relaxed	arch_atomic_add_return_relaxed
836b160e05SGuo Ren #define arch_atomic_sub_return_relaxed	arch_atomic_sub_return_relaxed
846b160e05SGuo Ren 
856b160e05SGuo Ren #undef ATOMIC_OPS
866b160e05SGuo Ren #undef ATOMIC_OP_RETURN
876b160e05SGuo Ren 
886b160e05SGuo Ren #define ATOMIC_OPS(op)							\
896b160e05SGuo Ren 	ATOMIC_FETCH_OP(op)
906b160e05SGuo Ren 
916b160e05SGuo Ren ATOMIC_OPS(and)
926b160e05SGuo Ren ATOMIC_OPS( or)
936b160e05SGuo Ren ATOMIC_OPS(xor)
946b160e05SGuo Ren 
956b160e05SGuo Ren #define arch_atomic_fetch_and_relaxed	arch_atomic_fetch_and_relaxed
966b160e05SGuo Ren #define arch_atomic_fetch_or_relaxed	arch_atomic_fetch_or_relaxed
976b160e05SGuo Ren #define arch_atomic_fetch_xor_relaxed	arch_atomic_fetch_xor_relaxed
986b160e05SGuo Ren 
996b160e05SGuo Ren #undef ATOMIC_OPS
1006b160e05SGuo Ren 
1016b160e05SGuo Ren #undef ATOMIC_FETCH_OP
1026b160e05SGuo Ren 
103*c5acdf12SGuo Ren static __always_inline int
104*c5acdf12SGuo Ren arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
105*c5acdf12SGuo Ren {
106*c5acdf12SGuo Ren 	int prev, tmp;
107*c5acdf12SGuo Ren 
108*c5acdf12SGuo Ren 	__asm__ __volatile__ (
109*c5acdf12SGuo Ren 		RELEASE_FENCE
110*c5acdf12SGuo Ren 		"1:	ldex.w		%0, (%3)	\n"
111*c5acdf12SGuo Ren 		"	cmpne		%0, %4		\n"
112*c5acdf12SGuo Ren 		"	bf		2f		\n"
113*c5acdf12SGuo Ren 		"	mov		%1, %0		\n"
114*c5acdf12SGuo Ren 		"	add		%1, %2		\n"
115*c5acdf12SGuo Ren 		"	stex.w		%1, (%3)	\n"
116*c5acdf12SGuo Ren 		"	bez		%1, 1b		\n"
117*c5acdf12SGuo Ren 		FULL_FENCE
118*c5acdf12SGuo Ren 		"2:\n"
119*c5acdf12SGuo Ren 		: "=&r" (prev), "=&r" (tmp)
120*c5acdf12SGuo Ren 		: "r" (a), "r" (&v->counter), "r" (u)
121*c5acdf12SGuo Ren 		: "memory");
122*c5acdf12SGuo Ren 
123*c5acdf12SGuo Ren 	return prev;
124*c5acdf12SGuo Ren }
125*c5acdf12SGuo Ren #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
126*c5acdf12SGuo Ren 
127*c5acdf12SGuo Ren static __always_inline bool
arch_atomic_inc_unless_negative(atomic_t * v)128*c5acdf12SGuo Ren arch_atomic_inc_unless_negative(atomic_t *v)
129*c5acdf12SGuo Ren {
130*c5acdf12SGuo Ren 	int rc, tmp;
131*c5acdf12SGuo Ren 
132*c5acdf12SGuo Ren 	__asm__ __volatile__ (
133*c5acdf12SGuo Ren 		RELEASE_FENCE
134*c5acdf12SGuo Ren 		"1:	ldex.w		%0, (%2)	\n"
135*c5acdf12SGuo Ren 		"	movi		%1, 0		\n"
136*c5acdf12SGuo Ren 		"	blz		%0, 2f		\n"
137*c5acdf12SGuo Ren 		"	movi		%1, 1		\n"
138*c5acdf12SGuo Ren 		"	addi		%0, 1		\n"
139*c5acdf12SGuo Ren 		"	stex.w		%0, (%2)	\n"
140*c5acdf12SGuo Ren 		"	bez		%0, 1b		\n"
141*c5acdf12SGuo Ren 		FULL_FENCE
142*c5acdf12SGuo Ren 		"2:\n"
143*c5acdf12SGuo Ren 		: "=&r" (tmp), "=&r" (rc)
144*c5acdf12SGuo Ren 		: "r" (&v->counter)
145*c5acdf12SGuo Ren 		: "memory");
146*c5acdf12SGuo Ren 
147*c5acdf12SGuo Ren 	return tmp ? true : false;
148*c5acdf12SGuo Ren 
149*c5acdf12SGuo Ren }
150*c5acdf12SGuo Ren #define arch_atomic_inc_unless_negative arch_atomic_inc_unless_negative
151*c5acdf12SGuo Ren 
152*c5acdf12SGuo Ren static __always_inline bool
arch_atomic_dec_unless_positive(atomic_t * v)153*c5acdf12SGuo Ren arch_atomic_dec_unless_positive(atomic_t *v)
154*c5acdf12SGuo Ren {
155*c5acdf12SGuo Ren 	int rc, tmp;
156*c5acdf12SGuo Ren 
157*c5acdf12SGuo Ren 	__asm__ __volatile__ (
158*c5acdf12SGuo Ren 		RELEASE_FENCE
159*c5acdf12SGuo Ren 		"1:	ldex.w		%0, (%2)	\n"
160*c5acdf12SGuo Ren 		"	movi		%1, 0		\n"
161*c5acdf12SGuo Ren 		"	bhz		%0, 2f		\n"
162*c5acdf12SGuo Ren 		"	movi		%1, 1		\n"
163*c5acdf12SGuo Ren 		"	subi		%0, 1		\n"
164*c5acdf12SGuo Ren 		"	stex.w		%0, (%2)	\n"
165*c5acdf12SGuo Ren 		"	bez		%0, 1b		\n"
166*c5acdf12SGuo Ren 		FULL_FENCE
167*c5acdf12SGuo Ren 		"2:\n"
168*c5acdf12SGuo Ren 		: "=&r" (tmp), "=&r" (rc)
169*c5acdf12SGuo Ren 		: "r" (&v->counter)
170*c5acdf12SGuo Ren 		: "memory");
171*c5acdf12SGuo Ren 
172*c5acdf12SGuo Ren 	return tmp ? true : false;
173*c5acdf12SGuo Ren }
174*c5acdf12SGuo Ren #define arch_atomic_dec_unless_positive arch_atomic_dec_unless_positive
175*c5acdf12SGuo Ren 
176*c5acdf12SGuo Ren static __always_inline int
arch_atomic_dec_if_positive(atomic_t * v)177*c5acdf12SGuo Ren arch_atomic_dec_if_positive(atomic_t *v)
178*c5acdf12SGuo Ren {
179*c5acdf12SGuo Ren 	int dec, tmp;
180*c5acdf12SGuo Ren 
181*c5acdf12SGuo Ren 	__asm__ __volatile__ (
182*c5acdf12SGuo Ren 		RELEASE_FENCE
183*c5acdf12SGuo Ren 		"1:	ldex.w		%0, (%2)	\n"
184*c5acdf12SGuo Ren 		"	subi		%1, %0, 1	\n"
185*c5acdf12SGuo Ren 		"	blz		%1, 2f		\n"
186*c5acdf12SGuo Ren 		"	stex.w		%1, (%2)	\n"
187*c5acdf12SGuo Ren 		"	bez		%1, 1b		\n"
188*c5acdf12SGuo Ren 		FULL_FENCE
189*c5acdf12SGuo Ren 		"2:\n"
190*c5acdf12SGuo Ren 		: "=&r" (dec), "=&r" (tmp)
191*c5acdf12SGuo Ren 		: "r" (&v->counter)
192*c5acdf12SGuo Ren 		: "memory");
193*c5acdf12SGuo Ren 
194*c5acdf12SGuo Ren 	return dec - 1;
195*c5acdf12SGuo Ren }
196*c5acdf12SGuo Ren #define arch_atomic_dec_if_positive arch_atomic_dec_if_positive
197*c5acdf12SGuo Ren 
1986b160e05SGuo Ren #else
1996b160e05SGuo Ren #include <asm-generic/atomic.h>
2006b160e05SGuo Ren #endif
2016b160e05SGuo Ren 
2026b160e05SGuo Ren #endif /* __ASM_CSKY_ATOMIC_H */
203