18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 ARM Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef __ASM_PERCPU_H 68c2ecf20Sopenharmony_ci#define __ASM_PERCPU_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/preempt.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <asm/alternative.h> 118c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 128c2ecf20Sopenharmony_ci#include <asm/stack_pointer.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic inline void set_my_cpu_offset(unsigned long off) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci asm volatile(ALTERNATIVE("msr tpidr_el1, %0", 178c2ecf20Sopenharmony_ci "msr tpidr_el2, %0", 188c2ecf20Sopenharmony_ci ARM64_HAS_VIRT_HOST_EXTN) 198c2ecf20Sopenharmony_ci :: "r" (off) : "memory"); 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic inline unsigned long __hyp_my_cpu_offset(void) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci /* 258c2ecf20Sopenharmony_ci * Non-VHE hyp code runs with preemption disabled. No need to hazard 268c2ecf20Sopenharmony_ci * the register access against barrier() as in __kern_my_cpu_offset. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci return read_sysreg(tpidr_el2); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic inline unsigned long __kern_my_cpu_offset(void) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci unsigned long off; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* 368c2ecf20Sopenharmony_ci * We want to allow caching the value, so avoid using volatile and 378c2ecf20Sopenharmony_ci * instead use a fake stack read to hazard against barrier(). 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci asm(ALTERNATIVE("mrs %0, tpidr_el1", 408c2ecf20Sopenharmony_ci "mrs %0, tpidr_el2", 418c2ecf20Sopenharmony_ci ARM64_HAS_VIRT_HOST_EXTN) 428c2ecf20Sopenharmony_ci : "=r" (off) : 438c2ecf20Sopenharmony_ci "Q" (*(const unsigned long *)current_stack_pointer)); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return off; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#ifdef __KVM_NVHE_HYPERVISOR__ 498c2ecf20Sopenharmony_ci#define __my_cpu_offset __hyp_my_cpu_offset() 508c2ecf20Sopenharmony_ci#else 518c2ecf20Sopenharmony_ci#define __my_cpu_offset __kern_my_cpu_offset() 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define PERCPU_RW_OPS(sz) \ 558c2ecf20Sopenharmony_cistatic inline unsigned long __percpu_read_##sz(void *ptr) \ 568c2ecf20Sopenharmony_ci{ \ 578c2ecf20Sopenharmony_ci return READ_ONCE(*(u##sz *)ptr); \ 588c2ecf20Sopenharmony_ci} \ 598c2ecf20Sopenharmony_ci \ 608c2ecf20Sopenharmony_cistatic inline void __percpu_write_##sz(void *ptr, unsigned long val) \ 618c2ecf20Sopenharmony_ci{ \ 628c2ecf20Sopenharmony_ci WRITE_ONCE(*(u##sz *)ptr, (u##sz)val); \ 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define __PERCPU_OP_CASE(w, sfx, name, sz, op_llsc, op_lse) \ 668c2ecf20Sopenharmony_cistatic inline void \ 678c2ecf20Sopenharmony_ci__percpu_##name##_case_##sz(void *ptr, unsigned long val) \ 688c2ecf20Sopenharmony_ci{ \ 698c2ecf20Sopenharmony_ci unsigned int loop; \ 708c2ecf20Sopenharmony_ci u##sz tmp; \ 718c2ecf20Sopenharmony_ci \ 728c2ecf20Sopenharmony_ci asm volatile (ARM64_LSE_ATOMIC_INSN( \ 738c2ecf20Sopenharmony_ci /* LL/SC */ \ 748c2ecf20Sopenharmony_ci "1: ldxr" #sfx "\t%" #w "[tmp], %[ptr]\n" \ 758c2ecf20Sopenharmony_ci #op_llsc "\t%" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ 768c2ecf20Sopenharmony_ci " stxr" #sfx "\t%w[loop], %" #w "[tmp], %[ptr]\n" \ 778c2ecf20Sopenharmony_ci " cbnz %w[loop], 1b", \ 788c2ecf20Sopenharmony_ci /* LSE atomics */ \ 798c2ecf20Sopenharmony_ci #op_lse "\t%" #w "[val], %[ptr]\n" \ 808c2ecf20Sopenharmony_ci __nops(3)) \ 818c2ecf20Sopenharmony_ci : [loop] "=&r" (loop), [tmp] "=&r" (tmp), \ 828c2ecf20Sopenharmony_ci [ptr] "+Q"(*(u##sz *)ptr) \ 838c2ecf20Sopenharmony_ci : [val] "r" ((u##sz)(val))); \ 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define __PERCPU_RET_OP_CASE(w, sfx, name, sz, op_llsc, op_lse) \ 878c2ecf20Sopenharmony_cistatic inline u##sz \ 888c2ecf20Sopenharmony_ci__percpu_##name##_return_case_##sz(void *ptr, unsigned long val) \ 898c2ecf20Sopenharmony_ci{ \ 908c2ecf20Sopenharmony_ci unsigned int loop; \ 918c2ecf20Sopenharmony_ci u##sz ret; \ 928c2ecf20Sopenharmony_ci \ 938c2ecf20Sopenharmony_ci asm volatile (ARM64_LSE_ATOMIC_INSN( \ 948c2ecf20Sopenharmony_ci /* LL/SC */ \ 958c2ecf20Sopenharmony_ci "1: ldxr" #sfx "\t%" #w "[ret], %[ptr]\n" \ 968c2ecf20Sopenharmony_ci #op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n" \ 978c2ecf20Sopenharmony_ci " stxr" #sfx "\t%w[loop], %" #w "[ret], %[ptr]\n" \ 988c2ecf20Sopenharmony_ci " cbnz %w[loop], 1b", \ 998c2ecf20Sopenharmony_ci /* LSE atomics */ \ 1008c2ecf20Sopenharmony_ci #op_lse "\t%" #w "[val], %" #w "[ret], %[ptr]\n" \ 1018c2ecf20Sopenharmony_ci #op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n" \ 1028c2ecf20Sopenharmony_ci __nops(2)) \ 1038c2ecf20Sopenharmony_ci : [loop] "=&r" (loop), [ret] "=&r" (ret), \ 1048c2ecf20Sopenharmony_ci [ptr] "+Q"(*(u##sz *)ptr) \ 1058c2ecf20Sopenharmony_ci : [val] "r" ((u##sz)(val))); \ 1068c2ecf20Sopenharmony_ci \ 1078c2ecf20Sopenharmony_ci return ret; \ 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define PERCPU_OP(name, op_llsc, op_lse) \ 1118c2ecf20Sopenharmony_ci __PERCPU_OP_CASE(w, b, name, 8, op_llsc, op_lse) \ 1128c2ecf20Sopenharmony_ci __PERCPU_OP_CASE(w, h, name, 16, op_llsc, op_lse) \ 1138c2ecf20Sopenharmony_ci __PERCPU_OP_CASE(w, , name, 32, op_llsc, op_lse) \ 1148c2ecf20Sopenharmony_ci __PERCPU_OP_CASE( , , name, 64, op_llsc, op_lse) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#define PERCPU_RET_OP(name, op_llsc, op_lse) \ 1178c2ecf20Sopenharmony_ci __PERCPU_RET_OP_CASE(w, b, name, 8, op_llsc, op_lse) \ 1188c2ecf20Sopenharmony_ci __PERCPU_RET_OP_CASE(w, h, name, 16, op_llsc, op_lse) \ 1198c2ecf20Sopenharmony_ci __PERCPU_RET_OP_CASE(w, , name, 32, op_llsc, op_lse) \ 1208c2ecf20Sopenharmony_ci __PERCPU_RET_OP_CASE( , , name, 64, op_llsc, op_lse) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciPERCPU_RW_OPS(8) 1238c2ecf20Sopenharmony_ciPERCPU_RW_OPS(16) 1248c2ecf20Sopenharmony_ciPERCPU_RW_OPS(32) 1258c2ecf20Sopenharmony_ciPERCPU_RW_OPS(64) 1268c2ecf20Sopenharmony_ciPERCPU_OP(add, add, stadd) 1278c2ecf20Sopenharmony_ciPERCPU_OP(andnot, bic, stclr) 1288c2ecf20Sopenharmony_ciPERCPU_OP(or, orr, stset) 1298c2ecf20Sopenharmony_ciPERCPU_RET_OP(add, add, ldadd) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#undef PERCPU_RW_OPS 1328c2ecf20Sopenharmony_ci#undef __PERCPU_OP_CASE 1338c2ecf20Sopenharmony_ci#undef __PERCPU_RET_OP_CASE 1348c2ecf20Sopenharmony_ci#undef PERCPU_OP 1358c2ecf20Sopenharmony_ci#undef PERCPU_RET_OP 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* 1388c2ecf20Sopenharmony_ci * It would be nice to avoid the conditional call into the scheduler when 1398c2ecf20Sopenharmony_ci * re-enabling preemption for preemptible kernels, but doing that in a way 1408c2ecf20Sopenharmony_ci * which builds inside a module would mean messing directly with the preempt 1418c2ecf20Sopenharmony_ci * count. If you do this, peterz and tglx will hunt you down. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \ 1448c2ecf20Sopenharmony_ci({ \ 1458c2ecf20Sopenharmony_ci int __ret; \ 1468c2ecf20Sopenharmony_ci preempt_disable_notrace(); \ 1478c2ecf20Sopenharmony_ci __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \ 1488c2ecf20Sopenharmony_ci raw_cpu_ptr(&(ptr2)), \ 1498c2ecf20Sopenharmony_ci o1, o2, n1, n2); \ 1508c2ecf20Sopenharmony_ci preempt_enable_notrace(); \ 1518c2ecf20Sopenharmony_ci __ret; \ 1528c2ecf20Sopenharmony_ci}) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#define _pcp_protect(op, pcp, ...) \ 1558c2ecf20Sopenharmony_ci({ \ 1568c2ecf20Sopenharmony_ci preempt_disable_notrace(); \ 1578c2ecf20Sopenharmony_ci op(raw_cpu_ptr(&(pcp)), __VA_ARGS__); \ 1588c2ecf20Sopenharmony_ci preempt_enable_notrace(); \ 1598c2ecf20Sopenharmony_ci}) 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define _pcp_protect_return(op, pcp, args...) \ 1628c2ecf20Sopenharmony_ci({ \ 1638c2ecf20Sopenharmony_ci typeof(pcp) __retval; \ 1648c2ecf20Sopenharmony_ci preempt_disable_notrace(); \ 1658c2ecf20Sopenharmony_ci __retval = (typeof(pcp))op(raw_cpu_ptr(&(pcp)), ##args); \ 1668c2ecf20Sopenharmony_ci preempt_enable_notrace(); \ 1678c2ecf20Sopenharmony_ci __retval; \ 1688c2ecf20Sopenharmony_ci}) 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define this_cpu_read_1(pcp) \ 1718c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_read_8, pcp) 1728c2ecf20Sopenharmony_ci#define this_cpu_read_2(pcp) \ 1738c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_read_16, pcp) 1748c2ecf20Sopenharmony_ci#define this_cpu_read_4(pcp) \ 1758c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_read_32, pcp) 1768c2ecf20Sopenharmony_ci#define this_cpu_read_8(pcp) \ 1778c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_read_64, pcp) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define this_cpu_write_1(pcp, val) \ 1808c2ecf20Sopenharmony_ci _pcp_protect(__percpu_write_8, pcp, (unsigned long)val) 1818c2ecf20Sopenharmony_ci#define this_cpu_write_2(pcp, val) \ 1828c2ecf20Sopenharmony_ci _pcp_protect(__percpu_write_16, pcp, (unsigned long)val) 1838c2ecf20Sopenharmony_ci#define this_cpu_write_4(pcp, val) \ 1848c2ecf20Sopenharmony_ci _pcp_protect(__percpu_write_32, pcp, (unsigned long)val) 1858c2ecf20Sopenharmony_ci#define this_cpu_write_8(pcp, val) \ 1868c2ecf20Sopenharmony_ci _pcp_protect(__percpu_write_64, pcp, (unsigned long)val) 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define this_cpu_add_1(pcp, val) \ 1898c2ecf20Sopenharmony_ci _pcp_protect(__percpu_add_case_8, pcp, val) 1908c2ecf20Sopenharmony_ci#define this_cpu_add_2(pcp, val) \ 1918c2ecf20Sopenharmony_ci _pcp_protect(__percpu_add_case_16, pcp, val) 1928c2ecf20Sopenharmony_ci#define this_cpu_add_4(pcp, val) \ 1938c2ecf20Sopenharmony_ci _pcp_protect(__percpu_add_case_32, pcp, val) 1948c2ecf20Sopenharmony_ci#define this_cpu_add_8(pcp, val) \ 1958c2ecf20Sopenharmony_ci _pcp_protect(__percpu_add_case_64, pcp, val) 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define this_cpu_add_return_1(pcp, val) \ 1988c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_8, pcp, val) 1998c2ecf20Sopenharmony_ci#define this_cpu_add_return_2(pcp, val) \ 2008c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_16, pcp, val) 2018c2ecf20Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) \ 2028c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_32, pcp, val) 2038c2ecf20Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) \ 2048c2ecf20Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_64, pcp, val) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define this_cpu_and_1(pcp, val) \ 2078c2ecf20Sopenharmony_ci _pcp_protect(__percpu_andnot_case_8, pcp, ~val) 2088c2ecf20Sopenharmony_ci#define this_cpu_and_2(pcp, val) \ 2098c2ecf20Sopenharmony_ci _pcp_protect(__percpu_andnot_case_16, pcp, ~val) 2108c2ecf20Sopenharmony_ci#define this_cpu_and_4(pcp, val) \ 2118c2ecf20Sopenharmony_ci _pcp_protect(__percpu_andnot_case_32, pcp, ~val) 2128c2ecf20Sopenharmony_ci#define this_cpu_and_8(pcp, val) \ 2138c2ecf20Sopenharmony_ci _pcp_protect(__percpu_andnot_case_64, pcp, ~val) 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define this_cpu_or_1(pcp, val) \ 2168c2ecf20Sopenharmony_ci _pcp_protect(__percpu_or_case_8, pcp, val) 2178c2ecf20Sopenharmony_ci#define this_cpu_or_2(pcp, val) \ 2188c2ecf20Sopenharmony_ci _pcp_protect(__percpu_or_case_16, pcp, val) 2198c2ecf20Sopenharmony_ci#define this_cpu_or_4(pcp, val) \ 2208c2ecf20Sopenharmony_ci _pcp_protect(__percpu_or_case_32, pcp, val) 2218c2ecf20Sopenharmony_ci#define this_cpu_or_8(pcp, val) \ 2228c2ecf20Sopenharmony_ci _pcp_protect(__percpu_or_case_64, pcp, val) 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci#define this_cpu_xchg_1(pcp, val) \ 2258c2ecf20Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 2268c2ecf20Sopenharmony_ci#define this_cpu_xchg_2(pcp, val) \ 2278c2ecf20Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 2288c2ecf20Sopenharmony_ci#define this_cpu_xchg_4(pcp, val) \ 2298c2ecf20Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 2308c2ecf20Sopenharmony_ci#define this_cpu_xchg_8(pcp, val) \ 2318c2ecf20Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_1(pcp, o, n) \ 2348c2ecf20Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 2358c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_2(pcp, o, n) \ 2368c2ecf20Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 2378c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_4(pcp, o, n) \ 2388c2ecf20Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 2398c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_8(pcp, o, n) \ 2408c2ecf20Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#include <asm-generic/percpu.h> 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* Redefine macros for nVHE hyp under DEBUG_PREEMPT to avoid its dependencies. */ 2458c2ecf20Sopenharmony_ci#if defined(__KVM_NVHE_HYPERVISOR__) && defined(CONFIG_DEBUG_PREEMPT) 2468c2ecf20Sopenharmony_ci#undef this_cpu_ptr 2478c2ecf20Sopenharmony_ci#define this_cpu_ptr raw_cpu_ptr 2488c2ecf20Sopenharmony_ci#undef __this_cpu_read 2498c2ecf20Sopenharmony_ci#define __this_cpu_read raw_cpu_read 2508c2ecf20Sopenharmony_ci#undef __this_cpu_write 2518c2ecf20Sopenharmony_ci#define __this_cpu_write raw_cpu_write 2528c2ecf20Sopenharmony_ci#endif 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#endif /* __ASM_PERCPU_H */ 255