162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __ASM_SH_ATOMIC_LLSC_H
362306a36Sopenharmony_ci#define __ASM_SH_ATOMIC_LLSC_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * SH-4A note:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * We basically get atomic_xxx_return() for free compared with
962306a36Sopenharmony_ci * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
1062306a36Sopenharmony_ci * encoding, so the retval is automatically set without having to
1162306a36Sopenharmony_ci * do any special work.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * To get proper branch prediction for the main line, we must branch
1562306a36Sopenharmony_ci * forward to code at the end of this object's .text section, then
1662306a36Sopenharmony_ci * branch back to restart the operation.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define ATOMIC_OP(op)							\
2062306a36Sopenharmony_cistatic inline void arch_atomic_##op(int i, atomic_t *v)			\
2162306a36Sopenharmony_ci{									\
2262306a36Sopenharmony_ci	unsigned long tmp;						\
2362306a36Sopenharmony_ci									\
2462306a36Sopenharmony_ci	__asm__ __volatile__ (						\
2562306a36Sopenharmony_ci"1:	movli.l @%2, %0		! atomic_" #op "\n"			\
2662306a36Sopenharmony_ci"	" #op "	%1, %0				\n"			\
2762306a36Sopenharmony_ci"	movco.l	%0, @%2				\n"			\
2862306a36Sopenharmony_ci"	bf	1b				\n"			\
2962306a36Sopenharmony_ci	: "=&z" (tmp)							\
3062306a36Sopenharmony_ci	: "r" (i), "r" (&v->counter)					\
3162306a36Sopenharmony_ci	: "t");								\
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op)						\
3562306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return(int i, atomic_t *v)		\
3662306a36Sopenharmony_ci{									\
3762306a36Sopenharmony_ci	unsigned long temp;						\
3862306a36Sopenharmony_ci									\
3962306a36Sopenharmony_ci	__asm__ __volatile__ (						\
4062306a36Sopenharmony_ci"1:	movli.l @%2, %0		! atomic_" #op "_return	\n"		\
4162306a36Sopenharmony_ci"	" #op "	%1, %0					\n"		\
4262306a36Sopenharmony_ci"	movco.l	%0, @%2					\n"		\
4362306a36Sopenharmony_ci"	bf	1b					\n"		\
4462306a36Sopenharmony_ci"	synco						\n"		\
4562306a36Sopenharmony_ci	: "=&z" (temp)							\
4662306a36Sopenharmony_ci	: "r" (i), "r" (&v->counter)					\
4762306a36Sopenharmony_ci	: "t");								\
4862306a36Sopenharmony_ci									\
4962306a36Sopenharmony_ci	return temp;							\
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op)						\
5362306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op(int i, atomic_t *v)		\
5462306a36Sopenharmony_ci{									\
5562306a36Sopenharmony_ci	unsigned long res, temp;					\
5662306a36Sopenharmony_ci									\
5762306a36Sopenharmony_ci	__asm__ __volatile__ (						\
5862306a36Sopenharmony_ci"1:	movli.l @%3, %0		! atomic_fetch_" #op "	\n"		\
5962306a36Sopenharmony_ci"	mov %0, %1					\n"		\
6062306a36Sopenharmony_ci"	" #op "	%2, %0					\n"		\
6162306a36Sopenharmony_ci"	movco.l	%0, @%3					\n"		\
6262306a36Sopenharmony_ci"	bf	1b					\n"		\
6362306a36Sopenharmony_ci"	synco						\n"		\
6462306a36Sopenharmony_ci	: "=&z" (temp), "=&r" (res)					\
6562306a36Sopenharmony_ci	: "r" (i), "r" (&v->counter)					\
6662306a36Sopenharmony_ci	: "t");								\
6762306a36Sopenharmony_ci									\
6862306a36Sopenharmony_ci	return res;							\
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciATOMIC_OPS(add)
7462306a36Sopenharmony_ciATOMIC_OPS(sub)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define arch_atomic_add_return	arch_atomic_add_return
7762306a36Sopenharmony_ci#define arch_atomic_sub_return	arch_atomic_sub_return
7862306a36Sopenharmony_ci#define arch_atomic_fetch_add	arch_atomic_fetch_add
7962306a36Sopenharmony_ci#define arch_atomic_fetch_sub	arch_atomic_fetch_sub
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#undef ATOMIC_OPS
8262306a36Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ciATOMIC_OPS(and)
8562306a36Sopenharmony_ciATOMIC_OPS(or)
8662306a36Sopenharmony_ciATOMIC_OPS(xor)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define arch_atomic_fetch_and	arch_atomic_fetch_and
8962306a36Sopenharmony_ci#define arch_atomic_fetch_or	arch_atomic_fetch_or
9062306a36Sopenharmony_ci#define arch_atomic_fetch_xor	arch_atomic_fetch_xor
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#undef ATOMIC_OPS
9362306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP
9462306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN
9562306a36Sopenharmony_ci#undef ATOMIC_OP
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#endif /* __ASM_SH_ATOMIC_LLSC_H */
98