18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef __ASM_PERCPU_H 68c2ecf20Sopenharmony_ci#define __ASM_PERCPU_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * The "address" (in fact, offset from $r21) of a per-CPU variable is close to 128c2ecf20Sopenharmony_ci * the loading address of main kernel image, but far from where the modules are 138c2ecf20Sopenharmony_ci * loaded. Tell the compiler this fact when using explicit relocs. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#if defined(MODULE) && defined(CONFIG_AS_HAS_EXPLICIT_RELOCS) 168c2ecf20Sopenharmony_ci# if __has_attribute(model) 178c2ecf20Sopenharmony_ci# define PER_CPU_ATTRIBUTES __attribute__((model("extreme"))) 188c2ecf20Sopenharmony_ci# else 198c2ecf20Sopenharmony_ci# error compiler support for the model attribute is necessary when a recent assembler is used 208c2ecf20Sopenharmony_ci# endif 218c2ecf20Sopenharmony_ci#endif 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Use r21 for fast access */ 248c2ecf20Sopenharmony_ciregister unsigned long __my_cpu_offset __asm__("$r21"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic inline void set_my_cpu_offset(unsigned long off) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci __my_cpu_offset = off; 298c2ecf20Sopenharmony_ci csr_write64(off, PERCPU_BASE_KS); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci#define __my_cpu_offset __my_cpu_offset 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define PERCPU_OP(op, asm_op, c_op) \ 348c2ecf20Sopenharmony_cistatic __always_inline unsigned long __percpu_##op(void *ptr, \ 358c2ecf20Sopenharmony_ci unsigned long val, int size) \ 368c2ecf20Sopenharmony_ci{ \ 378c2ecf20Sopenharmony_ci unsigned long ret; \ 388c2ecf20Sopenharmony_ci \ 398c2ecf20Sopenharmony_ci switch (size) { \ 408c2ecf20Sopenharmony_ci case 4: \ 418c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 428c2ecf20Sopenharmony_ci "am"#asm_op".w" " %[ret], %[val], %[ptr] \n" \ 438c2ecf20Sopenharmony_ci : [ret] "=&r" (ret), [ptr] "+ZB"(*(u32 *)ptr) \ 448c2ecf20Sopenharmony_ci : [val] "r" (val)); \ 458c2ecf20Sopenharmony_ci break; \ 468c2ecf20Sopenharmony_ci case 8: \ 478c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 488c2ecf20Sopenharmony_ci "am"#asm_op".d" " %[ret], %[val], %[ptr] \n" \ 498c2ecf20Sopenharmony_ci : [ret] "=&r" (ret), [ptr] "+ZB"(*(u64 *)ptr) \ 508c2ecf20Sopenharmony_ci : [val] "r" (val)); \ 518c2ecf20Sopenharmony_ci break; \ 528c2ecf20Sopenharmony_ci default: \ 538c2ecf20Sopenharmony_ci ret = 0; \ 548c2ecf20Sopenharmony_ci BUILD_BUG(); \ 558c2ecf20Sopenharmony_ci } \ 568c2ecf20Sopenharmony_ci \ 578c2ecf20Sopenharmony_ci return ret c_op val; \ 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciPERCPU_OP(add, add, +) 618c2ecf20Sopenharmony_ciPERCPU_OP(and, and, &) 628c2ecf20Sopenharmony_ciPERCPU_OP(or, or, |) 638c2ecf20Sopenharmony_ci#undef PERCPU_OP 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic __always_inline unsigned long __percpu_read(void __percpu *ptr, int size) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned long ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci switch (size) { 708c2ecf20Sopenharmony_ci case 1: 718c2ecf20Sopenharmony_ci __asm__ __volatile__ ("ldx.b %[ret], $r21, %[ptr] \n" 728c2ecf20Sopenharmony_ci : [ret] "=&r"(ret) 738c2ecf20Sopenharmony_ci : [ptr] "r"(ptr) 748c2ecf20Sopenharmony_ci : "memory"); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case 2: 778c2ecf20Sopenharmony_ci __asm__ __volatile__ ("ldx.h %[ret], $r21, %[ptr] \n" 788c2ecf20Sopenharmony_ci : [ret] "=&r"(ret) 798c2ecf20Sopenharmony_ci : [ptr] "r"(ptr) 808c2ecf20Sopenharmony_ci : "memory"); 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci case 4: 838c2ecf20Sopenharmony_ci __asm__ __volatile__ ("ldx.w %[ret], $r21, %[ptr] \n" 848c2ecf20Sopenharmony_ci : [ret] "=&r"(ret) 858c2ecf20Sopenharmony_ci : [ptr] "r"(ptr) 868c2ecf20Sopenharmony_ci : "memory"); 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case 8: 898c2ecf20Sopenharmony_ci __asm__ __volatile__ ("ldx.d %[ret], $r21, %[ptr] \n" 908c2ecf20Sopenharmony_ci : [ret] "=&r"(ret) 918c2ecf20Sopenharmony_ci : [ptr] "r"(ptr) 928c2ecf20Sopenharmony_ci : "memory"); 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci default: 958c2ecf20Sopenharmony_ci ret = 0; 968c2ecf20Sopenharmony_ci BUILD_BUG(); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic __always_inline void __percpu_write(void __percpu *ptr, unsigned long val, int size) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci switch (size) { 1058c2ecf20Sopenharmony_ci case 1: 1068c2ecf20Sopenharmony_ci __asm__ __volatile__("stx.b %[val], $r21, %[ptr] \n" 1078c2ecf20Sopenharmony_ci : 1088c2ecf20Sopenharmony_ci : [val] "r" (val), [ptr] "r" (ptr) 1098c2ecf20Sopenharmony_ci : "memory"); 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case 2: 1128c2ecf20Sopenharmony_ci __asm__ __volatile__("stx.h %[val], $r21, %[ptr] \n" 1138c2ecf20Sopenharmony_ci : 1148c2ecf20Sopenharmony_ci : [val] "r" (val), [ptr] "r" (ptr) 1158c2ecf20Sopenharmony_ci : "memory"); 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case 4: 1188c2ecf20Sopenharmony_ci __asm__ __volatile__("stx.w %[val], $r21, %[ptr] \n" 1198c2ecf20Sopenharmony_ci : 1208c2ecf20Sopenharmony_ci : [val] "r" (val), [ptr] "r" (ptr) 1218c2ecf20Sopenharmony_ci : "memory"); 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case 8: 1248c2ecf20Sopenharmony_ci __asm__ __volatile__("stx.d %[val], $r21, %[ptr] \n" 1258c2ecf20Sopenharmony_ci : 1268c2ecf20Sopenharmony_ci : [val] "r" (val), [ptr] "r" (ptr) 1278c2ecf20Sopenharmony_ci : "memory"); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci default: 1308c2ecf20Sopenharmony_ci BUILD_BUG(); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, int size) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci switch (size) { 1378c2ecf20Sopenharmony_ci case 1: 1388c2ecf20Sopenharmony_ci case 2: 1398c2ecf20Sopenharmony_ci return __xchg_small((volatile void *)ptr, val, size); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci case 4: 1428c2ecf20Sopenharmony_ci return __xchg_asm("amswap.w", (volatile u32 *)ptr, (u32)val); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci case 8: 1458c2ecf20Sopenharmony_ci return __xchg_asm("amswap.d", (volatile u64 *)ptr, (u64)val); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci default: 1488c2ecf20Sopenharmony_ci BUILD_BUG(); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* this_cpu_cmpxchg */ 1558c2ecf20Sopenharmony_ci#define _protect_cmpxchg_local(pcp, o, n) \ 1568c2ecf20Sopenharmony_ci({ \ 1578c2ecf20Sopenharmony_ci typeof(*raw_cpu_ptr(&(pcp))) __ret; \ 1588c2ecf20Sopenharmony_ci preempt_disable_notrace(); \ 1598c2ecf20Sopenharmony_ci __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \ 1608c2ecf20Sopenharmony_ci preempt_enable_notrace(); \ 1618c2ecf20Sopenharmony_ci __ret; \ 1628c2ecf20Sopenharmony_ci}) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define _percpu_read(pcp) \ 1658c2ecf20Sopenharmony_ci({ \ 1668c2ecf20Sopenharmony_ci typeof(pcp) __retval; \ 1678c2ecf20Sopenharmony_ci __retval = (typeof(pcp))__percpu_read(&(pcp), sizeof(pcp)); \ 1688c2ecf20Sopenharmony_ci __retval; \ 1698c2ecf20Sopenharmony_ci}) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define _percpu_write(pcp, val) \ 1728c2ecf20Sopenharmony_cido { \ 1738c2ecf20Sopenharmony_ci __percpu_write(&(pcp), (unsigned long)(val), sizeof(pcp)); \ 1748c2ecf20Sopenharmony_ci} while (0) \ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define _pcp_protect(operation, pcp, val) \ 1778c2ecf20Sopenharmony_ci({ \ 1788c2ecf20Sopenharmony_ci typeof(pcp) __retval; \ 1798c2ecf20Sopenharmony_ci preempt_disable_notrace(); \ 1808c2ecf20Sopenharmony_ci __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)), \ 1818c2ecf20Sopenharmony_ci (val), sizeof(pcp)); \ 1828c2ecf20Sopenharmony_ci preempt_enable_notrace(); \ 1838c2ecf20Sopenharmony_ci __retval; \ 1848c2ecf20Sopenharmony_ci}) 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define _percpu_add(pcp, val) \ 1878c2ecf20Sopenharmony_ci _pcp_protect(__percpu_add, pcp, val) 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#define _percpu_add_return(pcp, val) _percpu_add(pcp, val) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define _percpu_and(pcp, val) \ 1928c2ecf20Sopenharmony_ci _pcp_protect(__percpu_and, pcp, val) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define _percpu_or(pcp, val) \ 1958c2ecf20Sopenharmony_ci _pcp_protect(__percpu_or, pcp, val) 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define _percpu_xchg(pcp, val) ((typeof(pcp)) \ 1988c2ecf20Sopenharmony_ci _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val))) 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define this_cpu_add_4(pcp, val) _percpu_add(pcp, val) 2018c2ecf20Sopenharmony_ci#define this_cpu_add_8(pcp, val) _percpu_add(pcp, val) 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define this_cpu_add_return_4(pcp, val) _percpu_add_return(pcp, val) 2048c2ecf20Sopenharmony_ci#define this_cpu_add_return_8(pcp, val) _percpu_add_return(pcp, val) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define this_cpu_and_4(pcp, val) _percpu_and(pcp, val) 2078c2ecf20Sopenharmony_ci#define this_cpu_and_8(pcp, val) _percpu_and(pcp, val) 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val) 2108c2ecf20Sopenharmony_ci#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val) 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#define this_cpu_read_1(pcp) _percpu_read(pcp) 2138c2ecf20Sopenharmony_ci#define this_cpu_read_2(pcp) _percpu_read(pcp) 2148c2ecf20Sopenharmony_ci#define this_cpu_read_4(pcp) _percpu_read(pcp) 2158c2ecf20Sopenharmony_ci#define this_cpu_read_8(pcp) _percpu_read(pcp) 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define this_cpu_write_1(pcp, val) _percpu_write(pcp, val) 2188c2ecf20Sopenharmony_ci#define this_cpu_write_2(pcp, val) _percpu_write(pcp, val) 2198c2ecf20Sopenharmony_ci#define this_cpu_write_4(pcp, val) _percpu_write(pcp, val) 2208c2ecf20Sopenharmony_ci#define this_cpu_write_8(pcp, val) _percpu_write(pcp, val) 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val) 2238c2ecf20Sopenharmony_ci#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val) 2248c2ecf20Sopenharmony_ci#define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val) 2258c2ecf20Sopenharmony_ci#define this_cpu_xchg_8(pcp, val) _percpu_xchg(pcp, val) 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) 2288c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) 2298c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) 2308c2ecf20Sopenharmony_ci#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#include <asm-generic/percpu.h> 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#endif /* __ASM_PERCPU_H */ 235