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