162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_IA64_ATOMIC_H
362306a36Sopenharmony_ci#define _ASM_IA64_ATOMIC_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for
762306a36Sopenharmony_ci * resource counting etc..
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * NOTE: don't mess with the types below!  The "unsigned long" and
1062306a36Sopenharmony_ci * "int" types were carefully placed so as to ensure proper operation
1162306a36Sopenharmony_ci * of the macros.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Copyright (C) 1998, 1999, 2002-2003 Hewlett-Packard Co
1462306a36Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/intrinsics.h>
1962306a36Sopenharmony_ci#include <asm/barrier.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define ATOMIC64_INIT(i)	{ (i) }
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define arch_atomic_read(v)	READ_ONCE((v)->counter)
2562306a36Sopenharmony_ci#define arch_atomic64_read(v)	READ_ONCE((v)->counter)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define arch_atomic_set(v,i)	WRITE_ONCE(((v)->counter), (i))
2862306a36Sopenharmony_ci#define arch_atomic64_set(v,i)	WRITE_ONCE(((v)->counter), (i))
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define ATOMIC_OP(op, c_op)						\
3162306a36Sopenharmony_cistatic __inline__ int							\
3262306a36Sopenharmony_ciia64_atomic_##op (int i, atomic_t *v)					\
3362306a36Sopenharmony_ci{									\
3462306a36Sopenharmony_ci	__s32 old, new;							\
3562306a36Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
3662306a36Sopenharmony_ci									\
3762306a36Sopenharmony_ci	do {								\
3862306a36Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
3962306a36Sopenharmony_ci		old = arch_atomic_read(v);				\
4062306a36Sopenharmony_ci		new = old c_op i;					\
4162306a36Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
4262306a36Sopenharmony_ci	return new;							\
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op)					\
4662306a36Sopenharmony_cistatic __inline__ int							\
4762306a36Sopenharmony_ciia64_atomic_fetch_##op (int i, atomic_t *v)				\
4862306a36Sopenharmony_ci{									\
4962306a36Sopenharmony_ci	__s32 old, new;							\
5062306a36Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
5162306a36Sopenharmony_ci									\
5262306a36Sopenharmony_ci	do {								\
5362306a36Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
5462306a36Sopenharmony_ci		old = arch_atomic_read(v);				\
5562306a36Sopenharmony_ci		new = old c_op i;					\
5662306a36Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
5762306a36Sopenharmony_ci	return old;							\
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define ATOMIC_OPS(op, c_op)						\
6162306a36Sopenharmony_ci	ATOMIC_OP(op, c_op)						\
6262306a36Sopenharmony_ci	ATOMIC_FETCH_OP(op, c_op)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciATOMIC_OPS(add, +)
6562306a36Sopenharmony_ciATOMIC_OPS(sub, -)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#ifdef __OPTIMIZE__
6862306a36Sopenharmony_ci#define __ia64_atomic_const(i)						\
6962306a36Sopenharmony_ci	static const int __ia64_atomic_p = __builtin_constant_p(i) ?	\
7062306a36Sopenharmony_ci		((i) == 1 || (i) == 4 || (i) == 8 || (i) == 16 ||	\
7162306a36Sopenharmony_ci		 (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0;\
7262306a36Sopenharmony_ci	__ia64_atomic_p
7362306a36Sopenharmony_ci#else
7462306a36Sopenharmony_ci#define __ia64_atomic_const(i)	0
7562306a36Sopenharmony_ci#endif
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define arch_atomic_add_return(i,v)					\
7862306a36Sopenharmony_ci({									\
7962306a36Sopenharmony_ci	int __ia64_aar_i = (i);						\
8062306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
8162306a36Sopenharmony_ci		? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)	\
8262306a36Sopenharmony_ci		: ia64_atomic_add(__ia64_aar_i, v);			\
8362306a36Sopenharmony_ci})
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define arch_atomic_sub_return(i,v)					\
8662306a36Sopenharmony_ci({									\
8762306a36Sopenharmony_ci	int __ia64_asr_i = (i);						\
8862306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
8962306a36Sopenharmony_ci		? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)	\
9062306a36Sopenharmony_ci		: ia64_atomic_sub(__ia64_asr_i, v);			\
9162306a36Sopenharmony_ci})
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define arch_atomic_fetch_add(i,v)					\
9462306a36Sopenharmony_ci({									\
9562306a36Sopenharmony_ci	int __ia64_aar_i = (i);						\
9662306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
9762306a36Sopenharmony_ci		? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)	\
9862306a36Sopenharmony_ci		: ia64_atomic_fetch_add(__ia64_aar_i, v);		\
9962306a36Sopenharmony_ci})
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define arch_atomic_fetch_sub(i,v)					\
10262306a36Sopenharmony_ci({									\
10362306a36Sopenharmony_ci	int __ia64_asr_i = (i);						\
10462306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
10562306a36Sopenharmony_ci		? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)	\
10662306a36Sopenharmony_ci		: ia64_atomic_fetch_sub(__ia64_asr_i, v);		\
10762306a36Sopenharmony_ci})
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciATOMIC_FETCH_OP(and, &)
11062306a36Sopenharmony_ciATOMIC_FETCH_OP(or, |)
11162306a36Sopenharmony_ciATOMIC_FETCH_OP(xor, ^)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define arch_atomic_and(i,v)	(void)ia64_atomic_fetch_and(i,v)
11462306a36Sopenharmony_ci#define arch_atomic_or(i,v)	(void)ia64_atomic_fetch_or(i,v)
11562306a36Sopenharmony_ci#define arch_atomic_xor(i,v)	(void)ia64_atomic_fetch_xor(i,v)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define arch_atomic_fetch_and(i,v)	ia64_atomic_fetch_and(i,v)
11862306a36Sopenharmony_ci#define arch_atomic_fetch_or(i,v)	ia64_atomic_fetch_or(i,v)
11962306a36Sopenharmony_ci#define arch_atomic_fetch_xor(i,v)	ia64_atomic_fetch_xor(i,v)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#undef ATOMIC_OPS
12262306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP
12362306a36Sopenharmony_ci#undef ATOMIC_OP
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define ATOMIC64_OP(op, c_op)						\
12662306a36Sopenharmony_cistatic __inline__ s64							\
12762306a36Sopenharmony_ciia64_atomic64_##op (s64 i, atomic64_t *v)				\
12862306a36Sopenharmony_ci{									\
12962306a36Sopenharmony_ci	s64 old, new;							\
13062306a36Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
13162306a36Sopenharmony_ci									\
13262306a36Sopenharmony_ci	do {								\
13362306a36Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
13462306a36Sopenharmony_ci		old = arch_atomic64_read(v);				\
13562306a36Sopenharmony_ci		new = old c_op i;					\
13662306a36Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
13762306a36Sopenharmony_ci	return new;							\
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, c_op)					\
14162306a36Sopenharmony_cistatic __inline__ s64							\
14262306a36Sopenharmony_ciia64_atomic64_fetch_##op (s64 i, atomic64_t *v)				\
14362306a36Sopenharmony_ci{									\
14462306a36Sopenharmony_ci	s64 old, new;							\
14562306a36Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
14662306a36Sopenharmony_ci									\
14762306a36Sopenharmony_ci	do {								\
14862306a36Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
14962306a36Sopenharmony_ci		old = arch_atomic64_read(v);				\
15062306a36Sopenharmony_ci		new = old c_op i;					\
15162306a36Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
15262306a36Sopenharmony_ci	return old;							\
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#define ATOMIC64_OPS(op, c_op)						\
15662306a36Sopenharmony_ci	ATOMIC64_OP(op, c_op)						\
15762306a36Sopenharmony_ci	ATOMIC64_FETCH_OP(op, c_op)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciATOMIC64_OPS(add, +)
16062306a36Sopenharmony_ciATOMIC64_OPS(sub, -)
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define arch_atomic64_add_return(i,v)					\
16362306a36Sopenharmony_ci({									\
16462306a36Sopenharmony_ci	s64 __ia64_aar_i = (i);						\
16562306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
16662306a36Sopenharmony_ci		? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)	\
16762306a36Sopenharmony_ci		: ia64_atomic64_add(__ia64_aar_i, v);			\
16862306a36Sopenharmony_ci})
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define arch_atomic64_sub_return(i,v)					\
17162306a36Sopenharmony_ci({									\
17262306a36Sopenharmony_ci	s64 __ia64_asr_i = (i);						\
17362306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
17462306a36Sopenharmony_ci		? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)	\
17562306a36Sopenharmony_ci		: ia64_atomic64_sub(__ia64_asr_i, v);			\
17662306a36Sopenharmony_ci})
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define arch_atomic64_fetch_add(i,v)					\
17962306a36Sopenharmony_ci({									\
18062306a36Sopenharmony_ci	s64 __ia64_aar_i = (i);						\
18162306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
18262306a36Sopenharmony_ci		? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)	\
18362306a36Sopenharmony_ci		: ia64_atomic64_fetch_add(__ia64_aar_i, v);		\
18462306a36Sopenharmony_ci})
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define arch_atomic64_fetch_sub(i,v)					\
18762306a36Sopenharmony_ci({									\
18862306a36Sopenharmony_ci	s64 __ia64_asr_i = (i);						\
18962306a36Sopenharmony_ci	__ia64_atomic_const(i)						\
19062306a36Sopenharmony_ci		? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)	\
19162306a36Sopenharmony_ci		: ia64_atomic64_fetch_sub(__ia64_asr_i, v);		\
19262306a36Sopenharmony_ci})
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciATOMIC64_FETCH_OP(and, &)
19562306a36Sopenharmony_ciATOMIC64_FETCH_OP(or, |)
19662306a36Sopenharmony_ciATOMIC64_FETCH_OP(xor, ^)
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#define arch_atomic64_and(i,v)	(void)ia64_atomic64_fetch_and(i,v)
19962306a36Sopenharmony_ci#define arch_atomic64_or(i,v)	(void)ia64_atomic64_fetch_or(i,v)
20062306a36Sopenharmony_ci#define arch_atomic64_xor(i,v)	(void)ia64_atomic64_fetch_xor(i,v)
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#define arch_atomic64_fetch_and(i,v)	ia64_atomic64_fetch_and(i,v)
20362306a36Sopenharmony_ci#define arch_atomic64_fetch_or(i,v)	ia64_atomic64_fetch_or(i,v)
20462306a36Sopenharmony_ci#define arch_atomic64_fetch_xor(i,v)	ia64_atomic64_fetch_xor(i,v)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#undef ATOMIC64_OPS
20762306a36Sopenharmony_ci#undef ATOMIC64_FETCH_OP
20862306a36Sopenharmony_ci#undef ATOMIC64_OP
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define arch_atomic_add(i,v)		(void)arch_atomic_add_return((i), (v))
21162306a36Sopenharmony_ci#define arch_atomic_sub(i,v)		(void)arch_atomic_sub_return((i), (v))
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#define arch_atomic64_add(i,v)		(void)arch_atomic64_add_return((i), (v))
21462306a36Sopenharmony_ci#define arch_atomic64_sub(i,v)		(void)arch_atomic64_sub_return((i), (v))
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci#endif /* _ASM_IA64_ATOMIC_H */
217