18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for
48c2ecf20Sopenharmony_ci * resource counting etc..
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * But use these as seldom as possible since they are much more slower
78c2ecf20Sopenharmony_ci * than regular operations.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
108c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
118c2ecf20Sopenharmony_ci * for more details.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci#ifndef _ASM_ATOMIC_H
168c2ecf20Sopenharmony_ci#define _ASM_ATOMIC_H
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/types.h>
198c2ecf20Sopenharmony_ci#include <asm/barrier.h>
208c2ecf20Sopenharmony_ci#include <asm/cpu-features.h>
218c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#if __SIZEOF_LONG__ == 4
248c2ecf20Sopenharmony_ci#define __LL		"ll.w	"
258c2ecf20Sopenharmony_ci#define __SC		"sc.w	"
268c2ecf20Sopenharmony_ci#define __AMADD		"amadd.w	"
278c2ecf20Sopenharmony_ci#define __AMAND_DB	"amand_db.w	"
288c2ecf20Sopenharmony_ci#define __AMOR_DB	"amor_db.w	"
298c2ecf20Sopenharmony_ci#define __AMXOR_DB	"amxor_db.w	"
308c2ecf20Sopenharmony_ci#elif __SIZEOF_LONG__ == 8
318c2ecf20Sopenharmony_ci#define __LL		"ll.d	"
328c2ecf20Sopenharmony_ci#define __SC		"sc.d	"
338c2ecf20Sopenharmony_ci#define __AMADD		"amadd.d	"
348c2ecf20Sopenharmony_ci#define __AMAND_DB	"amand_db.d	"
358c2ecf20Sopenharmony_ci#define __AMOR_DB	"amor_db.d	"
368c2ecf20Sopenharmony_ci#define __AMXOR_DB	"amxor_db.d	"
378c2ecf20Sopenharmony_ci#endif
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define ATOMIC_INIT(i)	  { (i) }
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * atomic_read - read atomic variable
438c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * Atomically reads the value of @v.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci#define atomic_read(v)		READ_ONCE((v)->counter)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * atomic_set - set atomic variable
518c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
528c2ecf20Sopenharmony_ci * @i: required value
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * Atomically sets the value of @v to @i.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci#define atomic_set(v, i)	WRITE_ONCE((v)->counter, (i))
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, I, asm_op)					\
598c2ecf20Sopenharmony_cistatic __inline__ void atomic_##op(int i, atomic_t * v)			\
608c2ecf20Sopenharmony_ci{									\
618c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
628c2ecf20Sopenharmony_ci	"am"#asm_op".w" " $zero, %1, %0	\n"				\
638c2ecf20Sopenharmony_ci	: "+ZB" (v->counter)				   		\
648c2ecf20Sopenharmony_ci	: "r" (I)							\
658c2ecf20Sopenharmony_ci	: "memory");						   	\
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op, I, asm_op, c_op, mb, suffix)		\
698c2ecf20Sopenharmony_cistatic __inline__ int atomic_##op##_return##suffix(int i, atomic_t * v)	\
708c2ecf20Sopenharmony_ci{									\
718c2ecf20Sopenharmony_ci	int result;							\
728c2ecf20Sopenharmony_ci									\
738c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
748c2ecf20Sopenharmony_ci	"am"#asm_op#mb".w" " %1, %2, %0		\n"			\
758c2ecf20Sopenharmony_ci	: "+ZB" (v->counter), "=&r" (result)				\
768c2ecf20Sopenharmony_ci	: "r" (I)							\
778c2ecf20Sopenharmony_ci	: "memory");							\
788c2ecf20Sopenharmony_ci									\
798c2ecf20Sopenharmony_ci	return result c_op I;						\
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, I, asm_op, mb, suffix)			\
838c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_##op##suffix(int i, atomic_t * v)	\
848c2ecf20Sopenharmony_ci{									\
858c2ecf20Sopenharmony_ci	int result;							\
868c2ecf20Sopenharmony_ci									\
878c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
888c2ecf20Sopenharmony_ci	"am"#asm_op#mb".w" " %1, %2, %0		\n"			\
898c2ecf20Sopenharmony_ci	: "+ZB" (v->counter), "=&r" (result)				\
908c2ecf20Sopenharmony_ci	: "r" (I)							\
918c2ecf20Sopenharmony_ci	: "memory");							\
928c2ecf20Sopenharmony_ci									\
938c2ecf20Sopenharmony_ci	return result;							\
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, I, asm_op, c_op)					\
978c2ecf20Sopenharmony_ci	ATOMIC_OP(op, I, asm_op)					\
988c2ecf20Sopenharmony_ci	ATOMIC_OP_RETURN(op, I, asm_op, c_op, _db,         )		\
998c2ecf20Sopenharmony_ci	ATOMIC_OP_RETURN(op, I, asm_op, c_op,    , _relaxed)		\
1008c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, I, asm_op, _db,         )			\
1018c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, I, asm_op,    , _relaxed)
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciATOMIC_OPS(add, i, add, +)
1048c2ecf20Sopenharmony_ciATOMIC_OPS(sub, -i, add, +)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define atomic_add_return		atomic_add_return
1078c2ecf20Sopenharmony_ci#define atomic_add_return_acquire	atomic_add_return
1088c2ecf20Sopenharmony_ci#define atomic_add_return_release	atomic_add_return
1098c2ecf20Sopenharmony_ci#define atomic_add_return_relaxed	atomic_add_return_relaxed
1108c2ecf20Sopenharmony_ci#define atomic_sub_return		atomic_sub_return
1118c2ecf20Sopenharmony_ci#define atomic_sub_return_acquire	atomic_sub_return
1128c2ecf20Sopenharmony_ci#define atomic_sub_return_release	atomic_sub_return
1138c2ecf20Sopenharmony_ci#define atomic_sub_return_relaxed	atomic_sub_return_relaxed
1148c2ecf20Sopenharmony_ci#define atomic_fetch_add		atomic_fetch_add
1158c2ecf20Sopenharmony_ci#define atomic_fetch_add_acquire	atomic_fetch_add
1168c2ecf20Sopenharmony_ci#define atomic_fetch_add_release	atomic_fetch_add
1178c2ecf20Sopenharmony_ci#define atomic_fetch_add_relaxed	atomic_fetch_add_relaxed
1188c2ecf20Sopenharmony_ci#define atomic_fetch_sub		atomic_fetch_sub
1198c2ecf20Sopenharmony_ci#define atomic_fetch_sub_acquire	atomic_fetch_sub
1208c2ecf20Sopenharmony_ci#define atomic_fetch_sub_release	atomic_fetch_sub
1218c2ecf20Sopenharmony_ci#define atomic_fetch_sub_relaxed	atomic_fetch_sub_relaxed
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, I, asm_op)					\
1268c2ecf20Sopenharmony_ci	ATOMIC_OP(op, I, asm_op)					\
1278c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, I, asm_op, _db,         )			\
1288c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, I, asm_op,    , _relaxed)
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciATOMIC_OPS(and, i, and)
1318c2ecf20Sopenharmony_ciATOMIC_OPS(or, i, or)
1328c2ecf20Sopenharmony_ciATOMIC_OPS(xor, i, xor)
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define atomic_fetch_and		atomic_fetch_and
1358c2ecf20Sopenharmony_ci#define atomic_fetch_and_acquire	atomic_fetch_and
1368c2ecf20Sopenharmony_ci#define atomic_fetch_and_release	atomic_fetch_and
1378c2ecf20Sopenharmony_ci#define atomic_fetch_and_relaxed	atomic_fetch_and_relaxed
1388c2ecf20Sopenharmony_ci#define atomic_fetch_or			atomic_fetch_or
1398c2ecf20Sopenharmony_ci#define atomic_fetch_or_acquire		atomic_fetch_or
1408c2ecf20Sopenharmony_ci#define atomic_fetch_or_release		atomic_fetch_or
1418c2ecf20Sopenharmony_ci#define atomic_fetch_or_relaxed		atomic_fetch_or_relaxed
1428c2ecf20Sopenharmony_ci#define atomic_fetch_xor		atomic_fetch_xor
1438c2ecf20Sopenharmony_ci#define atomic_fetch_xor_acquire	atomic_fetch_xor
1448c2ecf20Sopenharmony_ci#define atomic_fetch_xor_release	atomic_fetch_xor
1458c2ecf20Sopenharmony_ci#define atomic_fetch_xor_relaxed	atomic_fetch_xor_relaxed
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1488c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
1498c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN
1508c2ecf20Sopenharmony_ci#undef ATOMIC_OP
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci       int prev, rc;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
1578c2ecf20Sopenharmony_ci		"0:	ll.w	%[p],  %[c]\n"
1588c2ecf20Sopenharmony_ci		"	beq	%[p],  %[u], 1f\n"
1598c2ecf20Sopenharmony_ci		"	add.w	%[rc], %[p], %[a]\n"
1608c2ecf20Sopenharmony_ci		"	sc.w	%[rc], %[c]\n"
1618c2ecf20Sopenharmony_ci		"	beqz	%[rc], 0b\n"
1628c2ecf20Sopenharmony_ci		"	b	2f\n"
1638c2ecf20Sopenharmony_ci		"1:\n"
1648c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
1658c2ecf20Sopenharmony_ci		"2:\n"
1668c2ecf20Sopenharmony_ci		: [p]"=&r" (prev), [rc]"=&r" (rc),
1678c2ecf20Sopenharmony_ci		  [c]"=ZB" (v->counter)
1688c2ecf20Sopenharmony_ci		: [a]"r" (a), [u]"r" (u)
1698c2ecf20Sopenharmony_ci		: "memory");
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return prev;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/*
1768c2ecf20Sopenharmony_ci * atomic_sub_if_positive - conditionally subtract integer from atomic variable
1778c2ecf20Sopenharmony_ci * @i: integer value to subtract
1788c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * Atomically test @v and subtract @i if @v is greater or equal than @i.
1818c2ecf20Sopenharmony_ci * The function returns the old value of @v minus @i.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	int result;
1868c2ecf20Sopenharmony_ci	int temp;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (__builtin_constant_p(i)) {
1898c2ecf20Sopenharmony_ci		__asm__ __volatile__(
1908c2ecf20Sopenharmony_ci		"1:	ll.w	%1, %2		# atomic_sub_if_positive\n"
1918c2ecf20Sopenharmony_ci		"	addi.w	%0, %1, %3				\n"
1928c2ecf20Sopenharmony_ci		"	or	%1, %0, $zero				\n"
1938c2ecf20Sopenharmony_ci		"	blt	%0, $zero, 2f				\n"
1948c2ecf20Sopenharmony_ci		"	sc.w	%1, %2					\n"
1958c2ecf20Sopenharmony_ci		"	beq	$zero, %1, 1b				\n"
1968c2ecf20Sopenharmony_ci		"2:							\n"
1978c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
1988c2ecf20Sopenharmony_ci		: "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
1998c2ecf20Sopenharmony_ci		: "I" (-i));
2008c2ecf20Sopenharmony_ci	} else {
2018c2ecf20Sopenharmony_ci		__asm__ __volatile__(
2028c2ecf20Sopenharmony_ci		"1:	ll.w	%1, %2		# atomic_sub_if_positive\n"
2038c2ecf20Sopenharmony_ci		"	sub.w	%0, %1, %3				\n"
2048c2ecf20Sopenharmony_ci		"	or	%1, %0, $zero				\n"
2058c2ecf20Sopenharmony_ci		"	blt	%0, $zero, 2f				\n"
2068c2ecf20Sopenharmony_ci		"	sc.w	%1, %2					\n"
2078c2ecf20Sopenharmony_ci		"	beq	$zero, %1, 1b				\n"
2088c2ecf20Sopenharmony_ci		"2:							\n"
2098c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
2108c2ecf20Sopenharmony_ci		: "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
2118c2ecf20Sopenharmony_ci		: "r" (i));
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return result;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
2188c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/*
2218c2ecf20Sopenharmony_ci * atomic_dec_if_positive - decrement by 1 if old value positive
2228c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
2238c2ecf20Sopenharmony_ci */
2248c2ecf20Sopenharmony_ci#define atomic_dec_if_positive(v)	atomic_sub_if_positive(1, v)
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i)    { (i) }
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * atomic64_read - read atomic variable
2328c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
2338c2ecf20Sopenharmony_ci *
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_ci#define atomic64_read(v)	READ_ONCE((v)->counter)
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/*
2388c2ecf20Sopenharmony_ci * atomic64_set - set atomic variable
2398c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
2408c2ecf20Sopenharmony_ci * @i: required value
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_ci#define atomic64_set(v, i)	WRITE_ONCE((v)->counter, (i))
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, I, asm_op)					\
2458c2ecf20Sopenharmony_cistatic __inline__ void atomic64_##op(long i, atomic64_t * v)		\
2468c2ecf20Sopenharmony_ci{									\
2478c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
2488c2ecf20Sopenharmony_ci	"am"#asm_op".d " " $zero, %1, %0	\n"			\
2498c2ecf20Sopenharmony_ci	: "+ZB" (v->counter)						\
2508c2ecf20Sopenharmony_ci	: "r" (I)							\
2518c2ecf20Sopenharmony_ci	: "memory");							\
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op, I, asm_op, c_op, mb, suffix)			\
2558c2ecf20Sopenharmony_cistatic __inline__ long atomic64_##op##_return##suffix(long i, atomic64_t * v)	\
2568c2ecf20Sopenharmony_ci{										\
2578c2ecf20Sopenharmony_ci	long result;								\
2588c2ecf20Sopenharmony_ci	__asm__ __volatile__(							\
2598c2ecf20Sopenharmony_ci	"am"#asm_op#mb".d " " %1, %2, %0		\n"			\
2608c2ecf20Sopenharmony_ci	: "+ZB" (v->counter), "=&r" (result)					\
2618c2ecf20Sopenharmony_ci	: "r" (I)								\
2628c2ecf20Sopenharmony_ci	: "memory");								\
2638c2ecf20Sopenharmony_ci										\
2648c2ecf20Sopenharmony_ci	return result c_op I;							\
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, I, asm_op, mb, suffix)				\
2688c2ecf20Sopenharmony_cistatic __inline__ long atomic64_fetch_##op##suffix(long i, atomic64_t * v)	\
2698c2ecf20Sopenharmony_ci{										\
2708c2ecf20Sopenharmony_ci	long result;								\
2718c2ecf20Sopenharmony_ci										\
2728c2ecf20Sopenharmony_ci	__asm__ __volatile__(							\
2738c2ecf20Sopenharmony_ci	"am"#asm_op#mb".d " " %1, %2, %0		\n"			\
2748c2ecf20Sopenharmony_ci	: "+ZB" (v->counter), "=&r" (result)					\
2758c2ecf20Sopenharmony_ci	: "r" (I)								\
2768c2ecf20Sopenharmony_ci	: "memory");								\
2778c2ecf20Sopenharmony_ci										\
2788c2ecf20Sopenharmony_ci	return result;								\
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, I, asm_op, c_op)				      \
2828c2ecf20Sopenharmony_ci	ATOMIC64_OP(op, I, asm_op)					      \
2838c2ecf20Sopenharmony_ci	ATOMIC64_OP_RETURN(op, I, asm_op, c_op, _db,         )		      \
2848c2ecf20Sopenharmony_ci	ATOMIC64_OP_RETURN(op, I, asm_op, c_op,    , _relaxed)		      \
2858c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP(op, I, asm_op, _db,         )			      \
2868c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP(op, I, asm_op,    , _relaxed)
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciATOMIC64_OPS(add, i, add, +)
2898c2ecf20Sopenharmony_ciATOMIC64_OPS(sub, -i, add, +)
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci#define atomic64_add_return		atomic64_add_return
2928c2ecf20Sopenharmony_ci#define atomic64_add_return_acquire	atomic64_add_return
2938c2ecf20Sopenharmony_ci#define atomic64_add_return_release	atomic64_add_return
2948c2ecf20Sopenharmony_ci#define atomic64_add_return_relaxed	atomic64_add_return_relaxed
2958c2ecf20Sopenharmony_ci#define atomic64_sub_return		atomic64_sub_return
2968c2ecf20Sopenharmony_ci#define atomic64_sub_return_acquire	atomic64_sub_return
2978c2ecf20Sopenharmony_ci#define atomic64_sub_return_release	atomic64_sub_return
2988c2ecf20Sopenharmony_ci#define atomic64_sub_return_relaxed	atomic64_sub_return_relaxed
2998c2ecf20Sopenharmony_ci#define atomic64_fetch_add		atomic64_fetch_add
3008c2ecf20Sopenharmony_ci#define atomic64_fetch_add_acquire	atomic64_fetch_add
3018c2ecf20Sopenharmony_ci#define atomic64_fetch_add_release	atomic64_fetch_add
3028c2ecf20Sopenharmony_ci#define atomic64_fetch_add_relaxed	atomic64_fetch_add_relaxed
3038c2ecf20Sopenharmony_ci#define atomic64_fetch_sub		atomic64_fetch_sub
3048c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_acquire	atomic64_fetch_sub
3058c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_release	atomic64_fetch_sub
3068c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_relaxed	atomic64_fetch_sub_relaxed
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, I, asm_op)					      \
3118c2ecf20Sopenharmony_ci	ATOMIC64_OP(op, I, asm_op)					      \
3128c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP(op, I, asm_op, _db,         )			      \
3138c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP(op, I, asm_op,    , _relaxed)
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ciATOMIC64_OPS(and, i, and)
3168c2ecf20Sopenharmony_ciATOMIC64_OPS(or, i, or)
3178c2ecf20Sopenharmony_ciATOMIC64_OPS(xor, i, xor)
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci#define atomic64_fetch_and		atomic64_fetch_and
3208c2ecf20Sopenharmony_ci#define atomic64_fetch_and_acquire	atomic64_fetch_and
3218c2ecf20Sopenharmony_ci#define atomic64_fetch_and_release	atomic64_fetch_and
3228c2ecf20Sopenharmony_ci#define atomic64_fetch_and_relaxed	atomic64_fetch_and_relaxed
3238c2ecf20Sopenharmony_ci#define atomic64_fetch_or		atomic64_fetch_or
3248c2ecf20Sopenharmony_ci#define atomic64_fetch_or_acquire	atomic64_fetch_or
3258c2ecf20Sopenharmony_ci#define atomic64_fetch_or_release	atomic64_fetch_or
3268c2ecf20Sopenharmony_ci#define atomic64_fetch_or_relaxed	atomic64_fetch_or_relaxed
3278c2ecf20Sopenharmony_ci#define atomic64_fetch_xor		atomic64_fetch_xor
3288c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_acquire	atomic64_fetch_xor
3298c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_release	atomic64_fetch_xor
3308c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_relaxed	atomic64_fetch_xor_relaxed
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS
3338c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP
3348c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN
3358c2ecf20Sopenharmony_ci#undef ATOMIC64_OP
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic __inline__ long atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci       long prev, rc;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
3428c2ecf20Sopenharmony_ci		"0:	ll.d	%[p],  %[c]\n"
3438c2ecf20Sopenharmony_ci		"	beq	%[p],  %[u], 1f\n"
3448c2ecf20Sopenharmony_ci		"	add.d	%[rc], %[p], %[a]\n"
3458c2ecf20Sopenharmony_ci		"	sc.d	%[rc], %[c]\n"
3468c2ecf20Sopenharmony_ci		"	beqz	%[rc], 0b\n"
3478c2ecf20Sopenharmony_ci		"	b	2f\n"
3488c2ecf20Sopenharmony_ci		"1:\n"
3498c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
3508c2ecf20Sopenharmony_ci		"2:\n"
3518c2ecf20Sopenharmony_ci		: [p]"=&r" (prev), [rc]"=&r" (rc),
3528c2ecf20Sopenharmony_ci		  [c] "=ZB" (v->counter)
3538c2ecf20Sopenharmony_ci		: [a]"r" (a), [u]"r" (u)
3548c2ecf20Sopenharmony_ci		: "memory");
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return prev;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci#define atomic64_fetch_add_unless atomic64_fetch_add_unless
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci/*
3618c2ecf20Sopenharmony_ci * atomic64_sub_if_positive - conditionally subtract integer from atomic
3628c2ecf20Sopenharmony_ci *                            variable
3638c2ecf20Sopenharmony_ci * @i: integer value to subtract
3648c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
3658c2ecf20Sopenharmony_ci *
3668c2ecf20Sopenharmony_ci * Atomically test @v and subtract @i if @v is greater or equal than @i.
3678c2ecf20Sopenharmony_ci * The function returns the old value of @v minus @i.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_cistatic __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	long result;
3728c2ecf20Sopenharmony_ci	long temp;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (__builtin_constant_p(i)) {
3758c2ecf20Sopenharmony_ci		__asm__ __volatile__(
3768c2ecf20Sopenharmony_ci		"1:	ll.d	%1, %2 	# atomic64_sub_if_positive	\n"
3778c2ecf20Sopenharmony_ci		"	addi.d	%0, %1, %3				\n"
3788c2ecf20Sopenharmony_ci		"	or	%1, %0, $zero				\n"
3798c2ecf20Sopenharmony_ci		"	blt	%0, $zero, 2f				\n"
3808c2ecf20Sopenharmony_ci		"	sc.d	%1, %2					\n"
3818c2ecf20Sopenharmony_ci		"	beq	%1, $zero, 1b				\n"
3828c2ecf20Sopenharmony_ci		"2:							\n"
3838c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
3848c2ecf20Sopenharmony_ci		: "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
3858c2ecf20Sopenharmony_ci		: "I" (-i));
3868c2ecf20Sopenharmony_ci	} else {
3878c2ecf20Sopenharmony_ci		__asm__ __volatile__(
3888c2ecf20Sopenharmony_ci		"1:	ll.d	%1, %2 	# atomic64_sub_if_positive	\n"
3898c2ecf20Sopenharmony_ci		"	sub.d	%0, %1, %3				\n"
3908c2ecf20Sopenharmony_ci		"	or	%1, %0, $zero				\n"
3918c2ecf20Sopenharmony_ci		"	blt	%0, $zero, 2f				\n"
3928c2ecf20Sopenharmony_ci		"	sc.d	%1, %2					\n"
3938c2ecf20Sopenharmony_ci		"	beq	%1, $zero, 1b				\n"
3948c2ecf20Sopenharmony_ci		"2:							\n"
3958c2ecf20Sopenharmony_ci		__WEAK_LLSC_MB
3968c2ecf20Sopenharmony_ci		: "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
3978c2ecf20Sopenharmony_ci		: "r" (i));
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	return result;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci#define atomic64_cmpxchg(v, o, n) \
4048c2ecf20Sopenharmony_ci	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
4058c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci/*
4088c2ecf20Sopenharmony_ci * atomic64_dec_if_positive - decrement by 1 if old value positive
4098c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_ci#define atomic64_dec_if_positive(v)	atomic64_sub_if_positive(1, v)
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci#endif /* CONFIG_64BIT */
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci#endif /* _ASM_ATOMIC_H */
416