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