xref: /linux/tools/testing/selftests/bpf/libarena/include/bpf_atomic.h (revision 8c1e1c33fe5ad867bc0b6ba121911d70e7881d88)
1*8c1e1c33SEmil Tsalapatis // SPDX-License-Identifier: GPL-2.0
2*8c1e1c33SEmil Tsalapatis /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3*8c1e1c33SEmil Tsalapatis #ifndef BPF_ATOMIC_H
4*8c1e1c33SEmil Tsalapatis #define BPF_ATOMIC_H
5*8c1e1c33SEmil Tsalapatis 
6*8c1e1c33SEmil Tsalapatis #include <vmlinux.h>
7*8c1e1c33SEmil Tsalapatis #include <bpf/bpf_helpers.h>
8*8c1e1c33SEmil Tsalapatis #include <bpf_may_goto.h>
9*8c1e1c33SEmil Tsalapatis 
10*8c1e1c33SEmil Tsalapatis extern bool CONFIG_X86_64 __kconfig __weak;
11*8c1e1c33SEmil Tsalapatis 
12*8c1e1c33SEmil Tsalapatis /*
13*8c1e1c33SEmil Tsalapatis  * __unqual_typeof(x) - Declare an unqualified scalar type, leaving
14*8c1e1c33SEmil Tsalapatis  *			non-scalar types unchanged,
15*8c1e1c33SEmil Tsalapatis  *
16*8c1e1c33SEmil Tsalapatis  * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
17*8c1e1c33SEmil Tsalapatis  * is not type-compatible with 'signed char', and we define a separate case.
18*8c1e1c33SEmil Tsalapatis  *
19*8c1e1c33SEmil Tsalapatis  * This is copied verbatim from kernel's include/linux/compiler_types.h, but
20*8c1e1c33SEmil Tsalapatis  * with default expression (for pointers) changed from (x) to (typeof(x)0).
21*8c1e1c33SEmil Tsalapatis  *
22*8c1e1c33SEmil Tsalapatis  * This is because LLVM has a bug where for lvalue (x), it does not get rid of
23*8c1e1c33SEmil Tsalapatis  * an extra address_space qualifier, but does in case of rvalue (typeof(x)0).
24*8c1e1c33SEmil Tsalapatis  * Hence, for pointers, we need to create an rvalue expression to get the
25*8c1e1c33SEmil Tsalapatis  * desired type. See https://github.com/llvm/llvm-project/issues/53400.
26*8c1e1c33SEmil Tsalapatis  */
27*8c1e1c33SEmil Tsalapatis #define __scalar_type_to_expr_cases(type) \
28*8c1e1c33SEmil Tsalapatis 	unsigned type : (unsigned type)0, signed type : (signed type)0
29*8c1e1c33SEmil Tsalapatis 
30*8c1e1c33SEmil Tsalapatis #define __unqual_typeof(x)                              \
31*8c1e1c33SEmil Tsalapatis 	typeof(_Generic((x),                            \
32*8c1e1c33SEmil Tsalapatis 		char: (char)0,                          \
33*8c1e1c33SEmil Tsalapatis 		__scalar_type_to_expr_cases(char),      \
34*8c1e1c33SEmil Tsalapatis 		__scalar_type_to_expr_cases(short),     \
35*8c1e1c33SEmil Tsalapatis 		__scalar_type_to_expr_cases(int),       \
36*8c1e1c33SEmil Tsalapatis 		__scalar_type_to_expr_cases(long),      \
37*8c1e1c33SEmil Tsalapatis 		__scalar_type_to_expr_cases(long long), \
38*8c1e1c33SEmil Tsalapatis 		default: (typeof(x))0))
39*8c1e1c33SEmil Tsalapatis 
40*8c1e1c33SEmil Tsalapatis /* No-op for BPF */
41*8c1e1c33SEmil Tsalapatis #define cpu_relax() ({})
42*8c1e1c33SEmil Tsalapatis 
43*8c1e1c33SEmil Tsalapatis #define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
44*8c1e1c33SEmil Tsalapatis 
45*8c1e1c33SEmil Tsalapatis #ifndef WRITE_ONCE
46*8c1e1c33SEmil Tsalapatis #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = (val))
47*8c1e1c33SEmil Tsalapatis #endif
48*8c1e1c33SEmil Tsalapatis 
49*8c1e1c33SEmil Tsalapatis #define cmpxchg(p, old, new) __sync_val_compare_and_swap((p), old, new)
50*8c1e1c33SEmil Tsalapatis 
51*8c1e1c33SEmil Tsalapatis #define try_cmpxchg(p, pold, new)                                 \
52*8c1e1c33SEmil Tsalapatis 	({                                                        \
53*8c1e1c33SEmil Tsalapatis 		__unqual_typeof(*(pold)) __o = *(pold);           \
54*8c1e1c33SEmil Tsalapatis 		__unqual_typeof(*(p)) __r = cmpxchg(p, __o, new); \
55*8c1e1c33SEmil Tsalapatis 		if (__r != __o)                                   \
56*8c1e1c33SEmil Tsalapatis 			*(pold) = __r;                            \
57*8c1e1c33SEmil Tsalapatis 		__r == __o;                                       \
58*8c1e1c33SEmil Tsalapatis 	})
59*8c1e1c33SEmil Tsalapatis 
60*8c1e1c33SEmil Tsalapatis #define try_cmpxchg_relaxed(p, pold, new) try_cmpxchg(p, pold, new)
61*8c1e1c33SEmil Tsalapatis 
62*8c1e1c33SEmil Tsalapatis #define try_cmpxchg_acquire(p, pold, new) try_cmpxchg(p, pold, new)
63*8c1e1c33SEmil Tsalapatis 
64*8c1e1c33SEmil Tsalapatis #define smp_mb()                                 \
65*8c1e1c33SEmil Tsalapatis 	({                                       \
66*8c1e1c33SEmil Tsalapatis 		volatile unsigned long __val;    \
67*8c1e1c33SEmil Tsalapatis 		__sync_fetch_and_add(&__val, 0); \
68*8c1e1c33SEmil Tsalapatis 	})
69*8c1e1c33SEmil Tsalapatis 
70*8c1e1c33SEmil Tsalapatis #define smp_rmb()                   \
71*8c1e1c33SEmil Tsalapatis 	({                          \
72*8c1e1c33SEmil Tsalapatis 		if (!CONFIG_X86_64) \
73*8c1e1c33SEmil Tsalapatis 			smp_mb();   \
74*8c1e1c33SEmil Tsalapatis 		else                \
75*8c1e1c33SEmil Tsalapatis 			barrier();  \
76*8c1e1c33SEmil Tsalapatis 	})
77*8c1e1c33SEmil Tsalapatis 
78*8c1e1c33SEmil Tsalapatis #define smp_wmb()                   \
79*8c1e1c33SEmil Tsalapatis 	({                          \
80*8c1e1c33SEmil Tsalapatis 		if (!CONFIG_X86_64) \
81*8c1e1c33SEmil Tsalapatis 			smp_mb();   \
82*8c1e1c33SEmil Tsalapatis 		else                \
83*8c1e1c33SEmil Tsalapatis 			barrier();  \
84*8c1e1c33SEmil Tsalapatis 	})
85*8c1e1c33SEmil Tsalapatis 
86*8c1e1c33SEmil Tsalapatis /* Control dependency provides LOAD->STORE, provide LOAD->LOAD */
87*8c1e1c33SEmil Tsalapatis #define smp_acquire__after_ctrl_dep() ({ smp_rmb(); })
88*8c1e1c33SEmil Tsalapatis 
89*8c1e1c33SEmil Tsalapatis #define smp_load_acquire(p)                                  \
90*8c1e1c33SEmil Tsalapatis 	({                                                   \
91*8c1e1c33SEmil Tsalapatis 		__unqual_typeof(*(p)) __v = READ_ONCE(*(p)); \
92*8c1e1c33SEmil Tsalapatis 		if (!CONFIG_X86_64)                          \
93*8c1e1c33SEmil Tsalapatis 			smp_mb();                            \
94*8c1e1c33SEmil Tsalapatis 		barrier();                                   \
95*8c1e1c33SEmil Tsalapatis 		__v;                                         \
96*8c1e1c33SEmil Tsalapatis 	})
97*8c1e1c33SEmil Tsalapatis 
98*8c1e1c33SEmil Tsalapatis #define smp_store_release(p, val)      \
99*8c1e1c33SEmil Tsalapatis 	({                             \
100*8c1e1c33SEmil Tsalapatis 		if (!CONFIG_X86_64)    \
101*8c1e1c33SEmil Tsalapatis 			smp_mb();      \
102*8c1e1c33SEmil Tsalapatis 		barrier();             \
103*8c1e1c33SEmil Tsalapatis 		WRITE_ONCE(*(p), val); \
104*8c1e1c33SEmil Tsalapatis 	})
105*8c1e1c33SEmil Tsalapatis 
106*8c1e1c33SEmil Tsalapatis #define smp_cond_load_relaxed_label(p, cond_expr, label)                \
107*8c1e1c33SEmil Tsalapatis 	({                                                              \
108*8c1e1c33SEmil Tsalapatis 		typeof(p) __ptr = (p);                                  \
109*8c1e1c33SEmil Tsalapatis 		__unqual_typeof(*(p)) VAL;                              \
110*8c1e1c33SEmil Tsalapatis 		for (;;) {                                              \
111*8c1e1c33SEmil Tsalapatis 			VAL = (__unqual_typeof(*(p)))READ_ONCE(*__ptr); \
112*8c1e1c33SEmil Tsalapatis 			if (cond_expr)                                  \
113*8c1e1c33SEmil Tsalapatis 				break;                                  \
114*8c1e1c33SEmil Tsalapatis 			cond_break_label(label);                        \
115*8c1e1c33SEmil Tsalapatis 			cpu_relax();                                    \
116*8c1e1c33SEmil Tsalapatis 		}                                                       \
117*8c1e1c33SEmil Tsalapatis 		(typeof(*(p)))VAL;                                      \
118*8c1e1c33SEmil Tsalapatis 	})
119*8c1e1c33SEmil Tsalapatis 
120*8c1e1c33SEmil Tsalapatis #define smp_cond_load_acquire_label(p, cond_expr, label)                  \
121*8c1e1c33SEmil Tsalapatis 	({                                                                \
122*8c1e1c33SEmil Tsalapatis 		__unqual_typeof(*p) __val =                               \
123*8c1e1c33SEmil Tsalapatis 			smp_cond_load_relaxed_label(p, cond_expr, label); \
124*8c1e1c33SEmil Tsalapatis 		smp_acquire__after_ctrl_dep();                            \
125*8c1e1c33SEmil Tsalapatis 		(typeof(*(p)))__val;                                      \
126*8c1e1c33SEmil Tsalapatis 	})
127*8c1e1c33SEmil Tsalapatis 
128*8c1e1c33SEmil Tsalapatis #define atomic_read(p) READ_ONCE((p)->counter)
129*8c1e1c33SEmil Tsalapatis 
130*8c1e1c33SEmil Tsalapatis #define atomic_cond_read_relaxed_label(p, cond_expr, label) \
131*8c1e1c33SEmil Tsalapatis 	smp_cond_load_relaxed_label(&(p)->counter, cond_expr, label)
132*8c1e1c33SEmil Tsalapatis 
133*8c1e1c33SEmil Tsalapatis #define atomic_cond_read_acquire_label(p, cond_expr, label) \
134*8c1e1c33SEmil Tsalapatis 	smp_cond_load_acquire_label(&(p)->counter, cond_expr, label)
135*8c1e1c33SEmil Tsalapatis 
136*8c1e1c33SEmil Tsalapatis #define atomic_try_cmpxchg_relaxed(p, pold, new) \
137*8c1e1c33SEmil Tsalapatis 	try_cmpxchg_relaxed(&(p)->counter, pold, new)
138*8c1e1c33SEmil Tsalapatis 
139*8c1e1c33SEmil Tsalapatis #define atomic_try_cmpxchg_acquire(p, pold, new) \
140*8c1e1c33SEmil Tsalapatis 	try_cmpxchg_acquire(&(p)->counter, pold, new)
141*8c1e1c33SEmil Tsalapatis 
142*8c1e1c33SEmil Tsalapatis #endif /* BPF_ATOMIC_H */
143