18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __ARCH_S390_PERCPU__
38c2ecf20Sopenharmony_ci#define __ARCH_S390_PERCPU__
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/preempt.h>
68c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci * s390 uses its own implementation for per cpu data, the offset of
108c2ecf20Sopenharmony_ci * the cpu local data area is cached in the cpu's lowcore memory.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#define __my_cpu_offset S390_lowcore.percpu_offset
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * For 64 bit module code, the module may be more than 4G above the
168c2ecf20Sopenharmony_ci * per cpu area, use weak definitions to force the compiler to
178c2ecf20Sopenharmony_ci * generate external references.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci#if defined(MODULE)
208c2ecf20Sopenharmony_ci#define ARCH_NEEDS_WEAK_PER_CPU
218c2ecf20Sopenharmony_ci#endif
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * We use a compare-and-swap loop since that uses less cpu cycles than
258c2ecf20Sopenharmony_ci * disabling and enabling interrupts like the generic variant would do.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci#define arch_this_cpu_to_op_simple(pcp, val, op)			\
288c2ecf20Sopenharmony_ci({									\
298c2ecf20Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__;					\
308c2ecf20Sopenharmony_ci	pcp_op_T__ old__, new__, prev__;				\
318c2ecf20Sopenharmony_ci	pcp_op_T__ *ptr__;						\
328c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
338c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
348c2ecf20Sopenharmony_ci	prev__ = READ_ONCE(*ptr__);					\
358c2ecf20Sopenharmony_ci	do {								\
368c2ecf20Sopenharmony_ci		old__ = prev__;						\
378c2ecf20Sopenharmony_ci		new__ = old__ op (val);					\
388c2ecf20Sopenharmony_ci		prev__ = cmpxchg(ptr__, old__, new__);			\
398c2ecf20Sopenharmony_ci	} while (prev__ != old__);					\
408c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
418c2ecf20Sopenharmony_ci	new__;								\
428c2ecf20Sopenharmony_ci})
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define this_cpu_add_1(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
458c2ecf20Sopenharmony_ci#define this_cpu_add_2(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
468c2ecf20Sopenharmony_ci#define this_cpu_add_return_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
478c2ecf20Sopenharmony_ci#define this_cpu_add_return_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
488c2ecf20Sopenharmony_ci#define this_cpu_and_1(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
498c2ecf20Sopenharmony_ci#define this_cpu_and_2(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
508c2ecf20Sopenharmony_ci#define this_cpu_or_1(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
518c2ecf20Sopenharmony_ci#define this_cpu_or_2(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#ifndef CONFIG_HAVE_MARCH_Z196_FEATURES
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define this_cpu_add_4(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
568c2ecf20Sopenharmony_ci#define this_cpu_add_8(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
578c2ecf20Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
588c2ecf20Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
598c2ecf20Sopenharmony_ci#define this_cpu_and_4(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
608c2ecf20Sopenharmony_ci#define this_cpu_and_8(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
618c2ecf20Sopenharmony_ci#define this_cpu_or_4(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
628c2ecf20Sopenharmony_ci#define this_cpu_or_8(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define arch_this_cpu_add(pcp, val, op1, op2, szcast)			\
678c2ecf20Sopenharmony_ci{									\
688c2ecf20Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
698c2ecf20Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
708c2ecf20Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
718c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
728c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp)); 				\
738c2ecf20Sopenharmony_ci	if (__builtin_constant_p(val__) &&				\
748c2ecf20Sopenharmony_ci	    ((szcast)val__ > -129) && ((szcast)val__ < 128)) {		\
758c2ecf20Sopenharmony_ci		asm volatile(						\
768c2ecf20Sopenharmony_ci			op2 "   %[ptr__],%[val__]\n"			\
778c2ecf20Sopenharmony_ci			: [ptr__] "+Q" (*ptr__) 			\
788c2ecf20Sopenharmony_ci			: [val__] "i" ((szcast)val__)			\
798c2ecf20Sopenharmony_ci			: "cc");					\
808c2ecf20Sopenharmony_ci	} else {							\
818c2ecf20Sopenharmony_ci		asm volatile(						\
828c2ecf20Sopenharmony_ci			op1 "   %[old__],%[val__],%[ptr__]\n"		\
838c2ecf20Sopenharmony_ci			: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)	\
848c2ecf20Sopenharmony_ci			: [val__] "d" (val__)				\
858c2ecf20Sopenharmony_ci			: "cc");					\
868c2ecf20Sopenharmony_ci	}								\
878c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int)
918c2ecf20Sopenharmony_ci#define this_cpu_add_8(pcp, val) arch_this_cpu_add(pcp, val, "laag", "agsi", long)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define arch_this_cpu_add_return(pcp, val, op)				\
948c2ecf20Sopenharmony_ci({									\
958c2ecf20Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
968c2ecf20Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
978c2ecf20Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
988c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
998c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));	 				\
1008c2ecf20Sopenharmony_ci	asm volatile(							\
1018c2ecf20Sopenharmony_ci		op "    %[old__],%[val__],%[ptr__]\n"			\
1028c2ecf20Sopenharmony_ci		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
1038c2ecf20Sopenharmony_ci		: [val__] "d" (val__)					\
1048c2ecf20Sopenharmony_ci		: "cc");						\
1058c2ecf20Sopenharmony_ci	preempt_enable_notrace();						\
1068c2ecf20Sopenharmony_ci	old__ + val__;							\
1078c2ecf20Sopenharmony_ci})
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) arch_this_cpu_add_return(pcp, val, "laa")
1108c2ecf20Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) arch_this_cpu_add_return(pcp, val, "laag")
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define arch_this_cpu_to_op(pcp, val, op)				\
1138c2ecf20Sopenharmony_ci{									\
1148c2ecf20Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
1158c2ecf20Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
1168c2ecf20Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
1178c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
1188c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));	 				\
1198c2ecf20Sopenharmony_ci	asm volatile(							\
1208c2ecf20Sopenharmony_ci		op "    %[old__],%[val__],%[ptr__]\n"			\
1218c2ecf20Sopenharmony_ci		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
1228c2ecf20Sopenharmony_ci		: [val__] "d" (val__)					\
1238c2ecf20Sopenharmony_ci		: "cc");						\
1248c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define this_cpu_and_4(pcp, val)	arch_this_cpu_to_op(pcp, val, "lan")
1288c2ecf20Sopenharmony_ci#define this_cpu_and_8(pcp, val)	arch_this_cpu_to_op(pcp, val, "lang")
1298c2ecf20Sopenharmony_ci#define this_cpu_or_4(pcp, val)		arch_this_cpu_to_op(pcp, val, "lao")
1308c2ecf20Sopenharmony_ci#define this_cpu_or_8(pcp, val)		arch_this_cpu_to_op(pcp, val, "laog")
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define arch_this_cpu_cmpxchg(pcp, oval, nval)				\
1358c2ecf20Sopenharmony_ci({									\
1368c2ecf20Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__;					\
1378c2ecf20Sopenharmony_ci	pcp_op_T__ ret__;						\
1388c2ecf20Sopenharmony_ci	pcp_op_T__ *ptr__;						\
1398c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
1408c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
1418c2ecf20Sopenharmony_ci	ret__ = cmpxchg(ptr__, oval, nval);				\
1428c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
1438c2ecf20Sopenharmony_ci	ret__;								\
1448c2ecf20Sopenharmony_ci})
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_1(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
1478c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_2(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
1488c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
1498c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define arch_this_cpu_xchg(pcp, nval)					\
1528c2ecf20Sopenharmony_ci({									\
1538c2ecf20Sopenharmony_ci	typeof(pcp) *ptr__;						\
1548c2ecf20Sopenharmony_ci	typeof(pcp) ret__;						\
1558c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
1568c2ecf20Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
1578c2ecf20Sopenharmony_ci	ret__ = xchg(ptr__, nval);					\
1588c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
1598c2ecf20Sopenharmony_ci	ret__;								\
1608c2ecf20Sopenharmony_ci})
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci#define this_cpu_xchg_1(pcp, nval) arch_this_cpu_xchg(pcp, nval)
1638c2ecf20Sopenharmony_ci#define this_cpu_xchg_2(pcp, nval) arch_this_cpu_xchg(pcp, nval)
1648c2ecf20Sopenharmony_ci#define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval)
1658c2ecf20Sopenharmony_ci#define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval)
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci#define arch_this_cpu_cmpxchg_double(pcp1, pcp2, o1, o2, n1, n2)	\
1688c2ecf20Sopenharmony_ci({									\
1698c2ecf20Sopenharmony_ci	typeof(pcp1) o1__ = (o1), n1__ = (n1);				\
1708c2ecf20Sopenharmony_ci	typeof(pcp2) o2__ = (o2), n2__ = (n2);				\
1718c2ecf20Sopenharmony_ci	typeof(pcp1) *p1__;						\
1728c2ecf20Sopenharmony_ci	typeof(pcp2) *p2__;						\
1738c2ecf20Sopenharmony_ci	int ret__;							\
1748c2ecf20Sopenharmony_ci	preempt_disable_notrace();					\
1758c2ecf20Sopenharmony_ci	p1__ = raw_cpu_ptr(&(pcp1));					\
1768c2ecf20Sopenharmony_ci	p2__ = raw_cpu_ptr(&(pcp2));					\
1778c2ecf20Sopenharmony_ci	ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__);	\
1788c2ecf20Sopenharmony_ci	preempt_enable_notrace();					\
1798c2ecf20Sopenharmony_ci	ret__;								\
1808c2ecf20Sopenharmony_ci})
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci#include <asm-generic/percpu.h>
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#endif /* __ARCH_S390_PERCPU__ */
187