18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_ATOMIC_H_
38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_ATOMIC_H_
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * PowerPC atomic operations
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifdef __KERNEL__
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
128c2ecf20Sopenharmony_ci#include <asm/barrier.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
168c2ecf20Sopenharmony_ci * a "bne-" instruction at the end, so an isync is enough as a acquire barrier
178c2ecf20Sopenharmony_ci * on the platform without lwsync.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci#define __atomic_acquire_fence()					\
208c2ecf20Sopenharmony_ci	__asm__ __volatile__(PPC_ACQUIRE_BARRIER "" : : : "memory")
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define __atomic_release_fence()					\
238c2ecf20Sopenharmony_ci	__asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory")
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic __inline__ int atomic_read(const atomic_t *v)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	int t;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	__asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return t;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic __inline__ void atomic_set(atomic_t *v, int i)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, asm_op)						\
408c2ecf20Sopenharmony_cistatic __inline__ void atomic_##op(int a, atomic_t *v)			\
418c2ecf20Sopenharmony_ci{									\
428c2ecf20Sopenharmony_ci	int t;								\
438c2ecf20Sopenharmony_ci									\
448c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
458c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%3		# atomic_" #op "\n"			\
468c2ecf20Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
478c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%3 \n"						\
488c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
498c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
508c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
518c2ecf20Sopenharmony_ci	: "cc");							\
528c2ecf20Sopenharmony_ci}									\
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN_RELAXED(op, asm_op)				\
558c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return_relaxed(int a, atomic_t *v)	\
568c2ecf20Sopenharmony_ci{									\
578c2ecf20Sopenharmony_ci	int t;								\
588c2ecf20Sopenharmony_ci									\
598c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
608c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%3		# atomic_" #op "_return_relaxed\n"	\
618c2ecf20Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
628c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%3\n"						\
638c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
648c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
658c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
668c2ecf20Sopenharmony_ci	: "cc");							\
678c2ecf20Sopenharmony_ci									\
688c2ecf20Sopenharmony_ci	return t;							\
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP_RELAXED(op, asm_op)				\
728c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op##_relaxed(int a, atomic_t *v)	\
738c2ecf20Sopenharmony_ci{									\
748c2ecf20Sopenharmony_ci	int res, t;							\
758c2ecf20Sopenharmony_ci									\
768c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
778c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%4		# atomic_fetch_" #op "_relaxed\n"	\
788c2ecf20Sopenharmony_ci	#asm_op " %1,%3,%0\n"						\
798c2ecf20Sopenharmony_ci"	stwcx.	%1,0,%4\n"						\
808c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
818c2ecf20Sopenharmony_ci	: "=&r" (res), "=&r" (t), "+m" (v->counter)			\
828c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
838c2ecf20Sopenharmony_ci	: "cc");							\
848c2ecf20Sopenharmony_ci									\
858c2ecf20Sopenharmony_ci	return res;							\
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, asm_op)						\
898c2ecf20Sopenharmony_ci	ATOMIC_OP(op, asm_op)						\
908c2ecf20Sopenharmony_ci	ATOMIC_OP_RETURN_RELAXED(op, asm_op)				\
918c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP_RELAXED(op, asm_op)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciATOMIC_OPS(add, add)
948c2ecf20Sopenharmony_ciATOMIC_OPS(sub, subf)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define atomic_add_return_relaxed atomic_add_return_relaxed
978c2ecf20Sopenharmony_ci#define atomic_sub_return_relaxed atomic_sub_return_relaxed
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
1008c2ecf20Sopenharmony_ci#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1038c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, asm_op)						\
1048c2ecf20Sopenharmony_ci	ATOMIC_OP(op, asm_op)						\
1058c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP_RELAXED(op, asm_op)
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciATOMIC_OPS(and, and)
1088c2ecf20Sopenharmony_ciATOMIC_OPS(or, or)
1098c2ecf20Sopenharmony_ciATOMIC_OPS(xor, xor)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
1128c2ecf20Sopenharmony_ci#define atomic_fetch_or_relaxed  atomic_fetch_or_relaxed
1138c2ecf20Sopenharmony_ci#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1168c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP_RELAXED
1178c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN_RELAXED
1188c2ecf20Sopenharmony_ci#undef ATOMIC_OP
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic __inline__ void atomic_inc(atomic_t *v)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	int t;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1258c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%2		# atomic_inc\n\
1268c2ecf20Sopenharmony_ci	addic	%0,%0,1\n"
1278c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%2 \n\
1288c2ecf20Sopenharmony_ci	bne-	1b"
1298c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
1308c2ecf20Sopenharmony_ci	: "r" (&v->counter)
1318c2ecf20Sopenharmony_ci	: "cc", "xer");
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci#define atomic_inc atomic_inc
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic __inline__ int atomic_inc_return_relaxed(atomic_t *v)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	int t;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1408c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%2		# atomic_inc_return_relaxed\n"
1418c2ecf20Sopenharmony_ci"	addic	%0,%0,1\n"
1428c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%2\n"
1438c2ecf20Sopenharmony_ci"	bne-	1b"
1448c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
1458c2ecf20Sopenharmony_ci	: "r" (&v->counter)
1468c2ecf20Sopenharmony_ci	: "cc", "xer");
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return t;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic __inline__ void atomic_dec(atomic_t *v)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	int t;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1568c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%2		# atomic_dec\n\
1578c2ecf20Sopenharmony_ci	addic	%0,%0,-1\n"
1588c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%2\n\
1598c2ecf20Sopenharmony_ci	bne-	1b"
1608c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
1618c2ecf20Sopenharmony_ci	: "r" (&v->counter)
1628c2ecf20Sopenharmony_ci	: "cc", "xer");
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci#define atomic_dec atomic_dec
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic __inline__ int atomic_dec_return_relaxed(atomic_t *v)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	int t;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1718c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%2		# atomic_dec_return_relaxed\n"
1728c2ecf20Sopenharmony_ci"	addic	%0,%0,-1\n"
1738c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%2\n"
1748c2ecf20Sopenharmony_ci"	bne-	1b"
1758c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
1768c2ecf20Sopenharmony_ci	: "r" (&v->counter)
1778c2ecf20Sopenharmony_ci	: "cc", "xer");
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return t;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define atomic_inc_return_relaxed atomic_inc_return_relaxed
1838c2ecf20Sopenharmony_ci#define atomic_dec_return_relaxed atomic_dec_return_relaxed
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
1868c2ecf20Sopenharmony_ci#define atomic_cmpxchg_relaxed(v, o, n) \
1878c2ecf20Sopenharmony_ci	cmpxchg_relaxed(&((v)->counter), (o), (n))
1888c2ecf20Sopenharmony_ci#define atomic_cmpxchg_acquire(v, o, n) \
1898c2ecf20Sopenharmony_ci	cmpxchg_acquire(&((v)->counter), (o), (n))
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
1928c2ecf20Sopenharmony_ci#define atomic_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/*
1958c2ecf20Sopenharmony_ci * Don't want to override the generic atomic_try_cmpxchg_acquire, because
1968c2ecf20Sopenharmony_ci * we add a lock hint to the lwarx, which may not be wanted for the
1978c2ecf20Sopenharmony_ci * _acquire case (and is not used by the other _acquire variants so it
1988c2ecf20Sopenharmony_ci * would be a surprise).
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_cistatic __always_inline bool
2018c2ecf20Sopenharmony_ciatomic_try_cmpxchg_lock(atomic_t *v, int *old, int new)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	int r, o = *old;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
2068c2ecf20Sopenharmony_ci"1:\t"	PPC_LWARX(%0,0,%2,1) "	# atomic_try_cmpxchg_acquire	\n"
2078c2ecf20Sopenharmony_ci"	cmpw	0,%0,%3							\n"
2088c2ecf20Sopenharmony_ci"	bne-	2f							\n"
2098c2ecf20Sopenharmony_ci"	stwcx.	%4,0,%2							\n"
2108c2ecf20Sopenharmony_ci"	bne-	1b							\n"
2118c2ecf20Sopenharmony_ci"\t"	PPC_ACQUIRE_BARRIER "						\n"
2128c2ecf20Sopenharmony_ci"2:									\n"
2138c2ecf20Sopenharmony_ci	: "=&r" (r), "+m" (v->counter)
2148c2ecf20Sopenharmony_ci	: "r" (&v->counter), "r" (o), "r" (new)
2158c2ecf20Sopenharmony_ci	: "cr0", "memory");
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (unlikely(r != o))
2188c2ecf20Sopenharmony_ci		*old = r;
2198c2ecf20Sopenharmony_ci	return likely(r == o);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/**
2238c2ecf20Sopenharmony_ci * atomic_fetch_add_unless - add unless the number is a given value
2248c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
2258c2ecf20Sopenharmony_ci * @a: the amount to add to v...
2268c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u.
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u.
2298c2ecf20Sopenharmony_ci * Returns the old value of @v.
2308c2ecf20Sopenharmony_ci */
2318c2ecf20Sopenharmony_cistatic __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	int t;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
2368c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
2378c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%1		# atomic_fetch_add_unless\n\
2388c2ecf20Sopenharmony_ci	cmpw	0,%0,%3 \n\
2398c2ecf20Sopenharmony_ci	beq	2f \n\
2408c2ecf20Sopenharmony_ci	add	%0,%2,%0 \n"
2418c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%1 \n\
2428c2ecf20Sopenharmony_ci	bne-	1b \n"
2438c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
2448c2ecf20Sopenharmony_ci"	subf	%0,%2,%0 \n\
2458c2ecf20Sopenharmony_ci2:"
2468c2ecf20Sopenharmony_ci	: "=&r" (t)
2478c2ecf20Sopenharmony_ci	: "r" (&v->counter), "r" (a), "r" (u)
2488c2ecf20Sopenharmony_ci	: "cc", "memory");
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return t;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci#define atomic_fetch_add_unless atomic_fetch_add_unless
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/**
2558c2ecf20Sopenharmony_ci * atomic_inc_not_zero - increment unless the number is zero
2568c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t
2578c2ecf20Sopenharmony_ci *
2588c2ecf20Sopenharmony_ci * Atomically increments @v by 1, so long as @v is non-zero.
2598c2ecf20Sopenharmony_ci * Returns non-zero if @v was non-zero, and zero otherwise.
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_cistatic __inline__ int atomic_inc_not_zero(atomic_t *v)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	int t1, t2;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
2668c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
2678c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%2		# atomic_inc_not_zero\n\
2688c2ecf20Sopenharmony_ci	cmpwi	0,%0,0\n\
2698c2ecf20Sopenharmony_ci	beq-	2f\n\
2708c2ecf20Sopenharmony_ci	addic	%1,%0,1\n"
2718c2ecf20Sopenharmony_ci"	stwcx.	%1,0,%2\n\
2728c2ecf20Sopenharmony_ci	bne-	1b\n"
2738c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
2748c2ecf20Sopenharmony_ci	"\n\
2758c2ecf20Sopenharmony_ci2:"
2768c2ecf20Sopenharmony_ci	: "=&r" (t1), "=&r" (t2)
2778c2ecf20Sopenharmony_ci	: "r" (&v->counter)
2788c2ecf20Sopenharmony_ci	: "cc", "xer", "memory");
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return t1;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci#define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/*
2858c2ecf20Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0.
2868c2ecf20Sopenharmony_ci * The function returns the old value of *v minus 1, even if
2878c2ecf20Sopenharmony_ci * the atomic variable, v, was not decremented.
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_cistatic __inline__ int atomic_dec_if_positive(atomic_t *v)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	int t;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2948c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
2958c2ecf20Sopenharmony_ci"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
2968c2ecf20Sopenharmony_ci	cmpwi	%0,1\n\
2978c2ecf20Sopenharmony_ci	addi	%0,%0,-1\n\
2988c2ecf20Sopenharmony_ci	blt-	2f\n"
2998c2ecf20Sopenharmony_ci"	stwcx.	%0,0,%1\n\
3008c2ecf20Sopenharmony_ci	bne-	1b"
3018c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
3028c2ecf20Sopenharmony_ci	"\n\
3038c2ecf20Sopenharmony_ci2:"	: "=&b" (t)
3048c2ecf20Sopenharmony_ci	: "r" (&v->counter)
3058c2ecf20Sopenharmony_ci	: "cc", "memory");
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return t;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci#define atomic_dec_if_positive atomic_dec_if_positive
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci#ifdef __powerpc64__
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i)	{ (i) }
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_read(const atomic64_t *v)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	s64 t;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	__asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return t;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic __inline__ void atomic64_set(atomic64_t *v, s64 i)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	__asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, asm_op)						\
3308c2ecf20Sopenharmony_cistatic __inline__ void atomic64_##op(s64 a, atomic64_t *v)		\
3318c2ecf20Sopenharmony_ci{									\
3328c2ecf20Sopenharmony_ci	s64 t;								\
3338c2ecf20Sopenharmony_ci									\
3348c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
3358c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%3		# atomic64_" #op "\n"			\
3368c2ecf20Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
3378c2ecf20Sopenharmony_ci"	stdcx.	%0,0,%3 \n"						\
3388c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
3398c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
3408c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
3418c2ecf20Sopenharmony_ci	: "cc");							\
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op)				\
3458c2ecf20Sopenharmony_cistatic inline s64							\
3468c2ecf20Sopenharmony_ciatomic64_##op##_return_relaxed(s64 a, atomic64_t *v)			\
3478c2ecf20Sopenharmony_ci{									\
3488c2ecf20Sopenharmony_ci	s64 t;								\
3498c2ecf20Sopenharmony_ci									\
3508c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
3518c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%3		# atomic64_" #op "_return_relaxed\n"	\
3528c2ecf20Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
3538c2ecf20Sopenharmony_ci"	stdcx.	%0,0,%3\n"						\
3548c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
3558c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
3568c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
3578c2ecf20Sopenharmony_ci	: "cc");							\
3588c2ecf20Sopenharmony_ci									\
3598c2ecf20Sopenharmony_ci	return t;							\
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op)				\
3638c2ecf20Sopenharmony_cistatic inline s64							\
3648c2ecf20Sopenharmony_ciatomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v)			\
3658c2ecf20Sopenharmony_ci{									\
3668c2ecf20Sopenharmony_ci	s64 res, t;							\
3678c2ecf20Sopenharmony_ci									\
3688c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
3698c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%4		# atomic64_fetch_" #op "_relaxed\n"	\
3708c2ecf20Sopenharmony_ci	#asm_op " %1,%3,%0\n"						\
3718c2ecf20Sopenharmony_ci"	stdcx.	%1,0,%4\n"						\
3728c2ecf20Sopenharmony_ci"	bne-	1b\n"							\
3738c2ecf20Sopenharmony_ci	: "=&r" (res), "=&r" (t), "+m" (v->counter)			\
3748c2ecf20Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
3758c2ecf20Sopenharmony_ci	: "cc");							\
3768c2ecf20Sopenharmony_ci									\
3778c2ecf20Sopenharmony_ci	return res;							\
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op)					\
3818c2ecf20Sopenharmony_ci	ATOMIC64_OP(op, asm_op)						\
3828c2ecf20Sopenharmony_ci	ATOMIC64_OP_RETURN_RELAXED(op, asm_op)				\
3838c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ciATOMIC64_OPS(add, add)
3868c2ecf20Sopenharmony_ciATOMIC64_OPS(sub, subf)
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci#define atomic64_add_return_relaxed atomic64_add_return_relaxed
3898c2ecf20Sopenharmony_ci#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
3928c2ecf20Sopenharmony_ci#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS
3958c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op)					\
3968c2ecf20Sopenharmony_ci	ATOMIC64_OP(op, asm_op)						\
3978c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciATOMIC64_OPS(and, and)
4008c2ecf20Sopenharmony_ciATOMIC64_OPS(or, or)
4018c2ecf20Sopenharmony_ciATOMIC64_OPS(xor, xor)
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
4048c2ecf20Sopenharmony_ci#define atomic64_fetch_or_relaxed  atomic64_fetch_or_relaxed
4058c2ecf20Sopenharmony_ci#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci#undef ATOPIC64_OPS
4088c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP_RELAXED
4098c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN_RELAXED
4108c2ecf20Sopenharmony_ci#undef ATOMIC64_OP
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic __inline__ void atomic64_inc(atomic64_t *v)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	s64 t;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	__asm__ __volatile__(
4178c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc\n\
4188c2ecf20Sopenharmony_ci	addic	%0,%0,1\n\
4198c2ecf20Sopenharmony_ci	stdcx.	%0,0,%2 \n\
4208c2ecf20Sopenharmony_ci	bne-	1b"
4218c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
4228c2ecf20Sopenharmony_ci	: "r" (&v->counter)
4238c2ecf20Sopenharmony_ci	: "cc", "xer");
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci#define atomic64_inc atomic64_inc
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_inc_return_relaxed(atomic64_t *v)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	s64 t;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	__asm__ __volatile__(
4328c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc_return_relaxed\n"
4338c2ecf20Sopenharmony_ci"	addic	%0,%0,1\n"
4348c2ecf20Sopenharmony_ci"	stdcx.	%0,0,%2\n"
4358c2ecf20Sopenharmony_ci"	bne-	1b"
4368c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
4378c2ecf20Sopenharmony_ci	: "r" (&v->counter)
4388c2ecf20Sopenharmony_ci	: "cc", "xer");
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	return t;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic __inline__ void atomic64_dec(atomic64_t *v)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	s64 t;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	__asm__ __volatile__(
4488c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_dec\n\
4498c2ecf20Sopenharmony_ci	addic	%0,%0,-1\n\
4508c2ecf20Sopenharmony_ci	stdcx.	%0,0,%2\n\
4518c2ecf20Sopenharmony_ci	bne-	1b"
4528c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
4538c2ecf20Sopenharmony_ci	: "r" (&v->counter)
4548c2ecf20Sopenharmony_ci	: "cc", "xer");
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci#define atomic64_dec atomic64_dec
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_dec_return_relaxed(atomic64_t *v)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	s64 t;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	__asm__ __volatile__(
4638c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_dec_return_relaxed\n"
4648c2ecf20Sopenharmony_ci"	addic	%0,%0,-1\n"
4658c2ecf20Sopenharmony_ci"	stdcx.	%0,0,%2\n"
4668c2ecf20Sopenharmony_ci"	bne-	1b"
4678c2ecf20Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
4688c2ecf20Sopenharmony_ci	: "r" (&v->counter)
4698c2ecf20Sopenharmony_ci	: "cc", "xer");
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return t;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
4758c2ecf20Sopenharmony_ci#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci/*
4788c2ecf20Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0.
4798c2ecf20Sopenharmony_ci * The function returns the old value of *v minus 1.
4808c2ecf20Sopenharmony_ci */
4818c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_dec_if_positive(atomic64_t *v)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	s64 t;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	__asm__ __volatile__(
4868c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
4878c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%1		# atomic64_dec_if_positive\n\
4888c2ecf20Sopenharmony_ci	addic.	%0,%0,-1\n\
4898c2ecf20Sopenharmony_ci	blt-	2f\n\
4908c2ecf20Sopenharmony_ci	stdcx.	%0,0,%1\n\
4918c2ecf20Sopenharmony_ci	bne-	1b"
4928c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
4938c2ecf20Sopenharmony_ci	"\n\
4948c2ecf20Sopenharmony_ci2:"	: "=&r" (t)
4958c2ecf20Sopenharmony_ci	: "r" (&v->counter)
4968c2ecf20Sopenharmony_ci	: "cc", "xer", "memory");
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return t;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci#define atomic64_dec_if_positive atomic64_dec_if_positive
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
5038c2ecf20Sopenharmony_ci#define atomic64_cmpxchg_relaxed(v, o, n) \
5048c2ecf20Sopenharmony_ci	cmpxchg_relaxed(&((v)->counter), (o), (n))
5058c2ecf20Sopenharmony_ci#define atomic64_cmpxchg_acquire(v, o, n) \
5068c2ecf20Sopenharmony_ci	cmpxchg_acquire(&((v)->counter), (o), (n))
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
5098c2ecf20Sopenharmony_ci#define atomic64_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/**
5128c2ecf20Sopenharmony_ci * atomic64_fetch_add_unless - add unless the number is a given value
5138c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
5148c2ecf20Sopenharmony_ci * @a: the amount to add to v...
5158c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u.
5168c2ecf20Sopenharmony_ci *
5178c2ecf20Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u.
5188c2ecf20Sopenharmony_ci * Returns the old value of @v.
5198c2ecf20Sopenharmony_ci */
5208c2ecf20Sopenharmony_cistatic __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	s64 t;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
5258c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
5268c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%1		# atomic64_fetch_add_unless\n\
5278c2ecf20Sopenharmony_ci	cmpd	0,%0,%3 \n\
5288c2ecf20Sopenharmony_ci	beq	2f \n\
5298c2ecf20Sopenharmony_ci	add	%0,%2,%0 \n"
5308c2ecf20Sopenharmony_ci"	stdcx.	%0,0,%1 \n\
5318c2ecf20Sopenharmony_ci	bne-	1b \n"
5328c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
5338c2ecf20Sopenharmony_ci"	subf	%0,%2,%0 \n\
5348c2ecf20Sopenharmony_ci2:"
5358c2ecf20Sopenharmony_ci	: "=&r" (t)
5368c2ecf20Sopenharmony_ci	: "r" (&v->counter), "r" (a), "r" (u)
5378c2ecf20Sopenharmony_ci	: "cc", "memory");
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return t;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci#define atomic64_fetch_add_unless atomic64_fetch_add_unless
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/**
5448c2ecf20Sopenharmony_ci * atomic_inc64_not_zero - increment unless the number is zero
5458c2ecf20Sopenharmony_ci * @v: pointer of type atomic64_t
5468c2ecf20Sopenharmony_ci *
5478c2ecf20Sopenharmony_ci * Atomically increments @v by 1, so long as @v is non-zero.
5488c2ecf20Sopenharmony_ci * Returns non-zero if @v was non-zero, and zero otherwise.
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_cistatic __inline__ int atomic64_inc_not_zero(atomic64_t *v)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	s64 t1, t2;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	__asm__ __volatile__ (
5558c2ecf20Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
5568c2ecf20Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc_not_zero\n\
5578c2ecf20Sopenharmony_ci	cmpdi	0,%0,0\n\
5588c2ecf20Sopenharmony_ci	beq-	2f\n\
5598c2ecf20Sopenharmony_ci	addic	%1,%0,1\n\
5608c2ecf20Sopenharmony_ci	stdcx.	%1,0,%2\n\
5618c2ecf20Sopenharmony_ci	bne-	1b\n"
5628c2ecf20Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
5638c2ecf20Sopenharmony_ci	"\n\
5648c2ecf20Sopenharmony_ci2:"
5658c2ecf20Sopenharmony_ci	: "=&r" (t1), "=&r" (t2)
5668c2ecf20Sopenharmony_ci	: "r" (&v->counter)
5678c2ecf20Sopenharmony_ci	: "cc", "xer", "memory");
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return t1 != 0;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci#define atomic64_inc_not_zero(v) atomic64_inc_not_zero((v))
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci#endif /* __KERNEL__ */
5768c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_ATOMIC_H_ */
577