18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_IA64_ATOMIC_H
38c2ecf20Sopenharmony_ci#define _ASM_IA64_ATOMIC_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us.  Useful for
78c2ecf20Sopenharmony_ci * resource counting etc..
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * NOTE: don't mess with the types below!  The "unsigned long" and
108c2ecf20Sopenharmony_ci * "int" types were carefully placed so as to ensure proper operation
118c2ecf20Sopenharmony_ci * of the macros.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999, 2002-2003 Hewlett-Packard Co
148c2ecf20Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#include <linux/types.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/intrinsics.h>
198c2ecf20Sopenharmony_ci#include <asm/barrier.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i)	{ (i) }
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define atomic_read(v)		READ_ONCE((v)->counter)
258c2ecf20Sopenharmony_ci#define atomic64_read(v)	READ_ONCE((v)->counter)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define atomic_set(v,i)		WRITE_ONCE(((v)->counter), (i))
288c2ecf20Sopenharmony_ci#define atomic64_set(v,i)	WRITE_ONCE(((v)->counter), (i))
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define ATOMIC_OP(op, c_op)						\
318c2ecf20Sopenharmony_cistatic __inline__ int							\
328c2ecf20Sopenharmony_ciia64_atomic_##op (int i, atomic_t *v)					\
338c2ecf20Sopenharmony_ci{									\
348c2ecf20Sopenharmony_ci	__s32 old, new;							\
358c2ecf20Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
368c2ecf20Sopenharmony_ci									\
378c2ecf20Sopenharmony_ci	do {								\
388c2ecf20Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
398c2ecf20Sopenharmony_ci		old = atomic_read(v);					\
408c2ecf20Sopenharmony_ci		new = old c_op i;					\
418c2ecf20Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
428c2ecf20Sopenharmony_ci	return new;							\
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op)					\
468c2ecf20Sopenharmony_cistatic __inline__ int							\
478c2ecf20Sopenharmony_ciia64_atomic_fetch_##op (int i, atomic_t *v)				\
488c2ecf20Sopenharmony_ci{									\
498c2ecf20Sopenharmony_ci	__s32 old, new;							\
508c2ecf20Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
518c2ecf20Sopenharmony_ci									\
528c2ecf20Sopenharmony_ci	do {								\
538c2ecf20Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
548c2ecf20Sopenharmony_ci		old = atomic_read(v);					\
558c2ecf20Sopenharmony_ci		new = old c_op i;					\
568c2ecf20Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
578c2ecf20Sopenharmony_ci	return old;							\
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op, c_op)						\
618c2ecf20Sopenharmony_ci	ATOMIC_OP(op, c_op)						\
628c2ecf20Sopenharmony_ci	ATOMIC_FETCH_OP(op, c_op)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciATOMIC_OPS(add, +)
658c2ecf20Sopenharmony_ciATOMIC_OPS(sub, -)
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#ifdef __OPTIMIZE__
688c2ecf20Sopenharmony_ci#define __ia64_atomic_const(i)						\
698c2ecf20Sopenharmony_ci	static const int __ia64_atomic_p = __builtin_constant_p(i) ?	\
708c2ecf20Sopenharmony_ci		((i) == 1 || (i) == 4 || (i) == 8 || (i) == 16 ||	\
718c2ecf20Sopenharmony_ci		 (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0;\
728c2ecf20Sopenharmony_ci	__ia64_atomic_p
738c2ecf20Sopenharmony_ci#else
748c2ecf20Sopenharmony_ci#define __ia64_atomic_const(i)	0
758c2ecf20Sopenharmony_ci#endif
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define atomic_add_return(i,v)						\
788c2ecf20Sopenharmony_ci({									\
798c2ecf20Sopenharmony_ci	int __ia64_aar_i = (i);						\
808c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
818c2ecf20Sopenharmony_ci		? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)	\
828c2ecf20Sopenharmony_ci		: ia64_atomic_add(__ia64_aar_i, v);			\
838c2ecf20Sopenharmony_ci})
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define atomic_sub_return(i,v)						\
868c2ecf20Sopenharmony_ci({									\
878c2ecf20Sopenharmony_ci	int __ia64_asr_i = (i);						\
888c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
898c2ecf20Sopenharmony_ci		? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)	\
908c2ecf20Sopenharmony_ci		: ia64_atomic_sub(__ia64_asr_i, v);			\
918c2ecf20Sopenharmony_ci})
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define atomic_fetch_add(i,v)						\
948c2ecf20Sopenharmony_ci({									\
958c2ecf20Sopenharmony_ci	int __ia64_aar_i = (i);						\
968c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
978c2ecf20Sopenharmony_ci		? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)	\
988c2ecf20Sopenharmony_ci		: ia64_atomic_fetch_add(__ia64_aar_i, v);		\
998c2ecf20Sopenharmony_ci})
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define atomic_fetch_sub(i,v)						\
1028c2ecf20Sopenharmony_ci({									\
1038c2ecf20Sopenharmony_ci	int __ia64_asr_i = (i);						\
1048c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
1058c2ecf20Sopenharmony_ci		? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)	\
1068c2ecf20Sopenharmony_ci		: ia64_atomic_fetch_sub(__ia64_asr_i, v);		\
1078c2ecf20Sopenharmony_ci})
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and, &)
1108c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or, |)
1118c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor, ^)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define atomic_and(i,v)	(void)ia64_atomic_fetch_and(i,v)
1148c2ecf20Sopenharmony_ci#define atomic_or(i,v)	(void)ia64_atomic_fetch_or(i,v)
1158c2ecf20Sopenharmony_ci#define atomic_xor(i,v)	(void)ia64_atomic_fetch_xor(i,v)
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define atomic_fetch_and(i,v)	ia64_atomic_fetch_and(i,v)
1188c2ecf20Sopenharmony_ci#define atomic_fetch_or(i,v)	ia64_atomic_fetch_or(i,v)
1198c2ecf20Sopenharmony_ci#define atomic_fetch_xor(i,v)	ia64_atomic_fetch_xor(i,v)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#undef ATOMIC_OPS
1228c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP
1238c2ecf20Sopenharmony_ci#undef ATOMIC_OP
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op, c_op)						\
1268c2ecf20Sopenharmony_cistatic __inline__ s64							\
1278c2ecf20Sopenharmony_ciia64_atomic64_##op (s64 i, atomic64_t *v)				\
1288c2ecf20Sopenharmony_ci{									\
1298c2ecf20Sopenharmony_ci	s64 old, new;							\
1308c2ecf20Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
1318c2ecf20Sopenharmony_ci									\
1328c2ecf20Sopenharmony_ci	do {								\
1338c2ecf20Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
1348c2ecf20Sopenharmony_ci		old = atomic64_read(v);					\
1358c2ecf20Sopenharmony_ci		new = old c_op i;					\
1368c2ecf20Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
1378c2ecf20Sopenharmony_ci	return new;							\
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op, c_op)					\
1418c2ecf20Sopenharmony_cistatic __inline__ s64							\
1428c2ecf20Sopenharmony_ciia64_atomic64_fetch_##op (s64 i, atomic64_t *v)				\
1438c2ecf20Sopenharmony_ci{									\
1448c2ecf20Sopenharmony_ci	s64 old, new;							\
1458c2ecf20Sopenharmony_ci	CMPXCHG_BUGCHECK_DECL						\
1468c2ecf20Sopenharmony_ci									\
1478c2ecf20Sopenharmony_ci	do {								\
1488c2ecf20Sopenharmony_ci		CMPXCHG_BUGCHECK(v);					\
1498c2ecf20Sopenharmony_ci		old = atomic64_read(v);					\
1508c2ecf20Sopenharmony_ci		new = old c_op i;					\
1518c2ecf20Sopenharmony_ci	} while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
1528c2ecf20Sopenharmony_ci	return old;							\
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op, c_op)						\
1568c2ecf20Sopenharmony_ci	ATOMIC64_OP(op, c_op)						\
1578c2ecf20Sopenharmony_ci	ATOMIC64_FETCH_OP(op, c_op)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ciATOMIC64_OPS(add, +)
1608c2ecf20Sopenharmony_ciATOMIC64_OPS(sub, -)
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci#define atomic64_add_return(i,v)					\
1638c2ecf20Sopenharmony_ci({									\
1648c2ecf20Sopenharmony_ci	s64 __ia64_aar_i = (i);						\
1658c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
1668c2ecf20Sopenharmony_ci		? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)	\
1678c2ecf20Sopenharmony_ci		: ia64_atomic64_add(__ia64_aar_i, v);			\
1688c2ecf20Sopenharmony_ci})
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define atomic64_sub_return(i,v)					\
1718c2ecf20Sopenharmony_ci({									\
1728c2ecf20Sopenharmony_ci	s64 __ia64_asr_i = (i);						\
1738c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
1748c2ecf20Sopenharmony_ci		? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)	\
1758c2ecf20Sopenharmony_ci		: ia64_atomic64_sub(__ia64_asr_i, v);			\
1768c2ecf20Sopenharmony_ci})
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci#define atomic64_fetch_add(i,v)						\
1798c2ecf20Sopenharmony_ci({									\
1808c2ecf20Sopenharmony_ci	s64 __ia64_aar_i = (i);						\
1818c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
1828c2ecf20Sopenharmony_ci		? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)	\
1838c2ecf20Sopenharmony_ci		: ia64_atomic64_fetch_add(__ia64_aar_i, v);		\
1848c2ecf20Sopenharmony_ci})
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#define atomic64_fetch_sub(i,v)						\
1878c2ecf20Sopenharmony_ci({									\
1888c2ecf20Sopenharmony_ci	s64 __ia64_asr_i = (i);						\
1898c2ecf20Sopenharmony_ci	__ia64_atomic_const(i)						\
1908c2ecf20Sopenharmony_ci		? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)	\
1918c2ecf20Sopenharmony_ci		: ia64_atomic64_fetch_sub(__ia64_asr_i, v);		\
1928c2ecf20Sopenharmony_ci})
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(and, &)
1958c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(or, |)
1968c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(xor, ^)
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci#define atomic64_and(i,v)	(void)ia64_atomic64_fetch_and(i,v)
1998c2ecf20Sopenharmony_ci#define atomic64_or(i,v)	(void)ia64_atomic64_fetch_or(i,v)
2008c2ecf20Sopenharmony_ci#define atomic64_xor(i,v)	(void)ia64_atomic64_fetch_xor(i,v)
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define atomic64_fetch_and(i,v)	ia64_atomic64_fetch_and(i,v)
2038c2ecf20Sopenharmony_ci#define atomic64_fetch_or(i,v)	ia64_atomic64_fetch_or(i,v)
2048c2ecf20Sopenharmony_ci#define atomic64_fetch_xor(i,v)	ia64_atomic64_fetch_xor(i,v)
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS
2078c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP
2088c2ecf20Sopenharmony_ci#undef ATOMIC64_OP
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
2118c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci#define atomic64_cmpxchg(v, old, new) \
2148c2ecf20Sopenharmony_ci	(cmpxchg(&((v)->counter), old, new))
2158c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci#define atomic_add(i,v)			(void)atomic_add_return((i), (v))
2188c2ecf20Sopenharmony_ci#define atomic_sub(i,v)			(void)atomic_sub_return((i), (v))
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define atomic64_add(i,v)		(void)atomic64_add_return((i), (v))
2218c2ecf20Sopenharmony_ci#define atomic64_sub(i,v)		(void)atomic64_sub_return((i), (v))
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci#endif /* _ASM_IA64_ATOMIC_H */
224