[PATCH v10 3/9] riscv: implement preemptible this_cpu read and write operations
Yunhui Cui
cuiyunhui at bytedance.com
Thu Nov 12 02:41:43 PST 2026
Apply the recoverable per-CPU address handling to read and write
operations.
Keep the address calculation and memory access in the same inline assembly
block, and use naturally sized loads and stores while preserving the type
semantics of the generic percpu API.
Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
---
arch/riscv/include/asm/percpu.h | 85 +++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/arch/riscv/include/asm/percpu.h b/arch/riscv/include/asm/percpu.h
index 59f7d44f7d3fe..ae7c123a48093 100644
--- a/arch/riscv/include/asm/percpu.h
+++ b/arch/riscv/include/asm/percpu.h
@@ -4,6 +4,7 @@
#define __ASM_PERCPU_H
#include <linux/bits.h>
+#include <linux/compiler.h>
#include <linux/stringify.h>
#include <linux/thread_info.h>
@@ -52,6 +53,90 @@
#define __PCPU_GPRS_END \
"sh zero, %[gprs]\n"
+#define __PCPU_OP_CONTEXT() \
+ struct thread_info *__ti = (struct thread_info *)current; \
+ unsigned long __off, __addr
+
+#define PERCPU_RW_OPS(load, store, sz) \
+static __always_inline unsigned long \
+__percpu_read_##sz(const void __percpu *pcp) \
+{ \
+ __PCPU_OP_CONTEXT(); \
+ unsigned long val; \
+ \
+ asm volatile (__PCPU_GPRS_BEGIN \
+ load " %[val], 0(%[addr])\n" \
+ __PCPU_GPRS_END \
+ : [gprs] "=m" (__ti->pcpu_gprs), \
+ [off] "=&r" (__off), [addr] "=&r" (__addr), \
+ [val] "=&r" (val) \
+ : [pcpu_offset] "m" (__ti->pcpu_offset), \
+ [pcp] "r" (pcp) \
+ : "memory"); \
+ \
+ return (u##sz)val; \
+} \
+ \
+static __always_inline void __percpu_write_##sz(void __percpu *pcp, \
+ unsigned long val) \
+{ \
+ __PCPU_OP_CONTEXT(); \
+ \
+ asm volatile (__PCPU_GPRS_BEGIN \
+ store " %[val], 0(%[addr])\n" \
+ __PCPU_GPRS_END \
+ : [gprs] "=m" (__ti->pcpu_gprs), \
+ [off] "=&r" (__off), [addr] "=&r" (__addr) \
+ : [pcpu_offset] "m" (__ti->pcpu_offset), \
+ [pcp] "r" (pcp), [val] "r" ((u##sz)val) \
+ : "memory"); \
+}
+
+PERCPU_RW_OPS("lbu", "sb", 8)
+PERCPU_RW_OPS("lhu", "sh", 16)
+
+#ifdef CONFIG_64BIT
+PERCPU_RW_OPS("lwu", "sw", 32)
+PERCPU_RW_OPS("ld", "sd", 64)
+#else
+PERCPU_RW_OPS("lw", "sw", 32)
+#endif
+
+#define _pcp_wrap(op, pcp, ...) \
+({ \
+ op(&(pcp), __VA_ARGS__); \
+})
+
+#define _pcp_wrap_return(op, pcp, args...) \
+({ \
+ __auto_type __pcp_ptr = &(pcp); \
+ \
+ (TYPEOF_UNQUAL(*__pcp_ptr))op(__pcp_ptr, ##args); \
+})
+
+#define this_cpu_read_1(pcp) _pcp_wrap_return(__percpu_read_8, pcp)
+#define this_cpu_read_2(pcp) _pcp_wrap_return(__percpu_read_16, pcp)
+#define this_cpu_read_4(pcp) _pcp_wrap_return(__percpu_read_32, pcp)
+
+#ifdef CONFIG_64BIT
+#define this_cpu_read_8(pcp) _pcp_wrap_return(__percpu_read_64, pcp)
+#endif
+
+#define this_cpu_write_1(pcp, val) \
+ _pcp_wrap(__percpu_write_8, pcp, (unsigned long)(val))
+#define this_cpu_write_2(pcp, val) \
+ _pcp_wrap(__percpu_write_16, pcp, (unsigned long)(val))
+#define this_cpu_write_4(pcp, val) \
+ _pcp_wrap(__percpu_write_32, pcp, (unsigned long)(val))
+
+#ifdef CONFIG_64BIT
+#define this_cpu_write_8(pcp, val) \
+ _pcp_wrap(__percpu_write_64, pcp, (unsigned long)(val))
+#endif
+
+#undef PERCPU_RW_OPS
+#undef __PCPU_OP_CONTEXT
+
#include <asm-generic/percpu.h>
#endif /* __ASM_PERCPU_H */
--
2.39.5
More information about the linux-riscv
mailing list