18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_PERCPU_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_PERCPU_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
68c2ecf20Sopenharmony_ci#define __percpu_seg		gs
78c2ecf20Sopenharmony_ci#else
88c2ecf20Sopenharmony_ci#define __percpu_seg		fs
98c2ecf20Sopenharmony_ci#endif
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifdef __ASSEMBLY__
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
148c2ecf20Sopenharmony_ci#define PER_CPU_VAR(var)	%__percpu_seg:var
158c2ecf20Sopenharmony_ci#else /* ! SMP */
168c2ecf20Sopenharmony_ci#define PER_CPU_VAR(var)	var
178c2ecf20Sopenharmony_ci#endif	/* SMP */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64_SMP
208c2ecf20Sopenharmony_ci#define INIT_PER_CPU_VAR(var)  init_per_cpu__##var
218c2ecf20Sopenharmony_ci#else
228c2ecf20Sopenharmony_ci#define INIT_PER_CPU_VAR(var)  var
238c2ecf20Sopenharmony_ci#endif
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#else /* ...!ASSEMBLY */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/kernel.h>
288c2ecf20Sopenharmony_ci#include <linux/stringify.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
318c2ecf20Sopenharmony_ci#define __percpu_prefix		"%%"__stringify(__percpu_seg)":"
328c2ecf20Sopenharmony_ci#define __my_cpu_offset		this_cpu_read(this_cpu_off)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/*
358c2ecf20Sopenharmony_ci * Compared to the generic __my_cpu_offset version, the following
368c2ecf20Sopenharmony_ci * saves one instruction and avoids clobbering a temp register.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci#define arch_raw_cpu_ptr(ptr)				\
398c2ecf20Sopenharmony_ci({							\
408c2ecf20Sopenharmony_ci	unsigned long tcp_ptr__;			\
418c2ecf20Sopenharmony_ci	asm volatile("add " __percpu_arg(1) ", %0"	\
428c2ecf20Sopenharmony_ci		     : "=r" (tcp_ptr__)			\
438c2ecf20Sopenharmony_ci		     : "m" (this_cpu_off), "0" (ptr));	\
448c2ecf20Sopenharmony_ci	(typeof(*(ptr)) __kernel __force *)tcp_ptr__;	\
458c2ecf20Sopenharmony_ci})
468c2ecf20Sopenharmony_ci#else
478c2ecf20Sopenharmony_ci#define __percpu_prefix		""
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define __percpu_arg(x)		__percpu_prefix "%" #x
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci * Initialized pointers to per-cpu variables needed for the boot
548c2ecf20Sopenharmony_ci * processor need to use these macros to get the proper address
558c2ecf20Sopenharmony_ci * offset from __per_cpu_load on SMP.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * There also must be an entry in vmlinux_64.lds.S
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci#define DECLARE_INIT_PER_CPU(var) \
608c2ecf20Sopenharmony_ci       extern typeof(var) init_per_cpu_var(var)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64_SMP
638c2ecf20Sopenharmony_ci#define init_per_cpu_var(var)  init_per_cpu__##var
648c2ecf20Sopenharmony_ci#else
658c2ecf20Sopenharmony_ci#define init_per_cpu_var(var)  var
668c2ecf20Sopenharmony_ci#endif
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* For arch-specific code, we can use direct single-insn ops (they
698c2ecf20Sopenharmony_ci * don't give an lvalue though). */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define __pcpu_type_1 u8
728c2ecf20Sopenharmony_ci#define __pcpu_type_2 u16
738c2ecf20Sopenharmony_ci#define __pcpu_type_4 u32
748c2ecf20Sopenharmony_ci#define __pcpu_type_8 u64
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define __pcpu_cast_1(val) ((u8)(((unsigned long) val) & 0xff))
778c2ecf20Sopenharmony_ci#define __pcpu_cast_2(val) ((u16)(((unsigned long) val) & 0xffff))
788c2ecf20Sopenharmony_ci#define __pcpu_cast_4(val) ((u32)(((unsigned long) val) & 0xffffffff))
798c2ecf20Sopenharmony_ci#define __pcpu_cast_8(val) ((u64)(val))
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define __pcpu_op1_1(op, dst) op "b " dst
828c2ecf20Sopenharmony_ci#define __pcpu_op1_2(op, dst) op "w " dst
838c2ecf20Sopenharmony_ci#define __pcpu_op1_4(op, dst) op "l " dst
848c2ecf20Sopenharmony_ci#define __pcpu_op1_8(op, dst) op "q " dst
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define __pcpu_op2_1(op, src, dst) op "b " src ", " dst
878c2ecf20Sopenharmony_ci#define __pcpu_op2_2(op, src, dst) op "w " src ", " dst
888c2ecf20Sopenharmony_ci#define __pcpu_op2_4(op, src, dst) op "l " src ", " dst
898c2ecf20Sopenharmony_ci#define __pcpu_op2_8(op, src, dst) op "q " src ", " dst
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define __pcpu_reg_1(mod, x) mod "q" (x)
928c2ecf20Sopenharmony_ci#define __pcpu_reg_2(mod, x) mod "r" (x)
938c2ecf20Sopenharmony_ci#define __pcpu_reg_4(mod, x) mod "r" (x)
948c2ecf20Sopenharmony_ci#define __pcpu_reg_8(mod, x) mod "r" (x)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define __pcpu_reg_imm_1(x) "qi" (x)
978c2ecf20Sopenharmony_ci#define __pcpu_reg_imm_2(x) "ri" (x)
988c2ecf20Sopenharmony_ci#define __pcpu_reg_imm_4(x) "ri" (x)
998c2ecf20Sopenharmony_ci#define __pcpu_reg_imm_8(x) "re" (x)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define percpu_to_op(size, qual, op, _var, _val)			\
1028c2ecf20Sopenharmony_cido {									\
1038c2ecf20Sopenharmony_ci	__pcpu_type_##size pto_val__ = __pcpu_cast_##size(_val);	\
1048c2ecf20Sopenharmony_ci	if (0) {		                                        \
1058c2ecf20Sopenharmony_ci		typeof(_var) pto_tmp__;					\
1068c2ecf20Sopenharmony_ci		pto_tmp__ = (_val);					\
1078c2ecf20Sopenharmony_ci		(void)pto_tmp__;					\
1088c2ecf20Sopenharmony_ci	}								\
1098c2ecf20Sopenharmony_ci	asm qual(__pcpu_op2_##size(op, "%[val]", __percpu_arg([var]))	\
1108c2ecf20Sopenharmony_ci	    : [var] "+m" (_var)						\
1118c2ecf20Sopenharmony_ci	    : [val] __pcpu_reg_imm_##size(pto_val__));			\
1128c2ecf20Sopenharmony_ci} while (0)
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define percpu_unary_op(size, qual, op, _var)				\
1158c2ecf20Sopenharmony_ci({									\
1168c2ecf20Sopenharmony_ci	asm qual (__pcpu_op1_##size(op, __percpu_arg([var]))		\
1178c2ecf20Sopenharmony_ci	    : [var] "+m" (_var));					\
1188c2ecf20Sopenharmony_ci})
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * Generate a percpu add to memory instruction and optimize code
1228c2ecf20Sopenharmony_ci * if one is added or subtracted.
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_ci#define percpu_add_op(size, qual, var, val)				\
1258c2ecf20Sopenharmony_cido {									\
1268c2ecf20Sopenharmony_ci	const int pao_ID__ = (__builtin_constant_p(val) &&		\
1278c2ecf20Sopenharmony_ci			      ((val) == 1 || (val) == -1)) ?		\
1288c2ecf20Sopenharmony_ci				(int)(val) : 0;				\
1298c2ecf20Sopenharmony_ci	if (0) {							\
1308c2ecf20Sopenharmony_ci		typeof(var) pao_tmp__;					\
1318c2ecf20Sopenharmony_ci		pao_tmp__ = (val);					\
1328c2ecf20Sopenharmony_ci		(void)pao_tmp__;					\
1338c2ecf20Sopenharmony_ci	}								\
1348c2ecf20Sopenharmony_ci	if (pao_ID__ == 1)						\
1358c2ecf20Sopenharmony_ci		percpu_unary_op(size, qual, "inc", var);		\
1368c2ecf20Sopenharmony_ci	else if (pao_ID__ == -1)					\
1378c2ecf20Sopenharmony_ci		percpu_unary_op(size, qual, "dec", var);		\
1388c2ecf20Sopenharmony_ci	else								\
1398c2ecf20Sopenharmony_ci		percpu_to_op(size, qual, "add", var, val);		\
1408c2ecf20Sopenharmony_ci} while (0)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#define percpu_from_op(size, qual, op, _var)				\
1438c2ecf20Sopenharmony_ci({									\
1448c2ecf20Sopenharmony_ci	__pcpu_type_##size pfo_val__;					\
1458c2ecf20Sopenharmony_ci	asm qual (__pcpu_op2_##size(op, __percpu_arg([var]), "%[val]")	\
1468c2ecf20Sopenharmony_ci	    : [val] __pcpu_reg_##size("=", pfo_val__)			\
1478c2ecf20Sopenharmony_ci	    : [var] "m" (_var));					\
1488c2ecf20Sopenharmony_ci	(typeof(_var))(unsigned long) pfo_val__;			\
1498c2ecf20Sopenharmony_ci})
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define percpu_stable_op(size, op, _var)				\
1528c2ecf20Sopenharmony_ci({									\
1538c2ecf20Sopenharmony_ci	__pcpu_type_##size pfo_val__;					\
1548c2ecf20Sopenharmony_ci	asm(__pcpu_op2_##size(op, __percpu_arg(P[var]), "%[val]")	\
1558c2ecf20Sopenharmony_ci	    : [val] __pcpu_reg_##size("=", pfo_val__)			\
1568c2ecf20Sopenharmony_ci	    : [var] "p" (&(_var)));					\
1578c2ecf20Sopenharmony_ci	(typeof(_var))(unsigned long) pfo_val__;			\
1588c2ecf20Sopenharmony_ci})
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * Add return operation
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_ci#define percpu_add_return_op(size, qual, _var, _val)			\
1648c2ecf20Sopenharmony_ci({									\
1658c2ecf20Sopenharmony_ci	__pcpu_type_##size paro_tmp__ = __pcpu_cast_##size(_val);	\
1668c2ecf20Sopenharmony_ci	asm qual (__pcpu_op2_##size("xadd", "%[tmp]",			\
1678c2ecf20Sopenharmony_ci				     __percpu_arg([var]))		\
1688c2ecf20Sopenharmony_ci		  : [tmp] __pcpu_reg_##size("+", paro_tmp__),		\
1698c2ecf20Sopenharmony_ci		    [var] "+m" (_var)					\
1708c2ecf20Sopenharmony_ci		  : : "memory");					\
1718c2ecf20Sopenharmony_ci	(typeof(_var))(unsigned long) (paro_tmp__ + _val);		\
1728c2ecf20Sopenharmony_ci})
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/*
1758c2ecf20Sopenharmony_ci * xchg is implemented using cmpxchg without a lock prefix. xchg is
1768c2ecf20Sopenharmony_ci * expensive due to the implied lock prefix.  The processor cannot prefetch
1778c2ecf20Sopenharmony_ci * cachelines if xchg is used.
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_ci#define percpu_xchg_op(size, qual, _var, _nval)				\
1808c2ecf20Sopenharmony_ci({									\
1818c2ecf20Sopenharmony_ci	__pcpu_type_##size pxo_old__;					\
1828c2ecf20Sopenharmony_ci	__pcpu_type_##size pxo_new__ = __pcpu_cast_##size(_nval);	\
1838c2ecf20Sopenharmony_ci	asm qual (__pcpu_op2_##size("mov", __percpu_arg([var]),		\
1848c2ecf20Sopenharmony_ci				    "%[oval]")				\
1858c2ecf20Sopenharmony_ci		  "\n1:\t"						\
1868c2ecf20Sopenharmony_ci		  __pcpu_op2_##size("cmpxchg", "%[nval]",		\
1878c2ecf20Sopenharmony_ci				    __percpu_arg([var]))		\
1888c2ecf20Sopenharmony_ci		  "\n\tjnz 1b"						\
1898c2ecf20Sopenharmony_ci		  : [oval] "=&a" (pxo_old__),				\
1908c2ecf20Sopenharmony_ci		    [var] "+m" (_var)					\
1918c2ecf20Sopenharmony_ci		  : [nval] __pcpu_reg_##size(, pxo_new__)		\
1928c2ecf20Sopenharmony_ci		  : "memory");						\
1938c2ecf20Sopenharmony_ci	(typeof(_var))(unsigned long) pxo_old__;			\
1948c2ecf20Sopenharmony_ci})
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/*
1978c2ecf20Sopenharmony_ci * cmpxchg has no such implied lock semantics as a result it is much
1988c2ecf20Sopenharmony_ci * more efficient for cpu local operations.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_ci#define percpu_cmpxchg_op(size, qual, _var, _oval, _nval)		\
2018c2ecf20Sopenharmony_ci({									\
2028c2ecf20Sopenharmony_ci	__pcpu_type_##size pco_old__ = __pcpu_cast_##size(_oval);	\
2038c2ecf20Sopenharmony_ci	__pcpu_type_##size pco_new__ = __pcpu_cast_##size(_nval);	\
2048c2ecf20Sopenharmony_ci	asm qual (__pcpu_op2_##size("cmpxchg", "%[nval]",		\
2058c2ecf20Sopenharmony_ci				    __percpu_arg([var]))		\
2068c2ecf20Sopenharmony_ci		  : [oval] "+a" (pco_old__),				\
2078c2ecf20Sopenharmony_ci		    [var] "+m" (_var)					\
2088c2ecf20Sopenharmony_ci		  : [nval] __pcpu_reg_##size(, pco_new__)		\
2098c2ecf20Sopenharmony_ci		  : "memory");						\
2108c2ecf20Sopenharmony_ci	(typeof(_var))(unsigned long) pco_old__;			\
2118c2ecf20Sopenharmony_ci})
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * this_cpu_read() makes gcc load the percpu variable every time it is
2158c2ecf20Sopenharmony_ci * accessed while this_cpu_read_stable() allows the value to be cached.
2168c2ecf20Sopenharmony_ci * this_cpu_read_stable() is more efficient and can be used if its value
2178c2ecf20Sopenharmony_ci * is guaranteed to be valid across cpus.  The current users include
2188c2ecf20Sopenharmony_ci * get_current() and get_thread_info() both of which are actually
2198c2ecf20Sopenharmony_ci * per-thread variables implemented as per-cpu variables and thus
2208c2ecf20Sopenharmony_ci * stable for the duration of the respective task.
2218c2ecf20Sopenharmony_ci */
2228c2ecf20Sopenharmony_ci#define this_cpu_read_stable_1(pcp)	percpu_stable_op(1, "mov", pcp)
2238c2ecf20Sopenharmony_ci#define this_cpu_read_stable_2(pcp)	percpu_stable_op(2, "mov", pcp)
2248c2ecf20Sopenharmony_ci#define this_cpu_read_stable_4(pcp)	percpu_stable_op(4, "mov", pcp)
2258c2ecf20Sopenharmony_ci#define this_cpu_read_stable_8(pcp)	percpu_stable_op(8, "mov", pcp)
2268c2ecf20Sopenharmony_ci#define this_cpu_read_stable(pcp)	__pcpu_size_call_return(this_cpu_read_stable_, pcp)
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#define raw_cpu_read_1(pcp)		percpu_from_op(1, , "mov", pcp)
2298c2ecf20Sopenharmony_ci#define raw_cpu_read_2(pcp)		percpu_from_op(2, , "mov", pcp)
2308c2ecf20Sopenharmony_ci#define raw_cpu_read_4(pcp)		percpu_from_op(4, , "mov", pcp)
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci#define raw_cpu_write_1(pcp, val)	percpu_to_op(1, , "mov", (pcp), val)
2338c2ecf20Sopenharmony_ci#define raw_cpu_write_2(pcp, val)	percpu_to_op(2, , "mov", (pcp), val)
2348c2ecf20Sopenharmony_ci#define raw_cpu_write_4(pcp, val)	percpu_to_op(4, , "mov", (pcp), val)
2358c2ecf20Sopenharmony_ci#define raw_cpu_add_1(pcp, val)		percpu_add_op(1, , (pcp), val)
2368c2ecf20Sopenharmony_ci#define raw_cpu_add_2(pcp, val)		percpu_add_op(2, , (pcp), val)
2378c2ecf20Sopenharmony_ci#define raw_cpu_add_4(pcp, val)		percpu_add_op(4, , (pcp), val)
2388c2ecf20Sopenharmony_ci#define raw_cpu_and_1(pcp, val)		percpu_to_op(1, , "and", (pcp), val)
2398c2ecf20Sopenharmony_ci#define raw_cpu_and_2(pcp, val)		percpu_to_op(2, , "and", (pcp), val)
2408c2ecf20Sopenharmony_ci#define raw_cpu_and_4(pcp, val)		percpu_to_op(4, , "and", (pcp), val)
2418c2ecf20Sopenharmony_ci#define raw_cpu_or_1(pcp, val)		percpu_to_op(1, , "or", (pcp), val)
2428c2ecf20Sopenharmony_ci#define raw_cpu_or_2(pcp, val)		percpu_to_op(2, , "or", (pcp), val)
2438c2ecf20Sopenharmony_ci#define raw_cpu_or_4(pcp, val)		percpu_to_op(4, , "or", (pcp), val)
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/*
2468c2ecf20Sopenharmony_ci * raw_cpu_xchg() can use a load-store since it is not required to be
2478c2ecf20Sopenharmony_ci * IRQ-safe.
2488c2ecf20Sopenharmony_ci */
2498c2ecf20Sopenharmony_ci#define raw_percpu_xchg_op(var, nval)					\
2508c2ecf20Sopenharmony_ci({									\
2518c2ecf20Sopenharmony_ci	typeof(var) pxo_ret__ = raw_cpu_read(var);			\
2528c2ecf20Sopenharmony_ci	raw_cpu_write(var, (nval));					\
2538c2ecf20Sopenharmony_ci	pxo_ret__;							\
2548c2ecf20Sopenharmony_ci})
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci#define raw_cpu_xchg_1(pcp, val)	raw_percpu_xchg_op(pcp, val)
2578c2ecf20Sopenharmony_ci#define raw_cpu_xchg_2(pcp, val)	raw_percpu_xchg_op(pcp, val)
2588c2ecf20Sopenharmony_ci#define raw_cpu_xchg_4(pcp, val)	raw_percpu_xchg_op(pcp, val)
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci#define this_cpu_read_1(pcp)		percpu_from_op(1, volatile, "mov", pcp)
2618c2ecf20Sopenharmony_ci#define this_cpu_read_2(pcp)		percpu_from_op(2, volatile, "mov", pcp)
2628c2ecf20Sopenharmony_ci#define this_cpu_read_4(pcp)		percpu_from_op(4, volatile, "mov", pcp)
2638c2ecf20Sopenharmony_ci#define this_cpu_write_1(pcp, val)	percpu_to_op(1, volatile, "mov", (pcp), val)
2648c2ecf20Sopenharmony_ci#define this_cpu_write_2(pcp, val)	percpu_to_op(2, volatile, "mov", (pcp), val)
2658c2ecf20Sopenharmony_ci#define this_cpu_write_4(pcp, val)	percpu_to_op(4, volatile, "mov", (pcp), val)
2668c2ecf20Sopenharmony_ci#define this_cpu_add_1(pcp, val)	percpu_add_op(1, volatile, (pcp), val)
2678c2ecf20Sopenharmony_ci#define this_cpu_add_2(pcp, val)	percpu_add_op(2, volatile, (pcp), val)
2688c2ecf20Sopenharmony_ci#define this_cpu_add_4(pcp, val)	percpu_add_op(4, volatile, (pcp), val)
2698c2ecf20Sopenharmony_ci#define this_cpu_and_1(pcp, val)	percpu_to_op(1, volatile, "and", (pcp), val)
2708c2ecf20Sopenharmony_ci#define this_cpu_and_2(pcp, val)	percpu_to_op(2, volatile, "and", (pcp), val)
2718c2ecf20Sopenharmony_ci#define this_cpu_and_4(pcp, val)	percpu_to_op(4, volatile, "and", (pcp), val)
2728c2ecf20Sopenharmony_ci#define this_cpu_or_1(pcp, val)		percpu_to_op(1, volatile, "or", (pcp), val)
2738c2ecf20Sopenharmony_ci#define this_cpu_or_2(pcp, val)		percpu_to_op(2, volatile, "or", (pcp), val)
2748c2ecf20Sopenharmony_ci#define this_cpu_or_4(pcp, val)		percpu_to_op(4, volatile, "or", (pcp), val)
2758c2ecf20Sopenharmony_ci#define this_cpu_xchg_1(pcp, nval)	percpu_xchg_op(1, volatile, pcp, nval)
2768c2ecf20Sopenharmony_ci#define this_cpu_xchg_2(pcp, nval)	percpu_xchg_op(2, volatile, pcp, nval)
2778c2ecf20Sopenharmony_ci#define this_cpu_xchg_4(pcp, nval)	percpu_xchg_op(4, volatile, pcp, nval)
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci#define raw_cpu_add_return_1(pcp, val)		percpu_add_return_op(1, , pcp, val)
2808c2ecf20Sopenharmony_ci#define raw_cpu_add_return_2(pcp, val)		percpu_add_return_op(2, , pcp, val)
2818c2ecf20Sopenharmony_ci#define raw_cpu_add_return_4(pcp, val)		percpu_add_return_op(4, , pcp, val)
2828c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_1(pcp, oval, nval)	percpu_cmpxchg_op(1, , pcp, oval, nval)
2838c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_2(pcp, oval, nval)	percpu_cmpxchg_op(2, , pcp, oval, nval)
2848c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_4(pcp, oval, nval)	percpu_cmpxchg_op(4, , pcp, oval, nval)
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci#define this_cpu_add_return_1(pcp, val)		percpu_add_return_op(1, volatile, pcp, val)
2878c2ecf20Sopenharmony_ci#define this_cpu_add_return_2(pcp, val)		percpu_add_return_op(2, volatile, pcp, val)
2888c2ecf20Sopenharmony_ci#define this_cpu_add_return_4(pcp, val)		percpu_add_return_op(4, volatile, pcp, val)
2898c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_1(pcp, oval, nval)	percpu_cmpxchg_op(1, volatile, pcp, oval, nval)
2908c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_2(pcp, oval, nval)	percpu_cmpxchg_op(2, volatile, pcp, oval, nval)
2918c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_4(pcp, oval, nval)	percpu_cmpxchg_op(4, volatile, pcp, oval, nval)
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_CMPXCHG64
2948c2ecf20Sopenharmony_ci#define percpu_cmpxchg8b_double(pcp1, pcp2, o1, o2, n1, n2)		\
2958c2ecf20Sopenharmony_ci({									\
2968c2ecf20Sopenharmony_ci	bool __ret;							\
2978c2ecf20Sopenharmony_ci	typeof(pcp1) __o1 = (o1), __n1 = (n1);				\
2988c2ecf20Sopenharmony_ci	typeof(pcp2) __o2 = (o2), __n2 = (n2);				\
2998c2ecf20Sopenharmony_ci	asm volatile("cmpxchg8b "__percpu_arg(1)			\
3008c2ecf20Sopenharmony_ci		     CC_SET(z)						\
3018c2ecf20Sopenharmony_ci		     : CC_OUT(z) (__ret), "+m" (pcp1), "+m" (pcp2), "+a" (__o1), "+d" (__o2) \
3028c2ecf20Sopenharmony_ci		     : "b" (__n1), "c" (__n2));				\
3038c2ecf20Sopenharmony_ci	__ret;								\
3048c2ecf20Sopenharmony_ci})
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_double_4	percpu_cmpxchg8b_double
3078c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_double_4	percpu_cmpxchg8b_double
3088c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_CMPXCHG64 */
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci/*
3118c2ecf20Sopenharmony_ci * Per cpu atomic 64 bit operations are only available under 64 bit.
3128c2ecf20Sopenharmony_ci * 32 bit must fall back to generic operations.
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
3158c2ecf20Sopenharmony_ci#define raw_cpu_read_8(pcp)			percpu_from_op(8, , "mov", pcp)
3168c2ecf20Sopenharmony_ci#define raw_cpu_write_8(pcp, val)		percpu_to_op(8, , "mov", (pcp), val)
3178c2ecf20Sopenharmony_ci#define raw_cpu_add_8(pcp, val)			percpu_add_op(8, , (pcp), val)
3188c2ecf20Sopenharmony_ci#define raw_cpu_and_8(pcp, val)			percpu_to_op(8, , "and", (pcp), val)
3198c2ecf20Sopenharmony_ci#define raw_cpu_or_8(pcp, val)			percpu_to_op(8, , "or", (pcp), val)
3208c2ecf20Sopenharmony_ci#define raw_cpu_add_return_8(pcp, val)		percpu_add_return_op(8, , pcp, val)
3218c2ecf20Sopenharmony_ci#define raw_cpu_xchg_8(pcp, nval)		raw_percpu_xchg_op(pcp, nval)
3228c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_8(pcp, oval, nval)	percpu_cmpxchg_op(8, , pcp, oval, nval)
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci#define this_cpu_read_8(pcp)			percpu_from_op(8, volatile, "mov", pcp)
3258c2ecf20Sopenharmony_ci#define this_cpu_write_8(pcp, val)		percpu_to_op(8, volatile, "mov", (pcp), val)
3268c2ecf20Sopenharmony_ci#define this_cpu_add_8(pcp, val)		percpu_add_op(8, volatile, (pcp), val)
3278c2ecf20Sopenharmony_ci#define this_cpu_and_8(pcp, val)		percpu_to_op(8, volatile, "and", (pcp), val)
3288c2ecf20Sopenharmony_ci#define this_cpu_or_8(pcp, val)			percpu_to_op(8, volatile, "or", (pcp), val)
3298c2ecf20Sopenharmony_ci#define this_cpu_add_return_8(pcp, val)		percpu_add_return_op(8, volatile, pcp, val)
3308c2ecf20Sopenharmony_ci#define this_cpu_xchg_8(pcp, nval)		percpu_xchg_op(8, volatile, pcp, nval)
3318c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_8(pcp, oval, nval)	percpu_cmpxchg_op(8, volatile, pcp, oval, nval)
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci/*
3348c2ecf20Sopenharmony_ci * Pretty complex macro to generate cmpxchg16 instruction.  The instruction
3358c2ecf20Sopenharmony_ci * is not supported on early AMD64 processors so we must be able to emulate
3368c2ecf20Sopenharmony_ci * it in software.  The address used in the cmpxchg16 instruction must be
3378c2ecf20Sopenharmony_ci * aligned to a 16 byte boundary.
3388c2ecf20Sopenharmony_ci */
3398c2ecf20Sopenharmony_ci#define percpu_cmpxchg16b_double(pcp1, pcp2, o1, o2, n1, n2)		\
3408c2ecf20Sopenharmony_ci({									\
3418c2ecf20Sopenharmony_ci	bool __ret;							\
3428c2ecf20Sopenharmony_ci	typeof(pcp1) __o1 = (o1), __n1 = (n1);				\
3438c2ecf20Sopenharmony_ci	typeof(pcp2) __o2 = (o2), __n2 = (n2);				\
3448c2ecf20Sopenharmony_ci	alternative_io("leaq %P1,%%rsi\n\tcall this_cpu_cmpxchg16b_emu\n\t", \
3458c2ecf20Sopenharmony_ci		       "cmpxchg16b " __percpu_arg(1) "\n\tsetz %0\n\t",	\
3468c2ecf20Sopenharmony_ci		       X86_FEATURE_CX16,				\
3478c2ecf20Sopenharmony_ci		       ASM_OUTPUT2("=a" (__ret), "+m" (pcp1),		\
3488c2ecf20Sopenharmony_ci				   "+m" (pcp2), "+d" (__o2)),		\
3498c2ecf20Sopenharmony_ci		       "b" (__n1), "c" (__n2), "a" (__o1) : "rsi");	\
3508c2ecf20Sopenharmony_ci	__ret;								\
3518c2ecf20Sopenharmony_ci})
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci#define raw_cpu_cmpxchg_double_8	percpu_cmpxchg16b_double
3548c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_double_8	percpu_cmpxchg16b_double
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci#endif
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic __always_inline bool x86_this_cpu_constant_test_bit(unsigned int nr,
3598c2ecf20Sopenharmony_ci                        const unsigned long __percpu *addr)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	unsigned long __percpu *a =
3628c2ecf20Sopenharmony_ci		(unsigned long __percpu *)addr + nr / BITS_PER_LONG;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
3658c2ecf20Sopenharmony_ci	return ((1UL << (nr % BITS_PER_LONG)) & raw_cpu_read_8(*a)) != 0;
3668c2ecf20Sopenharmony_ci#else
3678c2ecf20Sopenharmony_ci	return ((1UL << (nr % BITS_PER_LONG)) & raw_cpu_read_4(*a)) != 0;
3688c2ecf20Sopenharmony_ci#endif
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic inline bool x86_this_cpu_variable_test_bit(int nr,
3728c2ecf20Sopenharmony_ci                        const unsigned long __percpu *addr)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	bool oldbit;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	asm volatile("btl "__percpu_arg(2)",%1"
3778c2ecf20Sopenharmony_ci			CC_SET(c)
3788c2ecf20Sopenharmony_ci			: CC_OUT(c) (oldbit)
3798c2ecf20Sopenharmony_ci			: "m" (*(unsigned long __percpu *)addr), "Ir" (nr));
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return oldbit;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci#define x86_this_cpu_test_bit(nr, addr)			\
3858c2ecf20Sopenharmony_ci	(__builtin_constant_p((nr))			\
3868c2ecf20Sopenharmony_ci	 ? x86_this_cpu_constant_test_bit((nr), (addr))	\
3878c2ecf20Sopenharmony_ci	 : x86_this_cpu_variable_test_bit((nr), (addr)))
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci#include <asm-generic/percpu.h>
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/* We can use this directly for local CPU (faster). */
3938c2ecf20Sopenharmony_ciDECLARE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/*
4008c2ecf20Sopenharmony_ci * Define the "EARLY_PER_CPU" macros.  These are used for some per_cpu
4018c2ecf20Sopenharmony_ci * variables that are initialized and accessed before there are per_cpu
4028c2ecf20Sopenharmony_ci * areas allocated.
4038c2ecf20Sopenharmony_ci */
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci#define	DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)			\
4068c2ecf20Sopenharmony_ci	DEFINE_PER_CPU(_type, _name) = _initvalue;			\
4078c2ecf20Sopenharmony_ci	__typeof__(_type) _name##_early_map[NR_CPUS] __initdata =	\
4088c2ecf20Sopenharmony_ci				{ [0 ... NR_CPUS-1] = _initvalue };	\
4098c2ecf20Sopenharmony_ci	__typeof__(_type) *_name##_early_ptr __refdata = _name##_early_map
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci#define DEFINE_EARLY_PER_CPU_READ_MOSTLY(_type, _name, _initvalue)	\
4128c2ecf20Sopenharmony_ci	DEFINE_PER_CPU_READ_MOSTLY(_type, _name) = _initvalue;		\
4138c2ecf20Sopenharmony_ci	__typeof__(_type) _name##_early_map[NR_CPUS] __initdata =	\
4148c2ecf20Sopenharmony_ci				{ [0 ... NR_CPUS-1] = _initvalue };	\
4158c2ecf20Sopenharmony_ci	__typeof__(_type) *_name##_early_ptr __refdata = _name##_early_map
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci#define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\
4188c2ecf20Sopenharmony_ci	EXPORT_PER_CPU_SYMBOL(_name)
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci#define DECLARE_EARLY_PER_CPU(_type, _name)			\
4218c2ecf20Sopenharmony_ci	DECLARE_PER_CPU(_type, _name);				\
4228c2ecf20Sopenharmony_ci	extern __typeof__(_type) *_name##_early_ptr;		\
4238c2ecf20Sopenharmony_ci	extern __typeof__(_type)  _name##_early_map[]
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci#define DECLARE_EARLY_PER_CPU_READ_MOSTLY(_type, _name)		\
4268c2ecf20Sopenharmony_ci	DECLARE_PER_CPU_READ_MOSTLY(_type, _name);		\
4278c2ecf20Sopenharmony_ci	extern __typeof__(_type) *_name##_early_ptr;		\
4288c2ecf20Sopenharmony_ci	extern __typeof__(_type)  _name##_early_map[]
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci#define	early_per_cpu_ptr(_name) (_name##_early_ptr)
4318c2ecf20Sopenharmony_ci#define	early_per_cpu_map(_name, _idx) (_name##_early_map[_idx])
4328c2ecf20Sopenharmony_ci#define	early_per_cpu(_name, _cpu) 				\
4338c2ecf20Sopenharmony_ci	*(early_per_cpu_ptr(_name) ?				\
4348c2ecf20Sopenharmony_ci		&early_per_cpu_ptr(_name)[_cpu] :		\
4358c2ecf20Sopenharmony_ci		&per_cpu(_name, _cpu))
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci#else	/* !CONFIG_SMP */
4388c2ecf20Sopenharmony_ci#define	DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)		\
4398c2ecf20Sopenharmony_ci	DEFINE_PER_CPU(_type, _name) = _initvalue
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci#define DEFINE_EARLY_PER_CPU_READ_MOSTLY(_type, _name, _initvalue)	\
4428c2ecf20Sopenharmony_ci	DEFINE_PER_CPU_READ_MOSTLY(_type, _name) = _initvalue
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci#define EXPORT_EARLY_PER_CPU_SYMBOL(_name)			\
4458c2ecf20Sopenharmony_ci	EXPORT_PER_CPU_SYMBOL(_name)
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci#define DECLARE_EARLY_PER_CPU(_type, _name)			\
4488c2ecf20Sopenharmony_ci	DECLARE_PER_CPU(_type, _name)
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci#define DECLARE_EARLY_PER_CPU_READ_MOSTLY(_type, _name)		\
4518c2ecf20Sopenharmony_ci	DECLARE_PER_CPU_READ_MOSTLY(_type, _name)
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci#define	early_per_cpu(_name, _cpu) per_cpu(_name, _cpu)
4548c2ecf20Sopenharmony_ci#define	early_per_cpu_ptr(_name) NULL
4558c2ecf20Sopenharmony_ci/* no early_per_cpu_map() */
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci#endif	/* !CONFIG_SMP */
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci#endif /* _ASM_X86_PERCPU_H */
460