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