162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 ARM Ltd. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#ifndef __ASM_PERCPU_H 662306a36Sopenharmony_ci#define __ASM_PERCPU_H 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/preempt.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/alternative.h> 1162306a36Sopenharmony_ci#include <asm/cmpxchg.h> 1262306a36Sopenharmony_ci#include <asm/stack_pointer.h> 1362306a36Sopenharmony_ci#include <asm/sysreg.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic inline void set_my_cpu_offset(unsigned long off) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci asm volatile(ALTERNATIVE("msr tpidr_el1, %0", 1862306a36Sopenharmony_ci "msr tpidr_el2, %0", 1962306a36Sopenharmony_ci ARM64_HAS_VIRT_HOST_EXTN) 2062306a36Sopenharmony_ci :: "r" (off) : "memory"); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic inline unsigned long __hyp_my_cpu_offset(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci /* 2662306a36Sopenharmony_ci * Non-VHE hyp code runs with preemption disabled. No need to hazard 2762306a36Sopenharmony_ci * the register access against barrier() as in __kern_my_cpu_offset. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci return read_sysreg(tpidr_el2); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline unsigned long __kern_my_cpu_offset(void) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci unsigned long off; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* 3762306a36Sopenharmony_ci * We want to allow caching the value, so avoid using volatile and 3862306a36Sopenharmony_ci * instead use a fake stack read to hazard against barrier(). 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci asm(ALTERNATIVE("mrs %0, tpidr_el1", 4162306a36Sopenharmony_ci "mrs %0, tpidr_el2", 4262306a36Sopenharmony_ci ARM64_HAS_VIRT_HOST_EXTN) 4362306a36Sopenharmony_ci : "=r" (off) : 4462306a36Sopenharmony_ci "Q" (*(const unsigned long *)current_stack_pointer)); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return off; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#ifdef __KVM_NVHE_HYPERVISOR__ 5062306a36Sopenharmony_ci#define __my_cpu_offset __hyp_my_cpu_offset() 5162306a36Sopenharmony_ci#else 5262306a36Sopenharmony_ci#define __my_cpu_offset __kern_my_cpu_offset() 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define PERCPU_RW_OPS(sz) \ 5662306a36Sopenharmony_cistatic inline unsigned long __percpu_read_##sz(void *ptr) \ 5762306a36Sopenharmony_ci{ \ 5862306a36Sopenharmony_ci return READ_ONCE(*(u##sz *)ptr); \ 5962306a36Sopenharmony_ci} \ 6062306a36Sopenharmony_ci \ 6162306a36Sopenharmony_cistatic inline void __percpu_write_##sz(void *ptr, unsigned long val) \ 6262306a36Sopenharmony_ci{ \ 6362306a36Sopenharmony_ci WRITE_ONCE(*(u##sz *)ptr, (u##sz)val); \ 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define __PERCPU_OP_CASE(w, sfx, name, sz, op_llsc, op_lse) \ 6762306a36Sopenharmony_cistatic inline void \ 6862306a36Sopenharmony_ci__percpu_##name##_case_##sz(void *ptr, unsigned long val) \ 6962306a36Sopenharmony_ci{ \ 7062306a36Sopenharmony_ci unsigned int loop; \ 7162306a36Sopenharmony_ci u##sz tmp; \ 7262306a36Sopenharmony_ci \ 7362306a36Sopenharmony_ci asm volatile (ARM64_LSE_ATOMIC_INSN( \ 7462306a36Sopenharmony_ci /* LL/SC */ \ 7562306a36Sopenharmony_ci "1: ldxr" #sfx "\t%" #w "[tmp], %[ptr]\n" \ 7662306a36Sopenharmony_ci #op_llsc "\t%" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ 7762306a36Sopenharmony_ci " stxr" #sfx "\t%w[loop], %" #w "[tmp], %[ptr]\n" \ 7862306a36Sopenharmony_ci " cbnz %w[loop], 1b", \ 7962306a36Sopenharmony_ci /* LSE atomics */ \ 8062306a36Sopenharmony_ci #op_lse "\t%" #w "[val], %[ptr]\n" \ 8162306a36Sopenharmony_ci __nops(3)) \ 8262306a36Sopenharmony_ci : [loop] "=&r" (loop), [tmp] "=&r" (tmp), \ 8362306a36Sopenharmony_ci [ptr] "+Q"(*(u##sz *)ptr) \ 8462306a36Sopenharmony_ci : [val] "r" ((u##sz)(val))); \ 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define __PERCPU_RET_OP_CASE(w, sfx, name, sz, op_llsc, op_lse) \ 8862306a36Sopenharmony_cistatic inline u##sz \ 8962306a36Sopenharmony_ci__percpu_##name##_return_case_##sz(void *ptr, unsigned long val) \ 9062306a36Sopenharmony_ci{ \ 9162306a36Sopenharmony_ci unsigned int loop; \ 9262306a36Sopenharmony_ci u##sz ret; \ 9362306a36Sopenharmony_ci \ 9462306a36Sopenharmony_ci asm volatile (ARM64_LSE_ATOMIC_INSN( \ 9562306a36Sopenharmony_ci /* LL/SC */ \ 9662306a36Sopenharmony_ci "1: ldxr" #sfx "\t%" #w "[ret], %[ptr]\n" \ 9762306a36Sopenharmony_ci #op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n" \ 9862306a36Sopenharmony_ci " stxr" #sfx "\t%w[loop], %" #w "[ret], %[ptr]\n" \ 9962306a36Sopenharmony_ci " cbnz %w[loop], 1b", \ 10062306a36Sopenharmony_ci /* LSE atomics */ \ 10162306a36Sopenharmony_ci #op_lse "\t%" #w "[val], %" #w "[ret], %[ptr]\n" \ 10262306a36Sopenharmony_ci #op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n" \ 10362306a36Sopenharmony_ci __nops(2)) \ 10462306a36Sopenharmony_ci : [loop] "=&r" (loop), [ret] "=&r" (ret), \ 10562306a36Sopenharmony_ci [ptr] "+Q"(*(u##sz *)ptr) \ 10662306a36Sopenharmony_ci : [val] "r" ((u##sz)(val))); \ 10762306a36Sopenharmony_ci \ 10862306a36Sopenharmony_ci return ret; \ 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define PERCPU_OP(name, op_llsc, op_lse) \ 11262306a36Sopenharmony_ci __PERCPU_OP_CASE(w, b, name, 8, op_llsc, op_lse) \ 11362306a36Sopenharmony_ci __PERCPU_OP_CASE(w, h, name, 16, op_llsc, op_lse) \ 11462306a36Sopenharmony_ci __PERCPU_OP_CASE(w, , name, 32, op_llsc, op_lse) \ 11562306a36Sopenharmony_ci __PERCPU_OP_CASE( , , name, 64, op_llsc, op_lse) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define PERCPU_RET_OP(name, op_llsc, op_lse) \ 11862306a36Sopenharmony_ci __PERCPU_RET_OP_CASE(w, b, name, 8, op_llsc, op_lse) \ 11962306a36Sopenharmony_ci __PERCPU_RET_OP_CASE(w, h, name, 16, op_llsc, op_lse) \ 12062306a36Sopenharmony_ci __PERCPU_RET_OP_CASE(w, , name, 32, op_llsc, op_lse) \ 12162306a36Sopenharmony_ci __PERCPU_RET_OP_CASE( , , name, 64, op_llsc, op_lse) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciPERCPU_RW_OPS(8) 12462306a36Sopenharmony_ciPERCPU_RW_OPS(16) 12562306a36Sopenharmony_ciPERCPU_RW_OPS(32) 12662306a36Sopenharmony_ciPERCPU_RW_OPS(64) 12762306a36Sopenharmony_ciPERCPU_OP(add, add, stadd) 12862306a36Sopenharmony_ciPERCPU_OP(andnot, bic, stclr) 12962306a36Sopenharmony_ciPERCPU_OP(or, orr, stset) 13062306a36Sopenharmony_ciPERCPU_RET_OP(add, add, ldadd) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#undef PERCPU_RW_OPS 13362306a36Sopenharmony_ci#undef __PERCPU_OP_CASE 13462306a36Sopenharmony_ci#undef __PERCPU_RET_OP_CASE 13562306a36Sopenharmony_ci#undef PERCPU_OP 13662306a36Sopenharmony_ci#undef PERCPU_RET_OP 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * It would be nice to avoid the conditional call into the scheduler when 14062306a36Sopenharmony_ci * re-enabling preemption for preemptible kernels, but doing that in a way 14162306a36Sopenharmony_ci * which builds inside a module would mean messing directly with the preempt 14262306a36Sopenharmony_ci * count. If you do this, peterz and tglx will hunt you down. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Not to mention it'll break the actual preemption model for missing a 14562306a36Sopenharmony_ci * preemption point when TIF_NEED_RESCHED gets set while preemption is 14662306a36Sopenharmony_ci * disabled. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define _pcp_protect(op, pcp, ...) \ 15062306a36Sopenharmony_ci({ \ 15162306a36Sopenharmony_ci preempt_disable_notrace(); \ 15262306a36Sopenharmony_ci op(raw_cpu_ptr(&(pcp)), __VA_ARGS__); \ 15362306a36Sopenharmony_ci preempt_enable_notrace(); \ 15462306a36Sopenharmony_ci}) 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#define _pcp_protect_return(op, pcp, args...) \ 15762306a36Sopenharmony_ci({ \ 15862306a36Sopenharmony_ci typeof(pcp) __retval; \ 15962306a36Sopenharmony_ci preempt_disable_notrace(); \ 16062306a36Sopenharmony_ci __retval = (typeof(pcp))op(raw_cpu_ptr(&(pcp)), ##args); \ 16162306a36Sopenharmony_ci preempt_enable_notrace(); \ 16262306a36Sopenharmony_ci __retval; \ 16362306a36Sopenharmony_ci}) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define this_cpu_read_1(pcp) \ 16662306a36Sopenharmony_ci _pcp_protect_return(__percpu_read_8, pcp) 16762306a36Sopenharmony_ci#define this_cpu_read_2(pcp) \ 16862306a36Sopenharmony_ci _pcp_protect_return(__percpu_read_16, pcp) 16962306a36Sopenharmony_ci#define this_cpu_read_4(pcp) \ 17062306a36Sopenharmony_ci _pcp_protect_return(__percpu_read_32, pcp) 17162306a36Sopenharmony_ci#define this_cpu_read_8(pcp) \ 17262306a36Sopenharmony_ci _pcp_protect_return(__percpu_read_64, pcp) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define this_cpu_write_1(pcp, val) \ 17562306a36Sopenharmony_ci _pcp_protect(__percpu_write_8, pcp, (unsigned long)val) 17662306a36Sopenharmony_ci#define this_cpu_write_2(pcp, val) \ 17762306a36Sopenharmony_ci _pcp_protect(__percpu_write_16, pcp, (unsigned long)val) 17862306a36Sopenharmony_ci#define this_cpu_write_4(pcp, val) \ 17962306a36Sopenharmony_ci _pcp_protect(__percpu_write_32, pcp, (unsigned long)val) 18062306a36Sopenharmony_ci#define this_cpu_write_8(pcp, val) \ 18162306a36Sopenharmony_ci _pcp_protect(__percpu_write_64, pcp, (unsigned long)val) 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci#define this_cpu_add_1(pcp, val) \ 18462306a36Sopenharmony_ci _pcp_protect(__percpu_add_case_8, pcp, val) 18562306a36Sopenharmony_ci#define this_cpu_add_2(pcp, val) \ 18662306a36Sopenharmony_ci _pcp_protect(__percpu_add_case_16, pcp, val) 18762306a36Sopenharmony_ci#define this_cpu_add_4(pcp, val) \ 18862306a36Sopenharmony_ci _pcp_protect(__percpu_add_case_32, pcp, val) 18962306a36Sopenharmony_ci#define this_cpu_add_8(pcp, val) \ 19062306a36Sopenharmony_ci _pcp_protect(__percpu_add_case_64, pcp, val) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define this_cpu_add_return_1(pcp, val) \ 19362306a36Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_8, pcp, val) 19462306a36Sopenharmony_ci#define this_cpu_add_return_2(pcp, val) \ 19562306a36Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_16, pcp, val) 19662306a36Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) \ 19762306a36Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_32, pcp, val) 19862306a36Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) \ 19962306a36Sopenharmony_ci _pcp_protect_return(__percpu_add_return_case_64, pcp, val) 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define this_cpu_and_1(pcp, val) \ 20262306a36Sopenharmony_ci _pcp_protect(__percpu_andnot_case_8, pcp, ~val) 20362306a36Sopenharmony_ci#define this_cpu_and_2(pcp, val) \ 20462306a36Sopenharmony_ci _pcp_protect(__percpu_andnot_case_16, pcp, ~val) 20562306a36Sopenharmony_ci#define this_cpu_and_4(pcp, val) \ 20662306a36Sopenharmony_ci _pcp_protect(__percpu_andnot_case_32, pcp, ~val) 20762306a36Sopenharmony_ci#define this_cpu_and_8(pcp, val) \ 20862306a36Sopenharmony_ci _pcp_protect(__percpu_andnot_case_64, pcp, ~val) 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define this_cpu_or_1(pcp, val) \ 21162306a36Sopenharmony_ci _pcp_protect(__percpu_or_case_8, pcp, val) 21262306a36Sopenharmony_ci#define this_cpu_or_2(pcp, val) \ 21362306a36Sopenharmony_ci _pcp_protect(__percpu_or_case_16, pcp, val) 21462306a36Sopenharmony_ci#define this_cpu_or_4(pcp, val) \ 21562306a36Sopenharmony_ci _pcp_protect(__percpu_or_case_32, pcp, val) 21662306a36Sopenharmony_ci#define this_cpu_or_8(pcp, val) \ 21762306a36Sopenharmony_ci _pcp_protect(__percpu_or_case_64, pcp, val) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define this_cpu_xchg_1(pcp, val) \ 22062306a36Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 22162306a36Sopenharmony_ci#define this_cpu_xchg_2(pcp, val) \ 22262306a36Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 22362306a36Sopenharmony_ci#define this_cpu_xchg_4(pcp, val) \ 22462306a36Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 22562306a36Sopenharmony_ci#define this_cpu_xchg_8(pcp, val) \ 22662306a36Sopenharmony_ci _pcp_protect_return(xchg_relaxed, pcp, val) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define this_cpu_cmpxchg_1(pcp, o, n) \ 22962306a36Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 23062306a36Sopenharmony_ci#define this_cpu_cmpxchg_2(pcp, o, n) \ 23162306a36Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 23262306a36Sopenharmony_ci#define this_cpu_cmpxchg_4(pcp, o, n) \ 23362306a36Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 23462306a36Sopenharmony_ci#define this_cpu_cmpxchg_8(pcp, o, n) \ 23562306a36Sopenharmony_ci _pcp_protect_return(cmpxchg_relaxed, pcp, o, n) 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#define this_cpu_cmpxchg64(pcp, o, n) this_cpu_cmpxchg_8(pcp, o, n) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define this_cpu_cmpxchg128(pcp, o, n) \ 24062306a36Sopenharmony_ci({ \ 24162306a36Sopenharmony_ci typedef typeof(pcp) pcp_op_T__; \ 24262306a36Sopenharmony_ci u128 old__, new__, ret__; \ 24362306a36Sopenharmony_ci pcp_op_T__ *ptr__; \ 24462306a36Sopenharmony_ci old__ = o; \ 24562306a36Sopenharmony_ci new__ = n; \ 24662306a36Sopenharmony_ci preempt_disable_notrace(); \ 24762306a36Sopenharmony_ci ptr__ = raw_cpu_ptr(&(pcp)); \ 24862306a36Sopenharmony_ci ret__ = cmpxchg128_local((void *)ptr__, old__, new__); \ 24962306a36Sopenharmony_ci preempt_enable_notrace(); \ 25062306a36Sopenharmony_ci ret__; \ 25162306a36Sopenharmony_ci}) 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#ifdef __KVM_NVHE_HYPERVISOR__ 25462306a36Sopenharmony_ciextern unsigned long __hyp_per_cpu_offset(unsigned int cpu); 25562306a36Sopenharmony_ci#define __per_cpu_offset 25662306a36Sopenharmony_ci#define per_cpu_offset(cpu) __hyp_per_cpu_offset((cpu)) 25762306a36Sopenharmony_ci#endif 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci#include <asm-generic/percpu.h> 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* Redefine macros for nVHE hyp under DEBUG_PREEMPT to avoid its dependencies. */ 26262306a36Sopenharmony_ci#if defined(__KVM_NVHE_HYPERVISOR__) && defined(CONFIG_DEBUG_PREEMPT) 26362306a36Sopenharmony_ci#undef this_cpu_ptr 26462306a36Sopenharmony_ci#define this_cpu_ptr raw_cpu_ptr 26562306a36Sopenharmony_ci#undef __this_cpu_read 26662306a36Sopenharmony_ci#define __this_cpu_read raw_cpu_read 26762306a36Sopenharmony_ci#undef __this_cpu_write 26862306a36Sopenharmony_ci#define __this_cpu_write raw_cpu_write 26962306a36Sopenharmony_ci#endif 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#endif /* __ASM_PERCPU_H */ 272