202 lines · 4.3 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __ASM_CSKY_ATOMIC_H#define __ASM_CSKY_ATOMIC_H #ifdef CONFIG_SMP#include <asm-generic/atomic64.h> #include <asm/cmpxchg.h>#include <asm/barrier.h> #define __atomic_acquire_fence()	__bar_brarw() #define __atomic_release_fence()	__bar_brwaw() static __always_inline int arch_atomic_read(const atomic_t *v){	return READ_ONCE(v->counter);}static __always_inline void arch_atomic_set(atomic_t *v, int i){	WRITE_ONCE(v->counter, i);} #define ATOMIC_OP(op)							\static __always_inline							\void arch_atomic_##op(int i, atomic_t *v)				\{									\	unsigned long tmp;						\	__asm__ __volatile__ (						\	"1:	ldex.w		%0, (%2)	\n"			\	"	" #op "		%0, %1		\n"			\	"	stex.w		%0, (%2)	\n"			\	"	bez		%0, 1b		\n"			\	: "=&r" (tmp)							\	: "r" (i), "r" (&v->counter)					\	: "memory");							\} ATOMIC_OP(add)ATOMIC_OP(sub)ATOMIC_OP(and)ATOMIC_OP( or)ATOMIC_OP(xor) #undef ATOMIC_OP #define ATOMIC_FETCH_OP(op)						\static __always_inline							\int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v)		\{									\	register int ret, tmp;						\	__asm__ __volatile__ (						\	"1:	ldex.w		%0, (%3) \n"				\	"	mov		%1, %0   \n"				\	"	" #op "		%0, %2   \n"				\	"	stex.w		%0, (%3) \n"				\	"	bez		%0, 1b   \n"				\		: "=&r" (tmp), "=&r" (ret)				\		: "r" (i), "r"(&v->counter) 				\		: "memory");						\	return ret;							\} #define ATOMIC_OP_RETURN(op, c_op)					\static __always_inline							\int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)		\{									\	return arch_atomic_fetch_##op##_relaxed(i, v) c_op i;		\} #define ATOMIC_OPS(op, c_op)						\	ATOMIC_FETCH_OP(op)						\	ATOMIC_OP_RETURN(op, c_op) ATOMIC_OPS(add, +)ATOMIC_OPS(sub, -) #define arch_atomic_fetch_add_relaxed	arch_atomic_fetch_add_relaxed#define arch_atomic_fetch_sub_relaxed	arch_atomic_fetch_sub_relaxed #define arch_atomic_add_return_relaxed	arch_atomic_add_return_relaxed#define arch_atomic_sub_return_relaxed	arch_atomic_sub_return_relaxed #undef ATOMIC_OPS#undef ATOMIC_OP_RETURN #define ATOMIC_OPS(op)							\	ATOMIC_FETCH_OP(op) ATOMIC_OPS(and)ATOMIC_OPS( or)ATOMIC_OPS(xor) #define arch_atomic_fetch_and_relaxed	arch_atomic_fetch_and_relaxed#define arch_atomic_fetch_or_relaxed	arch_atomic_fetch_or_relaxed#define arch_atomic_fetch_xor_relaxed	arch_atomic_fetch_xor_relaxed #undef ATOMIC_OPS #undef ATOMIC_FETCH_OP static __always_inline intarch_atomic_fetch_add_unless(atomic_t *v, int a, int u){	int prev, tmp; 	__asm__ __volatile__ (		RELEASE_FENCE		"1:	ldex.w		%0, (%3)	\n"		"	cmpne		%0, %4		\n"		"	bf		2f		\n"		"	mov		%1, %0		\n"		"	add		%1, %2		\n"		"	stex.w		%1, (%3)	\n"		"	bez		%1, 1b		\n"		FULL_FENCE		"2:\n"		: "=&r" (prev), "=&r" (tmp)		: "r" (a), "r" (&v->counter), "r" (u)		: "memory"); 	return prev;}#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless static __always_inline boolarch_atomic_inc_unless_negative(atomic_t *v){	int rc, tmp; 	__asm__ __volatile__ (		RELEASE_FENCE		"1:	ldex.w		%0, (%2)	\n"		"	movi		%1, 0		\n"		"	blz		%0, 2f		\n"		"	movi		%1, 1		\n"		"	addi		%0, 1		\n"		"	stex.w		%0, (%2)	\n"		"	bez		%0, 1b		\n"		FULL_FENCE		"2:\n"		: "=&r" (tmp), "=&r" (rc)		: "r" (&v->counter)		: "memory"); 	return tmp ? true : false; }#define arch_atomic_inc_unless_negative arch_atomic_inc_unless_negative static __always_inline boolarch_atomic_dec_unless_positive(atomic_t *v){	int rc, tmp; 	__asm__ __volatile__ (		RELEASE_FENCE		"1:	ldex.w		%0, (%2)	\n"		"	movi		%1, 0		\n"		"	bhz		%0, 2f		\n"		"	movi		%1, 1		\n"		"	subi		%0, 1		\n"		"	stex.w		%0, (%2)	\n"		"	bez		%0, 1b		\n"		FULL_FENCE		"2:\n"		: "=&r" (tmp), "=&r" (rc)		: "r" (&v->counter)		: "memory"); 	return tmp ? true : false;}#define arch_atomic_dec_unless_positive arch_atomic_dec_unless_positive static __always_inline intarch_atomic_dec_if_positive(atomic_t *v){	int dec, tmp; 	__asm__ __volatile__ (		RELEASE_FENCE		"1:	ldex.w		%0, (%2)	\n"		"	subi		%1, %0, 1	\n"		"	blz		%1, 2f		\n"		"	stex.w		%1, (%2)	\n"		"	bez		%1, 1b		\n"		FULL_FENCE		"2:\n"		: "=&r" (dec), "=&r" (tmp)		: "r" (&v->counter)		: "memory"); 	return dec - 1;}#define arch_atomic_dec_if_positive arch_atomic_dec_if_positive #else#include <asm-generic/atomic.h>#endif #endif /* __ASM_CSKY_ATOMIC_H */