162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_ATOMIC_H_
362306a36Sopenharmony_ci#define _ASM_POWERPC_ATOMIC_H_
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * PowerPC atomic operations
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifdef __KERNEL__
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <asm/cmpxchg.h>
1262306a36Sopenharmony_ci#include <asm/barrier.h>
1362306a36Sopenharmony_ci#include <asm/asm-const.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
1762306a36Sopenharmony_ci * a "bne-" instruction at the end, so an isync is enough as a acquire barrier
1862306a36Sopenharmony_ci * on the platform without lwsync.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci#define __atomic_acquire_fence()					\
2162306a36Sopenharmony_ci	__asm__ __volatile__(PPC_ACQUIRE_BARRIER "" : : : "memory")
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define __atomic_release_fence()					\
2462306a36Sopenharmony_ci	__asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory")
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic __inline__ int arch_atomic_read(const atomic_t *v)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	int t;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* -mprefixed can generate offsets beyond range, fall back hack */
3162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
3262306a36Sopenharmony_ci		__asm__ __volatile__("lwz %0,0(%1)" : "=r"(t) : "b"(&v->counter));
3362306a36Sopenharmony_ci	else
3462306a36Sopenharmony_ci		__asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return t;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic __inline__ void arch_atomic_set(atomic_t *v, int i)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	/* -mprefixed can generate offsets beyond range, fall back hack */
4262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
4362306a36Sopenharmony_ci		__asm__ __volatile__("stw %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter));
4462306a36Sopenharmony_ci	else
4562306a36Sopenharmony_ci		__asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define ATOMIC_OP(op, asm_op, suffix, sign, ...)			\
4962306a36Sopenharmony_cistatic __inline__ void arch_atomic_##op(int a, atomic_t *v)		\
5062306a36Sopenharmony_ci{									\
5162306a36Sopenharmony_ci	int t;								\
5262306a36Sopenharmony_ci									\
5362306a36Sopenharmony_ci	__asm__ __volatile__(						\
5462306a36Sopenharmony_ci"1:	lwarx	%0,0,%3		# atomic_" #op "\n"			\
5562306a36Sopenharmony_ci	#asm_op "%I2" suffix " %0,%0,%2\n"				\
5662306a36Sopenharmony_ci"	stwcx.	%0,0,%3 \n"						\
5762306a36Sopenharmony_ci"	bne-	1b\n"							\
5862306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
5962306a36Sopenharmony_ci	: "r"#sign (a), "r" (&v->counter)				\
6062306a36Sopenharmony_ci	: "cc", ##__VA_ARGS__);						\
6162306a36Sopenharmony_ci}									\
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define ATOMIC_OP_RETURN_RELAXED(op, asm_op, suffix, sign, ...)		\
6462306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return_relaxed(int a, atomic_t *v)	\
6562306a36Sopenharmony_ci{									\
6662306a36Sopenharmony_ci	int t;								\
6762306a36Sopenharmony_ci									\
6862306a36Sopenharmony_ci	__asm__ __volatile__(						\
6962306a36Sopenharmony_ci"1:	lwarx	%0,0,%3		# atomic_" #op "_return_relaxed\n"	\
7062306a36Sopenharmony_ci	#asm_op "%I2" suffix " %0,%0,%2\n"				\
7162306a36Sopenharmony_ci"	stwcx.	%0,0,%3\n"						\
7262306a36Sopenharmony_ci"	bne-	1b\n"							\
7362306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
7462306a36Sopenharmony_ci	: "r"#sign (a), "r" (&v->counter)				\
7562306a36Sopenharmony_ci	: "cc", ##__VA_ARGS__);						\
7662306a36Sopenharmony_ci									\
7762306a36Sopenharmony_ci	return t;							\
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign, ...)		\
8162306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op##_relaxed(int a, atomic_t *v)	\
8262306a36Sopenharmony_ci{									\
8362306a36Sopenharmony_ci	int res, t;							\
8462306a36Sopenharmony_ci									\
8562306a36Sopenharmony_ci	__asm__ __volatile__(						\
8662306a36Sopenharmony_ci"1:	lwarx	%0,0,%4		# atomic_fetch_" #op "_relaxed\n"	\
8762306a36Sopenharmony_ci	#asm_op "%I3" suffix " %1,%0,%3\n"				\
8862306a36Sopenharmony_ci"	stwcx.	%1,0,%4\n"						\
8962306a36Sopenharmony_ci"	bne-	1b\n"							\
9062306a36Sopenharmony_ci	: "=&r" (res), "=&r" (t), "+m" (v->counter)			\
9162306a36Sopenharmony_ci	: "r"#sign (a), "r" (&v->counter)				\
9262306a36Sopenharmony_ci	: "cc", ##__VA_ARGS__);						\
9362306a36Sopenharmony_ci									\
9462306a36Sopenharmony_ci	return res;							\
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define ATOMIC_OPS(op, asm_op, suffix, sign, ...)			\
9862306a36Sopenharmony_ci	ATOMIC_OP(op, asm_op, suffix, sign, ##__VA_ARGS__)		\
9962306a36Sopenharmony_ci	ATOMIC_OP_RETURN_RELAXED(op, asm_op, suffix, sign, ##__VA_ARGS__)\
10062306a36Sopenharmony_ci	ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign, ##__VA_ARGS__)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciATOMIC_OPS(add, add, "c", I, "xer")
10362306a36Sopenharmony_ciATOMIC_OPS(sub, sub, "c", I, "xer")
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
10662306a36Sopenharmony_ci#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
10962306a36Sopenharmony_ci#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#undef ATOMIC_OPS
11262306a36Sopenharmony_ci#define ATOMIC_OPS(op, asm_op, suffix, sign)				\
11362306a36Sopenharmony_ci	ATOMIC_OP(op, asm_op, suffix, sign)				\
11462306a36Sopenharmony_ci	ATOMIC_FETCH_OP_RELAXED(op, asm_op, suffix, sign)
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciATOMIC_OPS(and, and, ".", K)
11762306a36Sopenharmony_ciATOMIC_OPS(or, or, "", K)
11862306a36Sopenharmony_ciATOMIC_OPS(xor, xor, "", K)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
12162306a36Sopenharmony_ci#define arch_atomic_fetch_or_relaxed  arch_atomic_fetch_or_relaxed
12262306a36Sopenharmony_ci#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#undef ATOMIC_OPS
12562306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP_RELAXED
12662306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN_RELAXED
12762306a36Sopenharmony_ci#undef ATOMIC_OP
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci * atomic_fetch_add_unless - add unless the number is a given value
13162306a36Sopenharmony_ci * @v: pointer of type atomic_t
13262306a36Sopenharmony_ci * @a: the amount to add to v...
13362306a36Sopenharmony_ci * @u: ...unless v is equal to u.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u.
13662306a36Sopenharmony_ci * Returns the old value of @v.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic __inline__ int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int t;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	__asm__ __volatile__ (
14362306a36Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
14462306a36Sopenharmony_ci"1:	lwarx	%0,0,%1		# atomic_fetch_add_unless\n\
14562306a36Sopenharmony_ci	cmpw	0,%0,%3 \n\
14662306a36Sopenharmony_ci	beq	2f \n\
14762306a36Sopenharmony_ci	add%I2c	%0,%0,%2 \n"
14862306a36Sopenharmony_ci"	stwcx.	%0,0,%1 \n\
14962306a36Sopenharmony_ci	bne-	1b \n"
15062306a36Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
15162306a36Sopenharmony_ci"	sub%I2c	%0,%0,%2 \n\
15262306a36Sopenharmony_ci2:"
15362306a36Sopenharmony_ci	: "=&r" (t)
15462306a36Sopenharmony_ci	: "r" (&v->counter), "rI" (a), "r" (u)
15562306a36Sopenharmony_ci	: "cc", "memory", "xer");
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return t;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/*
16262306a36Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0.
16362306a36Sopenharmony_ci * The function returns the old value of *v minus 1, even if
16462306a36Sopenharmony_ci * the atomic variable, v, was not decremented.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistatic __inline__ int arch_atomic_dec_if_positive(atomic_t *v)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	int t;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	__asm__ __volatile__(
17162306a36Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
17262306a36Sopenharmony_ci"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
17362306a36Sopenharmony_ci	cmpwi	%0,1\n\
17462306a36Sopenharmony_ci	addi	%0,%0,-1\n\
17562306a36Sopenharmony_ci	blt-	2f\n"
17662306a36Sopenharmony_ci"	stwcx.	%0,0,%1\n\
17762306a36Sopenharmony_ci	bne-	1b"
17862306a36Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
17962306a36Sopenharmony_ci	"\n\
18062306a36Sopenharmony_ci2:"	: "=&b" (t)
18162306a36Sopenharmony_ci	: "r" (&v->counter)
18262306a36Sopenharmony_ci	: "cc", "memory");
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return t;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci#define arch_atomic_dec_if_positive arch_atomic_dec_if_positive
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci#ifdef __powerpc64__
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define ATOMIC64_INIT(i)	{ (i) }
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_read(const atomic64_t *v)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	s64 t;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* -mprefixed can generate offsets beyond range, fall back hack */
19762306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
19862306a36Sopenharmony_ci		__asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter));
19962306a36Sopenharmony_ci	else
20062306a36Sopenharmony_ci		__asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter));
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return t;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic __inline__ void arch_atomic64_set(atomic64_t *v, s64 i)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	/* -mprefixed can generate offsets beyond range, fall back hack */
20862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED))
20962306a36Sopenharmony_ci		__asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter));
21062306a36Sopenharmony_ci	else
21162306a36Sopenharmony_ci		__asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i));
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci#define ATOMIC64_OP(op, asm_op)						\
21562306a36Sopenharmony_cistatic __inline__ void arch_atomic64_##op(s64 a, atomic64_t *v)		\
21662306a36Sopenharmony_ci{									\
21762306a36Sopenharmony_ci	s64 t;								\
21862306a36Sopenharmony_ci									\
21962306a36Sopenharmony_ci	__asm__ __volatile__(						\
22062306a36Sopenharmony_ci"1:	ldarx	%0,0,%3		# atomic64_" #op "\n"			\
22162306a36Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
22262306a36Sopenharmony_ci"	stdcx.	%0,0,%3 \n"						\
22362306a36Sopenharmony_ci"	bne-	1b\n"							\
22462306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
22562306a36Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
22662306a36Sopenharmony_ci	: "cc");							\
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op)				\
23062306a36Sopenharmony_cistatic inline s64							\
23162306a36Sopenharmony_ciarch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v)		\
23262306a36Sopenharmony_ci{									\
23362306a36Sopenharmony_ci	s64 t;								\
23462306a36Sopenharmony_ci									\
23562306a36Sopenharmony_ci	__asm__ __volatile__(						\
23662306a36Sopenharmony_ci"1:	ldarx	%0,0,%3		# atomic64_" #op "_return_relaxed\n"	\
23762306a36Sopenharmony_ci	#asm_op " %0,%2,%0\n"						\
23862306a36Sopenharmony_ci"	stdcx.	%0,0,%3\n"						\
23962306a36Sopenharmony_ci"	bne-	1b\n"							\
24062306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)					\
24162306a36Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
24262306a36Sopenharmony_ci	: "cc");							\
24362306a36Sopenharmony_ci									\
24462306a36Sopenharmony_ci	return t;							\
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op)				\
24862306a36Sopenharmony_cistatic inline s64							\
24962306a36Sopenharmony_ciarch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v)		\
25062306a36Sopenharmony_ci{									\
25162306a36Sopenharmony_ci	s64 res, t;							\
25262306a36Sopenharmony_ci									\
25362306a36Sopenharmony_ci	__asm__ __volatile__(						\
25462306a36Sopenharmony_ci"1:	ldarx	%0,0,%4		# atomic64_fetch_" #op "_relaxed\n"	\
25562306a36Sopenharmony_ci	#asm_op " %1,%3,%0\n"						\
25662306a36Sopenharmony_ci"	stdcx.	%1,0,%4\n"						\
25762306a36Sopenharmony_ci"	bne-	1b\n"							\
25862306a36Sopenharmony_ci	: "=&r" (res), "=&r" (t), "+m" (v->counter)			\
25962306a36Sopenharmony_ci	: "r" (a), "r" (&v->counter)					\
26062306a36Sopenharmony_ci	: "cc");							\
26162306a36Sopenharmony_ci									\
26262306a36Sopenharmony_ci	return res;							\
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op)					\
26662306a36Sopenharmony_ci	ATOMIC64_OP(op, asm_op)						\
26762306a36Sopenharmony_ci	ATOMIC64_OP_RETURN_RELAXED(op, asm_op)				\
26862306a36Sopenharmony_ci	ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ciATOMIC64_OPS(add, add)
27162306a36Sopenharmony_ciATOMIC64_OPS(sub, subf)
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed
27462306a36Sopenharmony_ci#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed
27762306a36Sopenharmony_ci#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#undef ATOMIC64_OPS
28062306a36Sopenharmony_ci#define ATOMIC64_OPS(op, asm_op)					\
28162306a36Sopenharmony_ci	ATOMIC64_OP(op, asm_op)						\
28262306a36Sopenharmony_ci	ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciATOMIC64_OPS(and, and)
28562306a36Sopenharmony_ciATOMIC64_OPS(or, or)
28662306a36Sopenharmony_ciATOMIC64_OPS(xor, xor)
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed
28962306a36Sopenharmony_ci#define arch_atomic64_fetch_or_relaxed  arch_atomic64_fetch_or_relaxed
29062306a36Sopenharmony_ci#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci#undef ATOPIC64_OPS
29362306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP_RELAXED
29462306a36Sopenharmony_ci#undef ATOMIC64_OP_RETURN_RELAXED
29562306a36Sopenharmony_ci#undef ATOMIC64_OP
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic __inline__ void arch_atomic64_inc(atomic64_t *v)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	s64 t;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	__asm__ __volatile__(
30262306a36Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc\n\
30362306a36Sopenharmony_ci	addic	%0,%0,1\n\
30462306a36Sopenharmony_ci	stdcx.	%0,0,%2 \n\
30562306a36Sopenharmony_ci	bne-	1b"
30662306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
30762306a36Sopenharmony_ci	: "r" (&v->counter)
30862306a36Sopenharmony_ci	: "cc", "xer");
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci#define arch_atomic64_inc arch_atomic64_inc
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_inc_return_relaxed(atomic64_t *v)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	s64 t;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	__asm__ __volatile__(
31762306a36Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc_return_relaxed\n"
31862306a36Sopenharmony_ci"	addic	%0,%0,1\n"
31962306a36Sopenharmony_ci"	stdcx.	%0,0,%2\n"
32062306a36Sopenharmony_ci"	bne-	1b"
32162306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
32262306a36Sopenharmony_ci	: "r" (&v->counter)
32362306a36Sopenharmony_ci	: "cc", "xer");
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return t;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic __inline__ void arch_atomic64_dec(atomic64_t *v)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	s64 t;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	__asm__ __volatile__(
33362306a36Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_dec\n\
33462306a36Sopenharmony_ci	addic	%0,%0,-1\n\
33562306a36Sopenharmony_ci	stdcx.	%0,0,%2\n\
33662306a36Sopenharmony_ci	bne-	1b"
33762306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
33862306a36Sopenharmony_ci	: "r" (&v->counter)
33962306a36Sopenharmony_ci	: "cc", "xer");
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci#define arch_atomic64_dec arch_atomic64_dec
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_dec_return_relaxed(atomic64_t *v)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	s64 t;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	__asm__ __volatile__(
34862306a36Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_dec_return_relaxed\n"
34962306a36Sopenharmony_ci"	addic	%0,%0,-1\n"
35062306a36Sopenharmony_ci"	stdcx.	%0,0,%2\n"
35162306a36Sopenharmony_ci"	bne-	1b"
35262306a36Sopenharmony_ci	: "=&r" (t), "+m" (v->counter)
35362306a36Sopenharmony_ci	: "r" (&v->counter)
35462306a36Sopenharmony_ci	: "cc", "xer");
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return t;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci#define arch_atomic64_inc_return_relaxed arch_atomic64_inc_return_relaxed
36062306a36Sopenharmony_ci#define arch_atomic64_dec_return_relaxed arch_atomic64_dec_return_relaxed
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*
36362306a36Sopenharmony_ci * Atomically test *v and decrement if it is greater than 0.
36462306a36Sopenharmony_ci * The function returns the old value of *v minus 1.
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_dec_if_positive(atomic64_t *v)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	s64 t;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	__asm__ __volatile__(
37162306a36Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
37262306a36Sopenharmony_ci"1:	ldarx	%0,0,%1		# atomic64_dec_if_positive\n\
37362306a36Sopenharmony_ci	addic.	%0,%0,-1\n\
37462306a36Sopenharmony_ci	blt-	2f\n\
37562306a36Sopenharmony_ci	stdcx.	%0,0,%1\n\
37662306a36Sopenharmony_ci	bne-	1b"
37762306a36Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
37862306a36Sopenharmony_ci	"\n\
37962306a36Sopenharmony_ci2:"	: "=&r" (t)
38062306a36Sopenharmony_ci	: "r" (&v->counter)
38162306a36Sopenharmony_ci	: "cc", "xer", "memory");
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return t;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * atomic64_fetch_add_unless - add unless the number is a given value
38962306a36Sopenharmony_ci * @v: pointer of type atomic64_t
39062306a36Sopenharmony_ci * @a: the amount to add to v...
39162306a36Sopenharmony_ci * @u: ...unless v is equal to u.
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * Atomically adds @a to @v, so long as it was not @u.
39462306a36Sopenharmony_ci * Returns the old value of @v.
39562306a36Sopenharmony_ci */
39662306a36Sopenharmony_cistatic __inline__ s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	s64 t;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	__asm__ __volatile__ (
40162306a36Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
40262306a36Sopenharmony_ci"1:	ldarx	%0,0,%1		# atomic64_fetch_add_unless\n\
40362306a36Sopenharmony_ci	cmpd	0,%0,%3 \n\
40462306a36Sopenharmony_ci	beq	2f \n\
40562306a36Sopenharmony_ci	add	%0,%2,%0 \n"
40662306a36Sopenharmony_ci"	stdcx.	%0,0,%1 \n\
40762306a36Sopenharmony_ci	bne-	1b \n"
40862306a36Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
40962306a36Sopenharmony_ci"	subf	%0,%2,%0 \n\
41062306a36Sopenharmony_ci2:"
41162306a36Sopenharmony_ci	: "=&r" (t)
41262306a36Sopenharmony_ci	: "r" (&v->counter), "r" (a), "r" (u)
41362306a36Sopenharmony_ci	: "cc", "memory");
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return t;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/**
42062306a36Sopenharmony_ci * atomic_inc64_not_zero - increment unless the number is zero
42162306a36Sopenharmony_ci * @v: pointer of type atomic64_t
42262306a36Sopenharmony_ci *
42362306a36Sopenharmony_ci * Atomically increments @v by 1, so long as @v is non-zero.
42462306a36Sopenharmony_ci * Returns non-zero if @v was non-zero, and zero otherwise.
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_cistatic __inline__ int arch_atomic64_inc_not_zero(atomic64_t *v)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	s64 t1, t2;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	__asm__ __volatile__ (
43162306a36Sopenharmony_ci	PPC_ATOMIC_ENTRY_BARRIER
43262306a36Sopenharmony_ci"1:	ldarx	%0,0,%2		# atomic64_inc_not_zero\n\
43362306a36Sopenharmony_ci	cmpdi	0,%0,0\n\
43462306a36Sopenharmony_ci	beq-	2f\n\
43562306a36Sopenharmony_ci	addic	%1,%0,1\n\
43662306a36Sopenharmony_ci	stdcx.	%1,0,%2\n\
43762306a36Sopenharmony_ci	bne-	1b\n"
43862306a36Sopenharmony_ci	PPC_ATOMIC_EXIT_BARRIER
43962306a36Sopenharmony_ci	"\n\
44062306a36Sopenharmony_ci2:"
44162306a36Sopenharmony_ci	: "=&r" (t1), "=&r" (t2)
44262306a36Sopenharmony_ci	: "r" (&v->counter)
44362306a36Sopenharmony_ci	: "cc", "xer", "memory");
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return t1 != 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci#define arch_atomic64_inc_not_zero(v) arch_atomic64_inc_not_zero((v))
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci#endif /* __powerpc64__ */
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci#endif /* __KERNEL__ */
45262306a36Sopenharmony_ci#endif /* _ASM_POWERPC_ATOMIC_H_ */
453