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