18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Low level function for atomic operations
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2016
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef __ARCH_S390_ATOMIC_OPS__
98c2ecf20Sopenharmony_ci#define __ARCH_S390_ATOMIC_OPS__
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define __ATOMIC_OP(op_name, op_type, op_string, op_barrier)		\
148c2ecf20Sopenharmony_cistatic inline op_type op_name(op_type val, op_type *ptr)		\
158c2ecf20Sopenharmony_ci{									\
168c2ecf20Sopenharmony_ci	op_type old;							\
178c2ecf20Sopenharmony_ci									\
188c2ecf20Sopenharmony_ci	asm volatile(							\
198c2ecf20Sopenharmony_ci		op_string "	%[old],%[val],%[ptr]\n"			\
208c2ecf20Sopenharmony_ci		op_barrier						\
218c2ecf20Sopenharmony_ci		: [old] "=d" (old), [ptr] "+Q" (*ptr)			\
228c2ecf20Sopenharmony_ci		: [val] "d" (val) : "cc", "memory");			\
238c2ecf20Sopenharmony_ci	return old;							\
248c2ecf20Sopenharmony_ci}									\
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define __ATOMIC_OPS(op_name, op_type, op_string)			\
278c2ecf20Sopenharmony_ci	__ATOMIC_OP(op_name, op_type, op_string, "\n")			\
288c2ecf20Sopenharmony_ci	__ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_add, int, "laa")
318c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_and, int, "lan")
328c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_or,  int, "lao")
338c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_xor, int, "lax")
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic64_add, long, "laag")
368c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic64_and, long, "lang")
378c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic64_or,  long, "laog")
388c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic64_xor, long, "laxg")
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#undef __ATOMIC_OPS
418c2ecf20Sopenharmony_ci#undef __ATOMIC_OP
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define __ATOMIC_CONST_OP(op_name, op_type, op_string, op_barrier)	\
448c2ecf20Sopenharmony_cistatic __always_inline void op_name(op_type val, op_type *ptr)		\
458c2ecf20Sopenharmony_ci{									\
468c2ecf20Sopenharmony_ci	asm volatile(							\
478c2ecf20Sopenharmony_ci		op_string "	%[ptr],%[val]\n"			\
488c2ecf20Sopenharmony_ci		op_barrier						\
498c2ecf20Sopenharmony_ci		: [ptr] "+Q" (*ptr) : [val] "i" (val) : "cc", "memory");\
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define __ATOMIC_CONST_OPS(op_name, op_type, op_string)			\
538c2ecf20Sopenharmony_ci	__ATOMIC_CONST_OP(op_name, op_type, op_string, "\n")		\
548c2ecf20Sopenharmony_ci	__ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci__ATOMIC_CONST_OPS(__atomic_add_const, int, "asi")
578c2ecf20Sopenharmony_ci__ATOMIC_CONST_OPS(__atomic64_add_const, long, "agsi")
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#undef __ATOMIC_CONST_OPS
608c2ecf20Sopenharmony_ci#undef __ATOMIC_CONST_OP
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define __ATOMIC_OP(op_name, op_string)					\
658c2ecf20Sopenharmony_cistatic inline int op_name(int val, int *ptr)				\
668c2ecf20Sopenharmony_ci{									\
678c2ecf20Sopenharmony_ci	int old, new;							\
688c2ecf20Sopenharmony_ci									\
698c2ecf20Sopenharmony_ci	asm volatile(							\
708c2ecf20Sopenharmony_ci		"0:	lr	%[new],%[old]\n"			\
718c2ecf20Sopenharmony_ci		op_string "	%[new],%[val]\n"			\
728c2ecf20Sopenharmony_ci		"	cs	%[old],%[new],%[ptr]\n"			\
738c2ecf20Sopenharmony_ci		"	jl	0b"					\
748c2ecf20Sopenharmony_ci		: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
758c2ecf20Sopenharmony_ci		: [val] "d" (val), "0" (*ptr) : "cc", "memory");	\
768c2ecf20Sopenharmony_ci	return old;							\
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define __ATOMIC_OPS(op_name, op_string)				\
808c2ecf20Sopenharmony_ci	__ATOMIC_OP(op_name, op_string)					\
818c2ecf20Sopenharmony_ci	__ATOMIC_OP(op_name##_barrier, op_string)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_add, "ar")
848c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_and, "nr")
858c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_or,  "or")
868c2ecf20Sopenharmony_ci__ATOMIC_OPS(__atomic_xor, "xr")
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#undef __ATOMIC_OPS
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define __ATOMIC64_OP(op_name, op_string)				\
918c2ecf20Sopenharmony_cistatic inline long op_name(long val, long *ptr)				\
928c2ecf20Sopenharmony_ci{									\
938c2ecf20Sopenharmony_ci	long old, new;							\
948c2ecf20Sopenharmony_ci									\
958c2ecf20Sopenharmony_ci	asm volatile(							\
968c2ecf20Sopenharmony_ci		"0:	lgr	%[new],%[old]\n"			\
978c2ecf20Sopenharmony_ci		op_string "	%[new],%[val]\n"			\
988c2ecf20Sopenharmony_ci		"	csg	%[old],%[new],%[ptr]\n"			\
998c2ecf20Sopenharmony_ci		"	jl	0b"					\
1008c2ecf20Sopenharmony_ci		: [old] "=d" (old), [new] "=&d" (new), [ptr] "+Q" (*ptr)\
1018c2ecf20Sopenharmony_ci		: [val] "d" (val), "0" (*ptr) : "cc", "memory");	\
1028c2ecf20Sopenharmony_ci	return old;							\
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define __ATOMIC64_OPS(op_name, op_string)				\
1068c2ecf20Sopenharmony_ci	__ATOMIC64_OP(op_name, op_string)				\
1078c2ecf20Sopenharmony_ci	__ATOMIC64_OP(op_name##_barrier, op_string)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci__ATOMIC64_OPS(__atomic64_add, "agr")
1108c2ecf20Sopenharmony_ci__ATOMIC64_OPS(__atomic64_and, "ngr")
1118c2ecf20Sopenharmony_ci__ATOMIC64_OPS(__atomic64_or,  "ogr")
1128c2ecf20Sopenharmony_ci__ATOMIC64_OPS(__atomic64_xor, "xgr")
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#undef __ATOMIC64_OPS
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci#define __atomic_add_const(val, ptr)		__atomic_add(val, ptr)
1178c2ecf20Sopenharmony_ci#define __atomic_add_const_barrier(val, ptr)	__atomic_add(val, ptr)
1188c2ecf20Sopenharmony_ci#define __atomic64_add_const(val, ptr)		__atomic64_add(val, ptr)
1198c2ecf20Sopenharmony_ci#define __atomic64_add_const_barrier(val, ptr)	__atomic64_add(val, ptr)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline int __atomic_cmpxchg(int *ptr, int old, int new)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return __sync_val_compare_and_swap(ptr, old, new);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline int __atomic_cmpxchg_bool(int *ptr, int old, int new)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	return __sync_bool_compare_and_swap(ptr, old, new);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic inline long __atomic64_cmpxchg(long *ptr, long old, long new)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	return __sync_val_compare_and_swap(ptr, old, new);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic inline long __atomic64_cmpxchg_bool(long *ptr, long old, long new)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return __sync_bool_compare_and_swap(ptr, old, new);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#endif /* __ARCH_S390_ATOMIC_OPS__  */
144