18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/* atomic.S: These things are too big to do inline.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2007 2012 David S. Miller (davem@davemloft.net)
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/linkage.h>
88c2ecf20Sopenharmony_ci#include <asm/asi.h>
98c2ecf20Sopenharmony_ci#include <asm/backoff.h>
108c2ecf20Sopenharmony_ci#include <asm/export.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci	.text
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	/* Three versions of the atomic routines, one that
158c2ecf20Sopenharmony_ci	 * does not return a value and does not perform
168c2ecf20Sopenharmony_ci	 * memory barriers, and a two which return
178c2ecf20Sopenharmony_ci	 * a value, the new and old value resp. and does the
188c2ecf20Sopenharmony_ci	 * barriers.
198c2ecf20Sopenharmony_ci	 */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define ATOMIC_OP(op)							\
228c2ecf20Sopenharmony_ciENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */		\
238c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
248c2ecf20Sopenharmony_ci1:	lduw	[%o1], %g1;						\
258c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
268c2ecf20Sopenharmony_ci	cas	[%o1], %g1, %g7;					\
278c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
288c2ecf20Sopenharmony_ci	bne,pn	%icc, BACKOFF_LABEL(2f, 1b);				\
298c2ecf20Sopenharmony_ci	 nop;								\
308c2ecf20Sopenharmony_ci	retl;								\
318c2ecf20Sopenharmony_ci	 nop;								\
328c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
338c2ecf20Sopenharmony_ciENDPROC(atomic_##op);							\
348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_##op);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
378c2ecf20Sopenharmony_ciENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */	\
388c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
398c2ecf20Sopenharmony_ci1:	lduw	[%o1], %g1;						\
408c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
418c2ecf20Sopenharmony_ci	cas	[%o1], %g1, %g7;					\
428c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
438c2ecf20Sopenharmony_ci	bne,pn	%icc, BACKOFF_LABEL(2f, 1b);				\
448c2ecf20Sopenharmony_ci	 op	%g1, %o0, %g1;						\
458c2ecf20Sopenharmony_ci	retl;								\
468c2ecf20Sopenharmony_ci	 sra	%g1, 0, %o0;						\
478c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
488c2ecf20Sopenharmony_ciENDPROC(atomic_##op##_return);						\
498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_##op##_return);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
528c2ecf20Sopenharmony_ciENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */	\
538c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
548c2ecf20Sopenharmony_ci1:	lduw	[%o1], %g1;						\
558c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
568c2ecf20Sopenharmony_ci	cas	[%o1], %g1, %g7;					\
578c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
588c2ecf20Sopenharmony_ci	bne,pn	%icc, BACKOFF_LABEL(2f, 1b);				\
598c2ecf20Sopenharmony_ci	 nop;								\
608c2ecf20Sopenharmony_ci	retl;								\
618c2ecf20Sopenharmony_ci	 sra	%g1, 0, %o0;						\
628c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
638c2ecf20Sopenharmony_ciENDPROC(atomic_fetch_##op);						\
648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_fetch_##op);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciATOMIC_OP(add)
678c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(add)
688c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(add)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciATOMIC_OP(sub)
718c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(sub)
728c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(sub)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciATOMIC_OP(and)
758c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and)
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciATOMIC_OP(or)
788c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciATOMIC_OP(xor)
818c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
848c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
858c2ecf20Sopenharmony_ci#undef ATOMIC_OP
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op)							\
888c2ecf20Sopenharmony_ciENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */		\
898c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
908c2ecf20Sopenharmony_ci1:	ldx	[%o1], %g1;						\
918c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
928c2ecf20Sopenharmony_ci	casx	[%o1], %g1, %g7;					\
938c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
948c2ecf20Sopenharmony_ci	bne,pn	%xcc, BACKOFF_LABEL(2f, 1b);				\
958c2ecf20Sopenharmony_ci	 nop;								\
968c2ecf20Sopenharmony_ci	retl;								\
978c2ecf20Sopenharmony_ci	 nop;								\
988c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
998c2ecf20Sopenharmony_ciENDPROC(atomic64_##op);							\
1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_##op);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op)						\
1038c2ecf20Sopenharmony_ciENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */	\
1048c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
1058c2ecf20Sopenharmony_ci1:	ldx	[%o1], %g1;						\
1068c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
1078c2ecf20Sopenharmony_ci	casx	[%o1], %g1, %g7;					\
1088c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
1098c2ecf20Sopenharmony_ci	bne,pn	%xcc, BACKOFF_LABEL(2f, 1b);				\
1108c2ecf20Sopenharmony_ci	 nop;								\
1118c2ecf20Sopenharmony_ci	retl;								\
1128c2ecf20Sopenharmony_ci	 op	%g1, %o0, %o0;						\
1138c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
1148c2ecf20Sopenharmony_ciENDPROC(atomic64_##op##_return);					\
1158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_##op##_return);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op)						\
1188c2ecf20Sopenharmony_ciENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */	\
1198c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2);						\
1208c2ecf20Sopenharmony_ci1:	ldx	[%o1], %g1;						\
1218c2ecf20Sopenharmony_ci	op	%g1, %o0, %g7;						\
1228c2ecf20Sopenharmony_ci	casx	[%o1], %g1, %g7;					\
1238c2ecf20Sopenharmony_ci	cmp	%g1, %g7;						\
1248c2ecf20Sopenharmony_ci	bne,pn	%xcc, BACKOFF_LABEL(2f, 1b);				\
1258c2ecf20Sopenharmony_ci	 nop;								\
1268c2ecf20Sopenharmony_ci	retl;								\
1278c2ecf20Sopenharmony_ci	 mov	%g1, %o0;						\
1288c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b);					\
1298c2ecf20Sopenharmony_ciENDPROC(atomic64_fetch_##op);						\
1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_fetch_##op);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciATOMIC64_OP(add)
1338c2ecf20Sopenharmony_ciATOMIC64_OP_RETURN(add)
1348c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(add)
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciATOMIC64_OP(sub)
1378c2ecf20Sopenharmony_ciATOMIC64_OP_RETURN(sub)
1388c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(sub)
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciATOMIC64_OP(and)
1418c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(and)
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ciATOMIC64_OP(or)
1448c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(or)
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciATOMIC64_OP(xor)
1478c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(xor)
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP
1508c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN
1518c2ecf20Sopenharmony_ci#undef ATOMIC64_OP
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ciENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
1548c2ecf20Sopenharmony_ci	BACKOFF_SETUP(%o2)
1558c2ecf20Sopenharmony_ci1:	ldx	[%o0], %g1
1568c2ecf20Sopenharmony_ci	brlez,pn %g1, 3f
1578c2ecf20Sopenharmony_ci	 sub	%g1, 1, %g7
1588c2ecf20Sopenharmony_ci	casx	[%o0], %g1, %g7
1598c2ecf20Sopenharmony_ci	cmp	%g1, %g7
1608c2ecf20Sopenharmony_ci	bne,pn	%xcc, BACKOFF_LABEL(2f, 1b)
1618c2ecf20Sopenharmony_ci	 nop
1628c2ecf20Sopenharmony_ci3:	retl
1638c2ecf20Sopenharmony_ci	 sub	%g1, 1, %o0
1648c2ecf20Sopenharmony_ci2:	BACKOFF_SPIN(%o2, %o3, 1b)
1658c2ecf20Sopenharmony_ciENDPROC(atomic64_dec_if_positive)
1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_dec_if_positive)
167