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