162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __ARCH_S390_PERCPU__
362306a36Sopenharmony_ci#define __ARCH_S390_PERCPU__
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/preempt.h>
662306a36Sopenharmony_ci#include <asm/cmpxchg.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * s390 uses its own implementation for per cpu data, the offset of
1062306a36Sopenharmony_ci * the cpu local data area is cached in the cpu's lowcore memory.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#define __my_cpu_offset S390_lowcore.percpu_offset
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * For 64 bit module code, the module may be more than 4G above the
1662306a36Sopenharmony_ci * per cpu area, use weak definitions to force the compiler to
1762306a36Sopenharmony_ci * generate external references.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci#if defined(MODULE)
2062306a36Sopenharmony_ci#define ARCH_NEEDS_WEAK_PER_CPU
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * We use a compare-and-swap loop since that uses less cpu cycles than
2562306a36Sopenharmony_ci * disabling and enabling interrupts like the generic variant would do.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#define arch_this_cpu_to_op_simple(pcp, val, op)			\
2862306a36Sopenharmony_ci({									\
2962306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__;					\
3062306a36Sopenharmony_ci	pcp_op_T__ old__, new__, prev__;				\
3162306a36Sopenharmony_ci	pcp_op_T__ *ptr__;						\
3262306a36Sopenharmony_ci	preempt_disable_notrace();					\
3362306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
3462306a36Sopenharmony_ci	prev__ = READ_ONCE(*ptr__);					\
3562306a36Sopenharmony_ci	do {								\
3662306a36Sopenharmony_ci		old__ = prev__;						\
3762306a36Sopenharmony_ci		new__ = old__ op (val);					\
3862306a36Sopenharmony_ci		prev__ = cmpxchg(ptr__, old__, new__);			\
3962306a36Sopenharmony_ci	} while (prev__ != old__);					\
4062306a36Sopenharmony_ci	preempt_enable_notrace();					\
4162306a36Sopenharmony_ci	new__;								\
4262306a36Sopenharmony_ci})
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define this_cpu_add_1(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
4562306a36Sopenharmony_ci#define this_cpu_add_2(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
4662306a36Sopenharmony_ci#define this_cpu_add_return_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
4762306a36Sopenharmony_ci#define this_cpu_add_return_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
4862306a36Sopenharmony_ci#define this_cpu_and_1(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
4962306a36Sopenharmony_ci#define this_cpu_and_2(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
5062306a36Sopenharmony_ci#define this_cpu_or_1(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
5162306a36Sopenharmony_ci#define this_cpu_or_2(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#ifndef CONFIG_HAVE_MARCH_Z196_FEATURES
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define this_cpu_add_4(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
5662306a36Sopenharmony_ci#define this_cpu_add_8(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, +)
5762306a36Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
5862306a36Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
5962306a36Sopenharmony_ci#define this_cpu_and_4(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
6062306a36Sopenharmony_ci#define this_cpu_and_8(pcp, val)	arch_this_cpu_to_op_simple(pcp, val, &)
6162306a36Sopenharmony_ci#define this_cpu_or_4(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
6262306a36Sopenharmony_ci#define this_cpu_or_8(pcp, val)		arch_this_cpu_to_op_simple(pcp, val, |)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#else /* CONFIG_HAVE_MARCH_Z196_FEATURES */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define arch_this_cpu_add(pcp, val, op1, op2, szcast)			\
6762306a36Sopenharmony_ci{									\
6862306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
6962306a36Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
7062306a36Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
7162306a36Sopenharmony_ci	preempt_disable_notrace();					\
7262306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp)); 				\
7362306a36Sopenharmony_ci	if (__builtin_constant_p(val__) &&				\
7462306a36Sopenharmony_ci	    ((szcast)val__ > -129) && ((szcast)val__ < 128)) {		\
7562306a36Sopenharmony_ci		asm volatile(						\
7662306a36Sopenharmony_ci			op2 "   %[ptr__],%[val__]\n"			\
7762306a36Sopenharmony_ci			: [ptr__] "+Q" (*ptr__) 			\
7862306a36Sopenharmony_ci			: [val__] "i" ((szcast)val__)			\
7962306a36Sopenharmony_ci			: "cc");					\
8062306a36Sopenharmony_ci	} else {							\
8162306a36Sopenharmony_ci		asm volatile(						\
8262306a36Sopenharmony_ci			op1 "   %[old__],%[val__],%[ptr__]\n"		\
8362306a36Sopenharmony_ci			: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)	\
8462306a36Sopenharmony_ci			: [val__] "d" (val__)				\
8562306a36Sopenharmony_ci			: "cc");					\
8662306a36Sopenharmony_ci	}								\
8762306a36Sopenharmony_ci	preempt_enable_notrace();					\
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int)
9162306a36Sopenharmony_ci#define this_cpu_add_8(pcp, val) arch_this_cpu_add(pcp, val, "laag", "agsi", long)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define arch_this_cpu_add_return(pcp, val, op)				\
9462306a36Sopenharmony_ci({									\
9562306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
9662306a36Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
9762306a36Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
9862306a36Sopenharmony_ci	preempt_disable_notrace();					\
9962306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));	 				\
10062306a36Sopenharmony_ci	asm volatile(							\
10162306a36Sopenharmony_ci		op "    %[old__],%[val__],%[ptr__]\n"			\
10262306a36Sopenharmony_ci		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
10362306a36Sopenharmony_ci		: [val__] "d" (val__)					\
10462306a36Sopenharmony_ci		: "cc");						\
10562306a36Sopenharmony_ci	preempt_enable_notrace();						\
10662306a36Sopenharmony_ci	old__ + val__;							\
10762306a36Sopenharmony_ci})
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) arch_this_cpu_add_return(pcp, val, "laa")
11062306a36Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) arch_this_cpu_add_return(pcp, val, "laag")
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define arch_this_cpu_to_op(pcp, val, op)				\
11362306a36Sopenharmony_ci{									\
11462306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__; 				\
11562306a36Sopenharmony_ci	pcp_op_T__ val__ = (val);					\
11662306a36Sopenharmony_ci	pcp_op_T__ old__, *ptr__;					\
11762306a36Sopenharmony_ci	preempt_disable_notrace();					\
11862306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));	 				\
11962306a36Sopenharmony_ci	asm volatile(							\
12062306a36Sopenharmony_ci		op "    %[old__],%[val__],%[ptr__]\n"			\
12162306a36Sopenharmony_ci		: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__)		\
12262306a36Sopenharmony_ci		: [val__] "d" (val__)					\
12362306a36Sopenharmony_ci		: "cc");						\
12462306a36Sopenharmony_ci	preempt_enable_notrace();					\
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define this_cpu_and_4(pcp, val)	arch_this_cpu_to_op(pcp, val, "lan")
12862306a36Sopenharmony_ci#define this_cpu_and_8(pcp, val)	arch_this_cpu_to_op(pcp, val, "lang")
12962306a36Sopenharmony_ci#define this_cpu_or_4(pcp, val)		arch_this_cpu_to_op(pcp, val, "lao")
13062306a36Sopenharmony_ci#define this_cpu_or_8(pcp, val)		arch_this_cpu_to_op(pcp, val, "laog")
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#endif /* CONFIG_HAVE_MARCH_Z196_FEATURES */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define arch_this_cpu_cmpxchg(pcp, oval, nval)				\
13562306a36Sopenharmony_ci({									\
13662306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__;					\
13762306a36Sopenharmony_ci	pcp_op_T__ ret__;						\
13862306a36Sopenharmony_ci	pcp_op_T__ *ptr__;						\
13962306a36Sopenharmony_ci	preempt_disable_notrace();					\
14062306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
14162306a36Sopenharmony_ci	ret__ = cmpxchg(ptr__, oval, nval);				\
14262306a36Sopenharmony_ci	preempt_enable_notrace();					\
14362306a36Sopenharmony_ci	ret__;								\
14462306a36Sopenharmony_ci})
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define this_cpu_cmpxchg_1(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
14762306a36Sopenharmony_ci#define this_cpu_cmpxchg_2(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
14862306a36Sopenharmony_ci#define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
14962306a36Sopenharmony_ci#define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval)
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define this_cpu_cmpxchg64(pcp, o, n)	this_cpu_cmpxchg_8(pcp, o, n)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define this_cpu_cmpxchg128(pcp, oval, nval)				\
15462306a36Sopenharmony_ci({									\
15562306a36Sopenharmony_ci	typedef typeof(pcp) pcp_op_T__;					\
15662306a36Sopenharmony_ci	u128 old__, new__, ret__;					\
15762306a36Sopenharmony_ci	pcp_op_T__ *ptr__;						\
15862306a36Sopenharmony_ci	old__ = oval;							\
15962306a36Sopenharmony_ci	new__ = nval;							\
16062306a36Sopenharmony_ci	preempt_disable_notrace();					\
16162306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
16262306a36Sopenharmony_ci	ret__ = cmpxchg128((void *)ptr__, old__, new__);		\
16362306a36Sopenharmony_ci	preempt_enable_notrace();					\
16462306a36Sopenharmony_ci	ret__;								\
16562306a36Sopenharmony_ci})
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define arch_this_cpu_xchg(pcp, nval)					\
16862306a36Sopenharmony_ci({									\
16962306a36Sopenharmony_ci	typeof(pcp) *ptr__;						\
17062306a36Sopenharmony_ci	typeof(pcp) ret__;						\
17162306a36Sopenharmony_ci	preempt_disable_notrace();					\
17262306a36Sopenharmony_ci	ptr__ = raw_cpu_ptr(&(pcp));					\
17362306a36Sopenharmony_ci	ret__ = xchg(ptr__, nval);					\
17462306a36Sopenharmony_ci	preempt_enable_notrace();					\
17562306a36Sopenharmony_ci	ret__;								\
17662306a36Sopenharmony_ci})
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define this_cpu_xchg_1(pcp, nval) arch_this_cpu_xchg(pcp, nval)
17962306a36Sopenharmony_ci#define this_cpu_xchg_2(pcp, nval) arch_this_cpu_xchg(pcp, nval)
18062306a36Sopenharmony_ci#define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval)
18162306a36Sopenharmony_ci#define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#include <asm-generic/percpu.h>
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#endif /* __ARCH_S390_PERCPU__ */
186