162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#ifndef __ASM_CSKY_ATOMIC_H
462306a36Sopenharmony_ci#define __ASM_CSKY_ATOMIC_H
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifdef CONFIG_SMP
762306a36Sopenharmony_ci#include <asm-generic/atomic64.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/cmpxchg.h>
1062306a36Sopenharmony_ci#include <asm/barrier.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define __atomic_acquire_fence()	__bar_brarw()
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define __atomic_release_fence()	__bar_brwaw()
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic __always_inline int arch_atomic_read(const atomic_t *v)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	return READ_ONCE(v->counter);
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_cistatic __always_inline void arch_atomic_set(atomic_t *v, int i)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	WRITE_ONCE(v->counter, i);
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define ATOMIC_OP(op)							\
2662306a36Sopenharmony_cistatic __always_inline							\
2762306a36Sopenharmony_civoid arch_atomic_##op(int i, atomic_t *v)				\
2862306a36Sopenharmony_ci{									\
2962306a36Sopenharmony_ci	unsigned long tmp;						\
3062306a36Sopenharmony_ci	__asm__ __volatile__ (						\
3162306a36Sopenharmony_ci	"1:	ldex.w		%0, (%2)	\n"			\
3262306a36Sopenharmony_ci	"	" #op "		%0, %1		\n"			\
3362306a36Sopenharmony_ci	"	stex.w		%0, (%2)	\n"			\
3462306a36Sopenharmony_ci	"	bez		%0, 1b		\n"			\
3562306a36Sopenharmony_ci	: "=&r" (tmp)							\
3662306a36Sopenharmony_ci	: "r" (i), "r" (&v->counter)					\
3762306a36Sopenharmony_ci	: "memory");							\
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciATOMIC_OP(add)
4162306a36Sopenharmony_ciATOMIC_OP(sub)
4262306a36Sopenharmony_ciATOMIC_OP(and)
4362306a36Sopenharmony_ciATOMIC_OP( or)
4462306a36Sopenharmony_ciATOMIC_OP(xor)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#undef ATOMIC_OP
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
4962306a36Sopenharmony_cistatic __always_inline							\
5062306a36Sopenharmony_ciint arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v)		\
5162306a36Sopenharmony_ci{									\
5262306a36Sopenharmony_ci	register int ret, tmp;						\
5362306a36Sopenharmony_ci	__asm__ __volatile__ (						\
5462306a36Sopenharmony_ci	"1:	ldex.w		%0, (%3) \n"				\
5562306a36Sopenharmony_ci	"	mov		%1, %0   \n"				\
5662306a36Sopenharmony_ci	"	" #op "		%0, %2   \n"				\
5762306a36Sopenharmony_ci	"	stex.w		%0, (%3) \n"				\
5862306a36Sopenharmony_ci	"	bez		%0, 1b   \n"				\
5962306a36Sopenharmony_ci		: "=&r" (tmp), "=&r" (ret)				\
6062306a36Sopenharmony_ci		: "r" (i), "r"(&v->counter) 				\
6162306a36Sopenharmony_ci		: "memory");						\
6262306a36Sopenharmony_ci	return ret;							\
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op)					\
6662306a36Sopenharmony_cistatic __always_inline							\
6762306a36Sopenharmony_ciint arch_atomic_##op##_return_relaxed(int i, atomic_t *v)		\
6862306a36Sopenharmony_ci{									\
6962306a36Sopenharmony_ci	return arch_atomic_fetch_##op##_relaxed(i, v) c_op i;		\
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define ATOMIC_OPS(op, c_op)						\
7362306a36Sopenharmony_ci	ATOMIC_FETCH_OP(op)						\
7462306a36Sopenharmony_ci	ATOMIC_OP_RETURN(op, c_op)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciATOMIC_OPS(add, +)
7762306a36Sopenharmony_ciATOMIC_OPS(sub, -)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define arch_atomic_fetch_add_relaxed	arch_atomic_fetch_add_relaxed
8062306a36Sopenharmony_ci#define arch_atomic_fetch_sub_relaxed	arch_atomic_fetch_sub_relaxed
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define arch_atomic_add_return_relaxed	arch_atomic_add_return_relaxed
8362306a36Sopenharmony_ci#define arch_atomic_sub_return_relaxed	arch_atomic_sub_return_relaxed
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#undef ATOMIC_OPS
8662306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define ATOMIC_OPS(op)							\
8962306a36Sopenharmony_ci	ATOMIC_FETCH_OP(op)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciATOMIC_OPS(and)
9262306a36Sopenharmony_ciATOMIC_OPS( or)
9362306a36Sopenharmony_ciATOMIC_OPS(xor)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define arch_atomic_fetch_and_relaxed	arch_atomic_fetch_and_relaxed
9662306a36Sopenharmony_ci#define arch_atomic_fetch_or_relaxed	arch_atomic_fetch_or_relaxed
9762306a36Sopenharmony_ci#define arch_atomic_fetch_xor_relaxed	arch_atomic_fetch_xor_relaxed
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#undef ATOMIC_OPS
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic __always_inline int
10462306a36Sopenharmony_ciarch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	int prev, tmp;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	__asm__ __volatile__ (
10962306a36Sopenharmony_ci		RELEASE_FENCE
11062306a36Sopenharmony_ci		"1:	ldex.w		%0, (%3)	\n"
11162306a36Sopenharmony_ci		"	cmpne		%0, %4		\n"
11262306a36Sopenharmony_ci		"	bf		2f		\n"
11362306a36Sopenharmony_ci		"	mov		%1, %0		\n"
11462306a36Sopenharmony_ci		"	add		%1, %2		\n"
11562306a36Sopenharmony_ci		"	stex.w		%1, (%3)	\n"
11662306a36Sopenharmony_ci		"	bez		%1, 1b		\n"
11762306a36Sopenharmony_ci		FULL_FENCE
11862306a36Sopenharmony_ci		"2:\n"
11962306a36Sopenharmony_ci		: "=&r" (prev), "=&r" (tmp)
12062306a36Sopenharmony_ci		: "r" (a), "r" (&v->counter), "r" (u)
12162306a36Sopenharmony_ci		: "memory");
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return prev;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic __always_inline bool
12862306a36Sopenharmony_ciarch_atomic_inc_unless_negative(atomic_t *v)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	int rc, tmp;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	__asm__ __volatile__ (
13362306a36Sopenharmony_ci		RELEASE_FENCE
13462306a36Sopenharmony_ci		"1:	ldex.w		%0, (%2)	\n"
13562306a36Sopenharmony_ci		"	movi		%1, 0		\n"
13662306a36Sopenharmony_ci		"	blz		%0, 2f		\n"
13762306a36Sopenharmony_ci		"	movi		%1, 1		\n"
13862306a36Sopenharmony_ci		"	addi		%0, 1		\n"
13962306a36Sopenharmony_ci		"	stex.w		%0, (%2)	\n"
14062306a36Sopenharmony_ci		"	bez		%0, 1b		\n"
14162306a36Sopenharmony_ci		FULL_FENCE
14262306a36Sopenharmony_ci		"2:\n"
14362306a36Sopenharmony_ci		: "=&r" (tmp), "=&r" (rc)
14462306a36Sopenharmony_ci		: "r" (&v->counter)
14562306a36Sopenharmony_ci		: "memory");
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return tmp ? true : false;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci#define arch_atomic_inc_unless_negative arch_atomic_inc_unless_negative
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic __always_inline bool
15362306a36Sopenharmony_ciarch_atomic_dec_unless_positive(atomic_t *v)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	int rc, tmp;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	__asm__ __volatile__ (
15862306a36Sopenharmony_ci		RELEASE_FENCE
15962306a36Sopenharmony_ci		"1:	ldex.w		%0, (%2)	\n"
16062306a36Sopenharmony_ci		"	movi		%1, 0		\n"
16162306a36Sopenharmony_ci		"	bhz		%0, 2f		\n"
16262306a36Sopenharmony_ci		"	movi		%1, 1		\n"
16362306a36Sopenharmony_ci		"	subi		%0, 1		\n"
16462306a36Sopenharmony_ci		"	stex.w		%0, (%2)	\n"
16562306a36Sopenharmony_ci		"	bez		%0, 1b		\n"
16662306a36Sopenharmony_ci		FULL_FENCE
16762306a36Sopenharmony_ci		"2:\n"
16862306a36Sopenharmony_ci		: "=&r" (tmp), "=&r" (rc)
16962306a36Sopenharmony_ci		: "r" (&v->counter)
17062306a36Sopenharmony_ci		: "memory");
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return tmp ? true : false;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci#define arch_atomic_dec_unless_positive arch_atomic_dec_unless_positive
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic __always_inline int
17762306a36Sopenharmony_ciarch_atomic_dec_if_positive(atomic_t *v)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int dec, tmp;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	__asm__ __volatile__ (
18262306a36Sopenharmony_ci		RELEASE_FENCE
18362306a36Sopenharmony_ci		"1:	ldex.w		%0, (%2)	\n"
18462306a36Sopenharmony_ci		"	subi		%1, %0, 1	\n"
18562306a36Sopenharmony_ci		"	blz		%1, 2f		\n"
18662306a36Sopenharmony_ci		"	stex.w		%1, (%2)	\n"
18762306a36Sopenharmony_ci		"	bez		%1, 1b		\n"
18862306a36Sopenharmony_ci		FULL_FENCE
18962306a36Sopenharmony_ci		"2:\n"
19062306a36Sopenharmony_ci		: "=&r" (dec), "=&r" (tmp)
19162306a36Sopenharmony_ci		: "r" (&v->counter)
19262306a36Sopenharmony_ci		: "memory");
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return dec - 1;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci#define arch_atomic_dec_if_positive arch_atomic_dec_if_positive
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#else
19962306a36Sopenharmony_ci#include <asm-generic/atomic.h>
20062306a36Sopenharmony_ci#endif
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#endif /* __ASM_CSKY_ATOMIC_H */
203