18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#ifndef __ASM_CSKY_ATOMIC_H
48c2ecf20Sopenharmony_ci#define __ASM_CSKY_ATOMIC_H
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/version.h>
78c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
88c2ecf20Sopenharmony_ci#include <asm/barrier.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_HAS_LDSTEX
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define __atomic_add_unless __atomic_add_unless
138c2ecf20Sopenharmony_cistatic inline int __atomic_add_unless(atomic_t *v, int a, int u)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	unsigned long tmp, ret;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	smp_mb();
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	asm volatile (
208c2ecf20Sopenharmony_ci	"1:	ldex.w		%0, (%3) \n"
218c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"
228c2ecf20Sopenharmony_ci	"	cmpne		%0, %4   \n"
238c2ecf20Sopenharmony_ci	"	bf		2f	 \n"
248c2ecf20Sopenharmony_ci	"	add		%0, %2   \n"
258c2ecf20Sopenharmony_ci	"	stex.w		%0, (%3) \n"
268c2ecf20Sopenharmony_ci	"	bez		%0, 1b   \n"
278c2ecf20Sopenharmony_ci	"2:				 \n"
288c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)
298c2ecf20Sopenharmony_ci		: "r" (a), "r"(&v->counter), "r"(u)
308c2ecf20Sopenharmony_ci		: "memory");
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (ret != u)
338c2ecf20Sopenharmony_ci		smp_mb();
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return ret;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op)						\
398c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v)			\
408c2ecf20Sopenharmony_ci{									\
418c2ecf20Sopenharmony_ci	unsigned long tmp;						\
428c2ecf20Sopenharmony_ci									\
438c2ecf20Sopenharmony_ci	asm volatile (							\
448c2ecf20Sopenharmony_ci	"1:	ldex.w		%0, (%2) \n"				\
458c2ecf20Sopenharmony_ci	"	" #op "		%0, %1   \n"				\
468c2ecf20Sopenharmony_ci	"	stex.w		%0, (%2) \n"				\
478c2ecf20Sopenharmony_ci	"	bez		%0, 1b   \n"				\
488c2ecf20Sopenharmony_ci		: "=&r" (tmp)						\
498c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
508c2ecf20Sopenharmony_ci		: "memory");						\
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op)					\
548c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v)		\
558c2ecf20Sopenharmony_ci{									\
568c2ecf20Sopenharmony_ci	unsigned long tmp, ret;						\
578c2ecf20Sopenharmony_ci									\
588c2ecf20Sopenharmony_ci	smp_mb();							\
598c2ecf20Sopenharmony_ci	asm volatile (							\
608c2ecf20Sopenharmony_ci	"1:	ldex.w		%0, (%3) \n"				\
618c2ecf20Sopenharmony_ci	"	" #op "		%0, %2   \n"				\
628c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"				\
638c2ecf20Sopenharmony_ci	"	stex.w		%0, (%3) \n"				\
648c2ecf20Sopenharmony_ci	"	bez		%0, 1b   \n"				\
658c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)				\
668c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
678c2ecf20Sopenharmony_ci		: "memory");						\
688c2ecf20Sopenharmony_ci	smp_mb();							\
698c2ecf20Sopenharmony_ci									\
708c2ecf20Sopenharmony_ci	return ret;							\
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op)					\
748c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v)			\
758c2ecf20Sopenharmony_ci{									\
768c2ecf20Sopenharmony_ci	unsigned long tmp, ret;						\
778c2ecf20Sopenharmony_ci									\
788c2ecf20Sopenharmony_ci	smp_mb();							\
798c2ecf20Sopenharmony_ci	asm volatile (							\
808c2ecf20Sopenharmony_ci	"1:	ldex.w		%0, (%3) \n"				\
818c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"				\
828c2ecf20Sopenharmony_ci	"	" #op "		%0, %2   \n"				\
838c2ecf20Sopenharmony_ci	"	stex.w		%0, (%3) \n"				\
848c2ecf20Sopenharmony_ci	"	bez		%0, 1b   \n"				\
858c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)				\
868c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
878c2ecf20Sopenharmony_ci		: "memory");						\
888c2ecf20Sopenharmony_ci	smp_mb();							\
898c2ecf20Sopenharmony_ci									\
908c2ecf20Sopenharmony_ci	return ret;							\
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#else /* CONFIG_CPU_HAS_LDSTEX */
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#include <linux/irqflags.h>
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#define __atomic_add_unless __atomic_add_unless
988c2ecf20Sopenharmony_cistatic inline int __atomic_add_unless(atomic_t *v, int a, int u)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	unsigned long tmp, ret, flags;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	raw_local_irq_save(flags);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	asm volatile (
1058c2ecf20Sopenharmony_ci	"	ldw		%0, (%3) \n"
1068c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"
1078c2ecf20Sopenharmony_ci	"	cmpne		%0, %4   \n"
1088c2ecf20Sopenharmony_ci	"	bf		2f	 \n"
1098c2ecf20Sopenharmony_ci	"	add		%0, %2   \n"
1108c2ecf20Sopenharmony_ci	"	stw		%0, (%3) \n"
1118c2ecf20Sopenharmony_ci	"2:				 \n"
1128c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)
1138c2ecf20Sopenharmony_ci		: "r" (a), "r"(&v->counter), "r"(u)
1148c2ecf20Sopenharmony_ci		: "memory");
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	raw_local_irq_restore(flags);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return ret;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op)						\
1228c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v)			\
1238c2ecf20Sopenharmony_ci{									\
1248c2ecf20Sopenharmony_ci	unsigned long tmp, flags;					\
1258c2ecf20Sopenharmony_ci									\
1268c2ecf20Sopenharmony_ci	raw_local_irq_save(flags);					\
1278c2ecf20Sopenharmony_ci									\
1288c2ecf20Sopenharmony_ci	asm volatile (							\
1298c2ecf20Sopenharmony_ci	"	ldw		%0, (%2) \n"				\
1308c2ecf20Sopenharmony_ci	"	" #op "		%0, %1   \n"				\
1318c2ecf20Sopenharmony_ci	"	stw		%0, (%2) \n"				\
1328c2ecf20Sopenharmony_ci		: "=&r" (tmp)						\
1338c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
1348c2ecf20Sopenharmony_ci		: "memory");						\
1358c2ecf20Sopenharmony_ci									\
1368c2ecf20Sopenharmony_ci	raw_local_irq_restore(flags);					\
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op)					\
1408c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v)		\
1418c2ecf20Sopenharmony_ci{									\
1428c2ecf20Sopenharmony_ci	unsigned long tmp, ret, flags;					\
1438c2ecf20Sopenharmony_ci									\
1448c2ecf20Sopenharmony_ci	raw_local_irq_save(flags);					\
1458c2ecf20Sopenharmony_ci									\
1468c2ecf20Sopenharmony_ci	asm volatile (							\
1478c2ecf20Sopenharmony_ci	"	ldw		%0, (%3) \n"				\
1488c2ecf20Sopenharmony_ci	"	" #op "		%0, %2   \n"				\
1498c2ecf20Sopenharmony_ci	"	stw		%0, (%3) \n"				\
1508c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"				\
1518c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)				\
1528c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
1538c2ecf20Sopenharmony_ci		: "memory");						\
1548c2ecf20Sopenharmony_ci									\
1558c2ecf20Sopenharmony_ci	raw_local_irq_restore(flags);					\
1568c2ecf20Sopenharmony_ci									\
1578c2ecf20Sopenharmony_ci	return ret;							\
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op)					\
1618c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v)			\
1628c2ecf20Sopenharmony_ci{									\
1638c2ecf20Sopenharmony_ci	unsigned long tmp, ret, flags;					\
1648c2ecf20Sopenharmony_ci									\
1658c2ecf20Sopenharmony_ci	raw_local_irq_save(flags);					\
1668c2ecf20Sopenharmony_ci									\
1678c2ecf20Sopenharmony_ci	asm volatile (							\
1688c2ecf20Sopenharmony_ci	"	ldw		%0, (%3) \n"				\
1698c2ecf20Sopenharmony_ci	"	mov		%1, %0   \n"				\
1708c2ecf20Sopenharmony_ci	"	" #op "		%0, %2   \n"				\
1718c2ecf20Sopenharmony_ci	"	stw		%0, (%3) \n"				\
1728c2ecf20Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)				\
1738c2ecf20Sopenharmony_ci		: "r" (i), "r"(&v->counter)				\
1748c2ecf20Sopenharmony_ci		: "memory");						\
1758c2ecf20Sopenharmony_ci									\
1768c2ecf20Sopenharmony_ci	raw_local_irq_restore(flags);					\
1778c2ecf20Sopenharmony_ci									\
1788c2ecf20Sopenharmony_ci	return ret;							\
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#endif /* CONFIG_CPU_HAS_LDSTEX */
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci#define atomic_add_return atomic_add_return
1848c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(add, +)
1858c2ecf20Sopenharmony_ci#define atomic_sub_return atomic_sub_return
1868c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(sub, -)
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci#define atomic_fetch_add atomic_fetch_add
1898c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(add, +)
1908c2ecf20Sopenharmony_ci#define atomic_fetch_sub atomic_fetch_sub
1918c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(sub, -)
1928c2ecf20Sopenharmony_ci#define atomic_fetch_and atomic_fetch_and
1938c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and, &)
1948c2ecf20Sopenharmony_ci#define atomic_fetch_or atomic_fetch_or
1958c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or, |)
1968c2ecf20Sopenharmony_ci#define atomic_fetch_xor atomic_fetch_xor
1978c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor, ^)
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci#define atomic_and atomic_and
2008c2ecf20Sopenharmony_ciATOMIC_OP(and, &)
2018c2ecf20Sopenharmony_ci#define atomic_or atomic_or
2028c2ecf20Sopenharmony_ciATOMIC_OP(or, |)
2038c2ecf20Sopenharmony_ci#define atomic_xor atomic_xor
2048c2ecf20Sopenharmony_ciATOMIC_OP(xor, ^)
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
2078c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
2088c2ecf20Sopenharmony_ci#undef ATOMIC_OP
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#include <asm-generic/atomic.h>
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci#endif /* __ASM_CSKY_ATOMIC_H */
213