199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson #ifndef _RTE_ATOMIC_H_ 699a2dd95SBruce Richardson #define _RTE_ATOMIC_H_ 799a2dd95SBruce Richardson 899a2dd95SBruce Richardson /** 999a2dd95SBruce Richardson * @file 1099a2dd95SBruce Richardson * Atomic Operations 1199a2dd95SBruce Richardson * 1299a2dd95SBruce Richardson * This file defines a generic API for atomic operations. 1399a2dd95SBruce Richardson */ 1499a2dd95SBruce Richardson 1599a2dd95SBruce Richardson #include <stdint.h> 161ec6a845STyler Retzlaff 1799a2dd95SBruce Richardson #include <rte_common.h> 181ec6a845STyler Retzlaff #include <rte_stdatomic.h> 1999a2dd95SBruce Richardson 20*719834a6SMattias Rönnblom #ifdef __cplusplus 21*719834a6SMattias Rönnblom extern "C" { 22*719834a6SMattias Rönnblom #endif 23*719834a6SMattias Rönnblom 2499a2dd95SBruce Richardson #ifdef __DOXYGEN__ 2599a2dd95SBruce Richardson 2699a2dd95SBruce Richardson /** @name Memory Barrier 2799a2dd95SBruce Richardson */ 2899a2dd95SBruce Richardson ///@{ 2999a2dd95SBruce Richardson /** 3099a2dd95SBruce Richardson * General memory barrier. 3199a2dd95SBruce Richardson * 3299a2dd95SBruce Richardson * Guarantees that the LOAD and STORE operations generated before the 3399a2dd95SBruce Richardson * barrier occur before the LOAD and STORE operations generated after. 3499a2dd95SBruce Richardson */ 3599a2dd95SBruce Richardson static inline void rte_mb(void); 3699a2dd95SBruce Richardson 3799a2dd95SBruce Richardson /** 3899a2dd95SBruce Richardson * Write memory barrier. 3999a2dd95SBruce Richardson * 4099a2dd95SBruce Richardson * Guarantees that the STORE operations generated before the barrier 4199a2dd95SBruce Richardson * occur before the STORE operations generated after. 4299a2dd95SBruce Richardson */ 4399a2dd95SBruce Richardson static inline void rte_wmb(void); 4499a2dd95SBruce Richardson 4599a2dd95SBruce Richardson /** 4699a2dd95SBruce Richardson * Read memory barrier. 4799a2dd95SBruce Richardson * 4899a2dd95SBruce Richardson * Guarantees that the LOAD operations generated before the barrier 4999a2dd95SBruce Richardson * occur before the LOAD operations generated after. 5099a2dd95SBruce Richardson */ 5199a2dd95SBruce Richardson static inline void rte_rmb(void); 5299a2dd95SBruce Richardson ///@} 5399a2dd95SBruce Richardson 5499a2dd95SBruce Richardson /** @name SMP Memory Barrier 5599a2dd95SBruce Richardson */ 5699a2dd95SBruce Richardson ///@{ 5799a2dd95SBruce Richardson /** 5899a2dd95SBruce Richardson * General memory barrier between lcores 5999a2dd95SBruce Richardson * 6099a2dd95SBruce Richardson * Guarantees that the LOAD and STORE operations that precede the 6199a2dd95SBruce Richardson * rte_smp_mb() call are globally visible across the lcores 6299a2dd95SBruce Richardson * before the LOAD and STORE operations that follows it. 63e7511996SRuifeng Wang * 64e7511996SRuifeng Wang * @note 65e7511996SRuifeng Wang * This function is deprecated. 66e7511996SRuifeng Wang * It provides similar synchronization primitive as atomic fence, 67e7511996SRuifeng Wang * but has different syntax and memory ordering semantic. Hence 68e7511996SRuifeng Wang * deprecated for the simplicity of memory ordering semantics in use. 69e7511996SRuifeng Wang * 701ec6a845STyler Retzlaff * rte_atomic_thread_fence(rte_memory_order_acq_rel) should be used instead. 7199a2dd95SBruce Richardson */ 7299a2dd95SBruce Richardson static inline void rte_smp_mb(void); 7399a2dd95SBruce Richardson 7499a2dd95SBruce Richardson /** 7599a2dd95SBruce Richardson * Write memory barrier between lcores 7699a2dd95SBruce Richardson * 7799a2dd95SBruce Richardson * Guarantees that the STORE operations that precede the 7899a2dd95SBruce Richardson * rte_smp_wmb() call are globally visible across the lcores 7999a2dd95SBruce Richardson * before the STORE operations that follows it. 80e7511996SRuifeng Wang * 81e7511996SRuifeng Wang * @note 82e7511996SRuifeng Wang * This function is deprecated. 83e7511996SRuifeng Wang * It provides similar synchronization primitive as atomic fence, 84e7511996SRuifeng Wang * but has different syntax and memory ordering semantic. Hence 85e7511996SRuifeng Wang * deprecated for the simplicity of memory ordering semantics in use. 86e7511996SRuifeng Wang * 871ec6a845STyler Retzlaff * rte_atomic_thread_fence(rte_memory_order_release) should be used instead. 88e7511996SRuifeng Wang * The fence also guarantees LOAD operations that precede the call 89e7511996SRuifeng Wang * are globally visible across the lcores before the STORE operations 90e7511996SRuifeng Wang * that follows it. 9199a2dd95SBruce Richardson */ 9299a2dd95SBruce Richardson static inline void rte_smp_wmb(void); 9399a2dd95SBruce Richardson 9499a2dd95SBruce Richardson /** 9599a2dd95SBruce Richardson * Read memory barrier between lcores 9699a2dd95SBruce Richardson * 9799a2dd95SBruce Richardson * Guarantees that the LOAD operations that precede the 9899a2dd95SBruce Richardson * rte_smp_rmb() call are globally visible across the lcores 9999a2dd95SBruce Richardson * before the LOAD operations that follows it. 100e7511996SRuifeng Wang * 101e7511996SRuifeng Wang * @note 102e7511996SRuifeng Wang * This function is deprecated. 103e7511996SRuifeng Wang * It provides similar synchronization primitive as atomic fence, 104e7511996SRuifeng Wang * but has different syntax and memory ordering semantic. Hence 105e7511996SRuifeng Wang * deprecated for the simplicity of memory ordering semantics in use. 106e7511996SRuifeng Wang * 1071ec6a845STyler Retzlaff * rte_atomic_thread_fence(rte_memory_order_acquire) should be used instead. 108e7511996SRuifeng Wang * The fence also guarantees LOAD operations that precede the call 109e7511996SRuifeng Wang * are globally visible across the lcores before the STORE operations 110e7511996SRuifeng Wang * that follows it. 11199a2dd95SBruce Richardson */ 11299a2dd95SBruce Richardson static inline void rte_smp_rmb(void); 11399a2dd95SBruce Richardson ///@} 11499a2dd95SBruce Richardson 11599a2dd95SBruce Richardson /** @name I/O Memory Barrier 11699a2dd95SBruce Richardson */ 11799a2dd95SBruce Richardson ///@{ 11899a2dd95SBruce Richardson /** 11999a2dd95SBruce Richardson * General memory barrier for I/O device 12099a2dd95SBruce Richardson * 12199a2dd95SBruce Richardson * Guarantees that the LOAD and STORE operations that precede the 12299a2dd95SBruce Richardson * rte_io_mb() call are visible to I/O device or CPU before the 12399a2dd95SBruce Richardson * LOAD and STORE operations that follow it. 12499a2dd95SBruce Richardson */ 12599a2dd95SBruce Richardson static inline void rte_io_mb(void); 12699a2dd95SBruce Richardson 12799a2dd95SBruce Richardson /** 12899a2dd95SBruce Richardson * Write memory barrier for I/O device 12999a2dd95SBruce Richardson * 13099a2dd95SBruce Richardson * Guarantees that the STORE operations that precede the 13199a2dd95SBruce Richardson * rte_io_wmb() call are visible to I/O device before the STORE 13299a2dd95SBruce Richardson * operations that follow it. 13399a2dd95SBruce Richardson */ 13499a2dd95SBruce Richardson static inline void rte_io_wmb(void); 13599a2dd95SBruce Richardson 13699a2dd95SBruce Richardson /** 13799a2dd95SBruce Richardson * Read memory barrier for IO device 13899a2dd95SBruce Richardson * 13999a2dd95SBruce Richardson * Guarantees that the LOAD operations on I/O device that precede the 14099a2dd95SBruce Richardson * rte_io_rmb() call are visible to CPU before the LOAD 14199a2dd95SBruce Richardson * operations that follow it. 14299a2dd95SBruce Richardson */ 14399a2dd95SBruce Richardson static inline void rte_io_rmb(void); 14499a2dd95SBruce Richardson ///@} 14599a2dd95SBruce Richardson 14699a2dd95SBruce Richardson #endif /* __DOXYGEN__ */ 14799a2dd95SBruce Richardson 14899a2dd95SBruce Richardson /** 14999a2dd95SBruce Richardson * Compiler barrier. 15099a2dd95SBruce Richardson * 15199a2dd95SBruce Richardson * Guarantees that operation reordering does not occur at compile time 15299a2dd95SBruce Richardson * for operations directly before and after the barrier. 15399a2dd95SBruce Richardson */ 1542dbaa926STyler Retzlaff #ifdef RTE_TOOLCHAIN_MSVC 1552dbaa926STyler Retzlaff #define rte_compiler_barrier() _ReadWriteBarrier() 1562dbaa926STyler Retzlaff #else 15799a2dd95SBruce Richardson #define rte_compiler_barrier() do { \ 15899a2dd95SBruce Richardson asm volatile ("" : : : "memory"); \ 15999a2dd95SBruce Richardson } while(0) 1602dbaa926STyler Retzlaff #endif 16199a2dd95SBruce Richardson 16299a2dd95SBruce Richardson /** 16399a2dd95SBruce Richardson * Synchronization fence between threads based on the specified memory order. 16499a2dd95SBruce Richardson */ 1651ec6a845STyler Retzlaff static inline void rte_atomic_thread_fence(rte_memory_order memorder); 16699a2dd95SBruce Richardson 16799a2dd95SBruce Richardson /*------------------------- 16 bit atomic operations -------------------------*/ 16899a2dd95SBruce Richardson 16927da6a12STyler Retzlaff #ifndef RTE_TOOLCHAIN_MSVC 17027da6a12STyler Retzlaff 17199a2dd95SBruce Richardson /** 17299a2dd95SBruce Richardson * Atomic compare and set. 17399a2dd95SBruce Richardson * 17499a2dd95SBruce Richardson * (atomic) equivalent to: 17599a2dd95SBruce Richardson * if (*dst == exp) 17699a2dd95SBruce Richardson * *dst = src (all 16-bit words) 17799a2dd95SBruce Richardson * 17899a2dd95SBruce Richardson * @param dst 17999a2dd95SBruce Richardson * The destination location into which the value will be written. 18099a2dd95SBruce Richardson * @param exp 18199a2dd95SBruce Richardson * The expected value. 18299a2dd95SBruce Richardson * @param src 18399a2dd95SBruce Richardson * The new value. 18499a2dd95SBruce Richardson * @return 18599a2dd95SBruce Richardson * Non-zero on success; 0 on failure. 18699a2dd95SBruce Richardson */ 18799a2dd95SBruce Richardson static inline int 18899a2dd95SBruce Richardson rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src); 18999a2dd95SBruce Richardson 19099a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 19199a2dd95SBruce Richardson static inline int 19299a2dd95SBruce Richardson rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src) 19399a2dd95SBruce Richardson { 19499a2dd95SBruce Richardson return __sync_bool_compare_and_swap(dst, exp, src); 19599a2dd95SBruce Richardson } 19699a2dd95SBruce Richardson #endif 19799a2dd95SBruce Richardson 19899a2dd95SBruce Richardson /** 19999a2dd95SBruce Richardson * Atomic exchange. 20099a2dd95SBruce Richardson * 20199a2dd95SBruce Richardson * (atomic) equivalent to: 20299a2dd95SBruce Richardson * ret = *dst 20399a2dd95SBruce Richardson * *dst = val; 20499a2dd95SBruce Richardson * return ret; 20599a2dd95SBruce Richardson * 20699a2dd95SBruce Richardson * @param dst 20799a2dd95SBruce Richardson * The destination location into which the value will be written. 20899a2dd95SBruce Richardson * @param val 20999a2dd95SBruce Richardson * The new value. 21099a2dd95SBruce Richardson * @return 21199a2dd95SBruce Richardson * The original value at that location 21299a2dd95SBruce Richardson */ 21399a2dd95SBruce Richardson static inline uint16_t 21499a2dd95SBruce Richardson rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val); 21599a2dd95SBruce Richardson 21699a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 21799a2dd95SBruce Richardson static inline uint16_t 21899a2dd95SBruce Richardson rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val) 21999a2dd95SBruce Richardson { 2201ec6a845STyler Retzlaff return rte_atomic_exchange_explicit(dst, val, rte_memory_order_seq_cst); 22199a2dd95SBruce Richardson } 22299a2dd95SBruce Richardson #endif 22399a2dd95SBruce Richardson 22499a2dd95SBruce Richardson /** 22599a2dd95SBruce Richardson * The atomic counter structure. 22699a2dd95SBruce Richardson */ 22799a2dd95SBruce Richardson typedef struct { 22899a2dd95SBruce Richardson volatile int16_t cnt; /**< An internal counter value. */ 22999a2dd95SBruce Richardson } rte_atomic16_t; 23099a2dd95SBruce Richardson 23199a2dd95SBruce Richardson /** 23299a2dd95SBruce Richardson * Static initializer for an atomic counter. 23399a2dd95SBruce Richardson */ 23499a2dd95SBruce Richardson #define RTE_ATOMIC16_INIT(val) { (val) } 23599a2dd95SBruce Richardson 23699a2dd95SBruce Richardson /** 23799a2dd95SBruce Richardson * Initialize an atomic counter. 23899a2dd95SBruce Richardson * 23999a2dd95SBruce Richardson * @param v 24099a2dd95SBruce Richardson * A pointer to the atomic counter. 24199a2dd95SBruce Richardson */ 24299a2dd95SBruce Richardson static inline void 24399a2dd95SBruce Richardson rte_atomic16_init(rte_atomic16_t *v) 24499a2dd95SBruce Richardson { 24599a2dd95SBruce Richardson v->cnt = 0; 24699a2dd95SBruce Richardson } 24799a2dd95SBruce Richardson 24899a2dd95SBruce Richardson /** 24999a2dd95SBruce Richardson * Atomically read a 16-bit value from a counter. 25099a2dd95SBruce Richardson * 25199a2dd95SBruce Richardson * @param v 25299a2dd95SBruce Richardson * A pointer to the atomic counter. 25399a2dd95SBruce Richardson * @return 25499a2dd95SBruce Richardson * The value of the counter. 25599a2dd95SBruce Richardson */ 25699a2dd95SBruce Richardson static inline int16_t 25799a2dd95SBruce Richardson rte_atomic16_read(const rte_atomic16_t *v) 25899a2dd95SBruce Richardson { 25999a2dd95SBruce Richardson return v->cnt; 26099a2dd95SBruce Richardson } 26199a2dd95SBruce Richardson 26299a2dd95SBruce Richardson /** 26399a2dd95SBruce Richardson * Atomically set a counter to a 16-bit value. 26499a2dd95SBruce Richardson * 26599a2dd95SBruce Richardson * @param v 26699a2dd95SBruce Richardson * A pointer to the atomic counter. 26799a2dd95SBruce Richardson * @param new_value 26899a2dd95SBruce Richardson * The new value for the counter. 26999a2dd95SBruce Richardson */ 27099a2dd95SBruce Richardson static inline void 27199a2dd95SBruce Richardson rte_atomic16_set(rte_atomic16_t *v, int16_t new_value) 27299a2dd95SBruce Richardson { 27399a2dd95SBruce Richardson v->cnt = new_value; 27499a2dd95SBruce Richardson } 27599a2dd95SBruce Richardson 27699a2dd95SBruce Richardson /** 27799a2dd95SBruce Richardson * Atomically add a 16-bit value to an atomic counter. 27899a2dd95SBruce Richardson * 27999a2dd95SBruce Richardson * @param v 28099a2dd95SBruce Richardson * A pointer to the atomic counter. 28199a2dd95SBruce Richardson * @param inc 28299a2dd95SBruce Richardson * The value to be added to the counter. 28399a2dd95SBruce Richardson */ 28499a2dd95SBruce Richardson static inline void 28599a2dd95SBruce Richardson rte_atomic16_add(rte_atomic16_t *v, int16_t inc) 28699a2dd95SBruce Richardson { 2879290f8beSTyler Retzlaff rte_atomic_fetch_add_explicit((volatile __rte_atomic int16_t *)&v->cnt, inc, 2889290f8beSTyler Retzlaff rte_memory_order_seq_cst); 28999a2dd95SBruce Richardson } 29099a2dd95SBruce Richardson 29199a2dd95SBruce Richardson /** 29299a2dd95SBruce Richardson * Atomically subtract a 16-bit value from an atomic counter. 29399a2dd95SBruce Richardson * 29499a2dd95SBruce Richardson * @param v 29599a2dd95SBruce Richardson * A pointer to the atomic counter. 29699a2dd95SBruce Richardson * @param dec 29799a2dd95SBruce Richardson * The value to be subtracted from the counter. 29899a2dd95SBruce Richardson */ 29999a2dd95SBruce Richardson static inline void 30099a2dd95SBruce Richardson rte_atomic16_sub(rte_atomic16_t *v, int16_t dec) 30199a2dd95SBruce Richardson { 3029290f8beSTyler Retzlaff rte_atomic_fetch_sub_explicit((volatile __rte_atomic int16_t *)&v->cnt, dec, 3039290f8beSTyler Retzlaff rte_memory_order_seq_cst); 30499a2dd95SBruce Richardson } 30599a2dd95SBruce Richardson 30699a2dd95SBruce Richardson /** 30799a2dd95SBruce Richardson * Atomically increment a counter by one. 30899a2dd95SBruce Richardson * 30999a2dd95SBruce Richardson * @param v 31099a2dd95SBruce Richardson * A pointer to the atomic counter. 31199a2dd95SBruce Richardson */ 31299a2dd95SBruce Richardson static inline void 31399a2dd95SBruce Richardson rte_atomic16_inc(rte_atomic16_t *v); 31499a2dd95SBruce Richardson 31599a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 31699a2dd95SBruce Richardson static inline void 31799a2dd95SBruce Richardson rte_atomic16_inc(rte_atomic16_t *v) 31899a2dd95SBruce Richardson { 31999a2dd95SBruce Richardson rte_atomic16_add(v, 1); 32099a2dd95SBruce Richardson } 32199a2dd95SBruce Richardson #endif 32299a2dd95SBruce Richardson 32399a2dd95SBruce Richardson /** 32499a2dd95SBruce Richardson * Atomically decrement a counter by one. 32599a2dd95SBruce Richardson * 32699a2dd95SBruce Richardson * @param v 32799a2dd95SBruce Richardson * A pointer to the atomic counter. 32899a2dd95SBruce Richardson */ 32999a2dd95SBruce Richardson static inline void 33099a2dd95SBruce Richardson rte_atomic16_dec(rte_atomic16_t *v); 33199a2dd95SBruce Richardson 33299a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 33399a2dd95SBruce Richardson static inline void 33499a2dd95SBruce Richardson rte_atomic16_dec(rte_atomic16_t *v) 33599a2dd95SBruce Richardson { 33699a2dd95SBruce Richardson rte_atomic16_sub(v, 1); 33799a2dd95SBruce Richardson } 33899a2dd95SBruce Richardson #endif 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson /** 34199a2dd95SBruce Richardson * Atomically add a 16-bit value to a counter and return the result. 34299a2dd95SBruce Richardson * 34399a2dd95SBruce Richardson * Atomically adds the 16-bits value (inc) to the atomic counter (v) and 34499a2dd95SBruce Richardson * returns the value of v after addition. 34599a2dd95SBruce Richardson * 34699a2dd95SBruce Richardson * @param v 34799a2dd95SBruce Richardson * A pointer to the atomic counter. 34899a2dd95SBruce Richardson * @param inc 34999a2dd95SBruce Richardson * The value to be added to the counter. 35099a2dd95SBruce Richardson * @return 35199a2dd95SBruce Richardson * The value of v after the addition. 35299a2dd95SBruce Richardson */ 35399a2dd95SBruce Richardson static inline int16_t 35499a2dd95SBruce Richardson rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc) 35599a2dd95SBruce Richardson { 3569290f8beSTyler Retzlaff return rte_atomic_fetch_add_explicit((volatile __rte_atomic int16_t *)&v->cnt, inc, 3579290f8beSTyler Retzlaff rte_memory_order_seq_cst) + inc; 35899a2dd95SBruce Richardson } 35999a2dd95SBruce Richardson 36099a2dd95SBruce Richardson /** 36199a2dd95SBruce Richardson * Atomically subtract a 16-bit value from a counter and return 36299a2dd95SBruce Richardson * the result. 36399a2dd95SBruce Richardson * 36499a2dd95SBruce Richardson * Atomically subtracts the 16-bit value (inc) from the atomic counter 36599a2dd95SBruce Richardson * (v) and returns the value of v after the subtraction. 36699a2dd95SBruce Richardson * 36799a2dd95SBruce Richardson * @param v 36899a2dd95SBruce Richardson * A pointer to the atomic counter. 36999a2dd95SBruce Richardson * @param dec 37099a2dd95SBruce Richardson * The value to be subtracted from the counter. 37199a2dd95SBruce Richardson * @return 37299a2dd95SBruce Richardson * The value of v after the subtraction. 37399a2dd95SBruce Richardson */ 37499a2dd95SBruce Richardson static inline int16_t 37599a2dd95SBruce Richardson rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec) 37699a2dd95SBruce Richardson { 3779290f8beSTyler Retzlaff return rte_atomic_fetch_sub_explicit((volatile __rte_atomic int16_t *)&v->cnt, dec, 3789290f8beSTyler Retzlaff rte_memory_order_seq_cst) - dec; 37999a2dd95SBruce Richardson } 38099a2dd95SBruce Richardson 38199a2dd95SBruce Richardson /** 38299a2dd95SBruce Richardson * Atomically increment a 16-bit counter by one and test. 38399a2dd95SBruce Richardson * 38499a2dd95SBruce Richardson * Atomically increments the atomic counter (v) by one and returns true if 38599a2dd95SBruce Richardson * the result is 0, or false in all other cases. 38699a2dd95SBruce Richardson * 38799a2dd95SBruce Richardson * @param v 38899a2dd95SBruce Richardson * A pointer to the atomic counter. 38999a2dd95SBruce Richardson * @return 39099a2dd95SBruce Richardson * True if the result after the increment operation is 0; false otherwise. 39199a2dd95SBruce Richardson */ 39299a2dd95SBruce Richardson static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v); 39399a2dd95SBruce Richardson 39499a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 39599a2dd95SBruce Richardson static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v) 39699a2dd95SBruce Richardson { 3979290f8beSTyler Retzlaff return rte_atomic_fetch_add_explicit((volatile __rte_atomic int16_t *)&v->cnt, 1, 3989290f8beSTyler Retzlaff rte_memory_order_seq_cst) + 1 == 0; 39999a2dd95SBruce Richardson } 40099a2dd95SBruce Richardson #endif 40199a2dd95SBruce Richardson 40299a2dd95SBruce Richardson /** 40399a2dd95SBruce Richardson * Atomically decrement a 16-bit counter by one and test. 40499a2dd95SBruce Richardson * 40599a2dd95SBruce Richardson * Atomically decrements the atomic counter (v) by one and returns true if 40699a2dd95SBruce Richardson * the result is 0, or false in all other cases. 40799a2dd95SBruce Richardson * 40899a2dd95SBruce Richardson * @param v 40999a2dd95SBruce Richardson * A pointer to the atomic counter. 41099a2dd95SBruce Richardson * @return 41199a2dd95SBruce Richardson * True if the result after the decrement operation is 0; false otherwise. 41299a2dd95SBruce Richardson */ 41399a2dd95SBruce Richardson static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v); 41499a2dd95SBruce Richardson 41599a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 41699a2dd95SBruce Richardson static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v) 41799a2dd95SBruce Richardson { 4189290f8beSTyler Retzlaff return rte_atomic_fetch_sub_explicit((volatile __rte_atomic int16_t *)&v->cnt, 1, 4199290f8beSTyler Retzlaff rte_memory_order_seq_cst) - 1 == 0; 42099a2dd95SBruce Richardson } 42199a2dd95SBruce Richardson #endif 42299a2dd95SBruce Richardson 42399a2dd95SBruce Richardson /** 42499a2dd95SBruce Richardson * Atomically test and set a 16-bit atomic counter. 42599a2dd95SBruce Richardson * 42699a2dd95SBruce Richardson * If the counter value is already set, return 0 (failed). Otherwise, set 42799a2dd95SBruce Richardson * the counter value to 1 and return 1 (success). 42899a2dd95SBruce Richardson * 42999a2dd95SBruce Richardson * @param v 43099a2dd95SBruce Richardson * A pointer to the atomic counter. 43199a2dd95SBruce Richardson * @return 43299a2dd95SBruce Richardson * 0 if failed; else 1, success. 43399a2dd95SBruce Richardson */ 43499a2dd95SBruce Richardson static inline int rte_atomic16_test_and_set(rte_atomic16_t *v); 43599a2dd95SBruce Richardson 43699a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 43799a2dd95SBruce Richardson static inline int rte_atomic16_test_and_set(rte_atomic16_t *v) 43899a2dd95SBruce Richardson { 43999a2dd95SBruce Richardson return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1); 44099a2dd95SBruce Richardson } 44199a2dd95SBruce Richardson #endif 44299a2dd95SBruce Richardson 44399a2dd95SBruce Richardson /** 44499a2dd95SBruce Richardson * Atomically set a 16-bit counter to 0. 44599a2dd95SBruce Richardson * 44699a2dd95SBruce Richardson * @param v 44799a2dd95SBruce Richardson * A pointer to the atomic counter. 44899a2dd95SBruce Richardson */ 44999a2dd95SBruce Richardson static inline void rte_atomic16_clear(rte_atomic16_t *v) 45099a2dd95SBruce Richardson { 45199a2dd95SBruce Richardson v->cnt = 0; 45299a2dd95SBruce Richardson } 45399a2dd95SBruce Richardson 45499a2dd95SBruce Richardson /*------------------------- 32 bit atomic operations -------------------------*/ 45599a2dd95SBruce Richardson 45699a2dd95SBruce Richardson /** 45799a2dd95SBruce Richardson * Atomic compare and set. 45899a2dd95SBruce Richardson * 45999a2dd95SBruce Richardson * (atomic) equivalent to: 46099a2dd95SBruce Richardson * if (*dst == exp) 46199a2dd95SBruce Richardson * *dst = src (all 32-bit words) 46299a2dd95SBruce Richardson * 46399a2dd95SBruce Richardson * @param dst 46499a2dd95SBruce Richardson * The destination location into which the value will be written. 46599a2dd95SBruce Richardson * @param exp 46699a2dd95SBruce Richardson * The expected value. 46799a2dd95SBruce Richardson * @param src 46899a2dd95SBruce Richardson * The new value. 46999a2dd95SBruce Richardson * @return 47099a2dd95SBruce Richardson * Non-zero on success; 0 on failure. 47199a2dd95SBruce Richardson */ 47299a2dd95SBruce Richardson static inline int 47399a2dd95SBruce Richardson rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src); 47499a2dd95SBruce Richardson 47599a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 47699a2dd95SBruce Richardson static inline int 47799a2dd95SBruce Richardson rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src) 47899a2dd95SBruce Richardson { 47999a2dd95SBruce Richardson return __sync_bool_compare_and_swap(dst, exp, src); 48099a2dd95SBruce Richardson } 48199a2dd95SBruce Richardson #endif 48299a2dd95SBruce Richardson 48399a2dd95SBruce Richardson /** 48499a2dd95SBruce Richardson * Atomic exchange. 48599a2dd95SBruce Richardson * 48699a2dd95SBruce Richardson * (atomic) equivalent to: 48799a2dd95SBruce Richardson * ret = *dst 48899a2dd95SBruce Richardson * *dst = val; 48999a2dd95SBruce Richardson * return ret; 49099a2dd95SBruce Richardson * 49199a2dd95SBruce Richardson * @param dst 49299a2dd95SBruce Richardson * The destination location into which the value will be written. 49399a2dd95SBruce Richardson * @param val 49499a2dd95SBruce Richardson * The new value. 49599a2dd95SBruce Richardson * @return 49699a2dd95SBruce Richardson * The original value at that location 49799a2dd95SBruce Richardson */ 49899a2dd95SBruce Richardson static inline uint32_t 49999a2dd95SBruce Richardson rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val); 50099a2dd95SBruce Richardson 50199a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 50299a2dd95SBruce Richardson static inline uint32_t 50399a2dd95SBruce Richardson rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val) 50499a2dd95SBruce Richardson { 5051ec6a845STyler Retzlaff return rte_atomic_exchange_explicit(dst, val, rte_memory_order_seq_cst); 50699a2dd95SBruce Richardson } 50799a2dd95SBruce Richardson #endif 50899a2dd95SBruce Richardson 50999a2dd95SBruce Richardson /** 51099a2dd95SBruce Richardson * The atomic counter structure. 51199a2dd95SBruce Richardson */ 51299a2dd95SBruce Richardson typedef struct { 51399a2dd95SBruce Richardson volatile int32_t cnt; /**< An internal counter value. */ 51499a2dd95SBruce Richardson } rte_atomic32_t; 51599a2dd95SBruce Richardson 51699a2dd95SBruce Richardson /** 51799a2dd95SBruce Richardson * Static initializer for an atomic counter. 51899a2dd95SBruce Richardson */ 51999a2dd95SBruce Richardson #define RTE_ATOMIC32_INIT(val) { (val) } 52099a2dd95SBruce Richardson 52199a2dd95SBruce Richardson /** 52299a2dd95SBruce Richardson * Initialize an atomic counter. 52399a2dd95SBruce Richardson * 52499a2dd95SBruce Richardson * @param v 52599a2dd95SBruce Richardson * A pointer to the atomic counter. 52699a2dd95SBruce Richardson */ 52799a2dd95SBruce Richardson static inline void 52899a2dd95SBruce Richardson rte_atomic32_init(rte_atomic32_t *v) 52999a2dd95SBruce Richardson { 53099a2dd95SBruce Richardson v->cnt = 0; 53199a2dd95SBruce Richardson } 53299a2dd95SBruce Richardson 53399a2dd95SBruce Richardson /** 53499a2dd95SBruce Richardson * Atomically read a 32-bit value from a counter. 53599a2dd95SBruce Richardson * 53699a2dd95SBruce Richardson * @param v 53799a2dd95SBruce Richardson * A pointer to the atomic counter. 53899a2dd95SBruce Richardson * @return 53999a2dd95SBruce Richardson * The value of the counter. 54099a2dd95SBruce Richardson */ 54199a2dd95SBruce Richardson static inline int32_t 54299a2dd95SBruce Richardson rte_atomic32_read(const rte_atomic32_t *v) 54399a2dd95SBruce Richardson { 54499a2dd95SBruce Richardson return v->cnt; 54599a2dd95SBruce Richardson } 54699a2dd95SBruce Richardson 54799a2dd95SBruce Richardson /** 54899a2dd95SBruce Richardson * Atomically set a counter to a 32-bit value. 54999a2dd95SBruce Richardson * 55099a2dd95SBruce Richardson * @param v 55199a2dd95SBruce Richardson * A pointer to the atomic counter. 55299a2dd95SBruce Richardson * @param new_value 55399a2dd95SBruce Richardson * The new value for the counter. 55499a2dd95SBruce Richardson */ 55599a2dd95SBruce Richardson static inline void 55699a2dd95SBruce Richardson rte_atomic32_set(rte_atomic32_t *v, int32_t new_value) 55799a2dd95SBruce Richardson { 55899a2dd95SBruce Richardson v->cnt = new_value; 55999a2dd95SBruce Richardson } 56099a2dd95SBruce Richardson 56199a2dd95SBruce Richardson /** 56299a2dd95SBruce Richardson * Atomically add a 32-bit value to an atomic counter. 56399a2dd95SBruce Richardson * 56499a2dd95SBruce Richardson * @param v 56599a2dd95SBruce Richardson * A pointer to the atomic counter. 56699a2dd95SBruce Richardson * @param inc 56799a2dd95SBruce Richardson * The value to be added to the counter. 56899a2dd95SBruce Richardson */ 56999a2dd95SBruce Richardson static inline void 57099a2dd95SBruce Richardson rte_atomic32_add(rte_atomic32_t *v, int32_t inc) 57199a2dd95SBruce Richardson { 5729290f8beSTyler Retzlaff rte_atomic_fetch_add_explicit((volatile __rte_atomic int32_t *)&v->cnt, inc, 5739290f8beSTyler Retzlaff rte_memory_order_seq_cst); 57499a2dd95SBruce Richardson } 57599a2dd95SBruce Richardson 57699a2dd95SBruce Richardson /** 57799a2dd95SBruce Richardson * Atomically subtract a 32-bit value from an atomic counter. 57899a2dd95SBruce Richardson * 57999a2dd95SBruce Richardson * @param v 58099a2dd95SBruce Richardson * A pointer to the atomic counter. 58199a2dd95SBruce Richardson * @param dec 58299a2dd95SBruce Richardson * The value to be subtracted from the counter. 58399a2dd95SBruce Richardson */ 58499a2dd95SBruce Richardson static inline void 58599a2dd95SBruce Richardson rte_atomic32_sub(rte_atomic32_t *v, int32_t dec) 58699a2dd95SBruce Richardson { 5879290f8beSTyler Retzlaff rte_atomic_fetch_sub_explicit((volatile __rte_atomic int32_t *)&v->cnt, dec, 5889290f8beSTyler Retzlaff rte_memory_order_seq_cst); 58999a2dd95SBruce Richardson } 59099a2dd95SBruce Richardson 59199a2dd95SBruce Richardson /** 59299a2dd95SBruce Richardson * Atomically increment a counter by one. 59399a2dd95SBruce Richardson * 59499a2dd95SBruce Richardson * @param v 59599a2dd95SBruce Richardson * A pointer to the atomic counter. 59699a2dd95SBruce Richardson */ 59799a2dd95SBruce Richardson static inline void 59899a2dd95SBruce Richardson rte_atomic32_inc(rte_atomic32_t *v); 59999a2dd95SBruce Richardson 60099a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 60199a2dd95SBruce Richardson static inline void 60299a2dd95SBruce Richardson rte_atomic32_inc(rte_atomic32_t *v) 60399a2dd95SBruce Richardson { 60499a2dd95SBruce Richardson rte_atomic32_add(v, 1); 60599a2dd95SBruce Richardson } 60699a2dd95SBruce Richardson #endif 60799a2dd95SBruce Richardson 60899a2dd95SBruce Richardson /** 60999a2dd95SBruce Richardson * Atomically decrement a counter by one. 61099a2dd95SBruce Richardson * 61199a2dd95SBruce Richardson * @param v 61299a2dd95SBruce Richardson * A pointer to the atomic counter. 61399a2dd95SBruce Richardson */ 61499a2dd95SBruce Richardson static inline void 61599a2dd95SBruce Richardson rte_atomic32_dec(rte_atomic32_t *v); 61699a2dd95SBruce Richardson 61799a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 61899a2dd95SBruce Richardson static inline void 61999a2dd95SBruce Richardson rte_atomic32_dec(rte_atomic32_t *v) 62099a2dd95SBruce Richardson { 62199a2dd95SBruce Richardson rte_atomic32_sub(v,1); 62299a2dd95SBruce Richardson } 62399a2dd95SBruce Richardson #endif 62499a2dd95SBruce Richardson 62599a2dd95SBruce Richardson /** 62699a2dd95SBruce Richardson * Atomically add a 32-bit value to a counter and return the result. 62799a2dd95SBruce Richardson * 62899a2dd95SBruce Richardson * Atomically adds the 32-bits value (inc) to the atomic counter (v) and 62999a2dd95SBruce Richardson * returns the value of v after addition. 63099a2dd95SBruce Richardson * 63199a2dd95SBruce Richardson * @param v 63299a2dd95SBruce Richardson * A pointer to the atomic counter. 63399a2dd95SBruce Richardson * @param inc 63499a2dd95SBruce Richardson * The value to be added to the counter. 63599a2dd95SBruce Richardson * @return 63699a2dd95SBruce Richardson * The value of v after the addition. 63799a2dd95SBruce Richardson */ 63899a2dd95SBruce Richardson static inline int32_t 63999a2dd95SBruce Richardson rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc) 64099a2dd95SBruce Richardson { 6419290f8beSTyler Retzlaff return rte_atomic_fetch_add_explicit((volatile __rte_atomic int32_t *)&v->cnt, inc, 6429290f8beSTyler Retzlaff rte_memory_order_seq_cst) + inc; 64399a2dd95SBruce Richardson } 64499a2dd95SBruce Richardson 64599a2dd95SBruce Richardson /** 64699a2dd95SBruce Richardson * Atomically subtract a 32-bit value from a counter and return 64799a2dd95SBruce Richardson * the result. 64899a2dd95SBruce Richardson * 64999a2dd95SBruce Richardson * Atomically subtracts the 32-bit value (inc) from the atomic counter 65099a2dd95SBruce Richardson * (v) and returns the value of v after the subtraction. 65199a2dd95SBruce Richardson * 65299a2dd95SBruce Richardson * @param v 65399a2dd95SBruce Richardson * A pointer to the atomic counter. 65499a2dd95SBruce Richardson * @param dec 65599a2dd95SBruce Richardson * The value to be subtracted from the counter. 65699a2dd95SBruce Richardson * @return 65799a2dd95SBruce Richardson * The value of v after the subtraction. 65899a2dd95SBruce Richardson */ 65999a2dd95SBruce Richardson static inline int32_t 66099a2dd95SBruce Richardson rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec) 66199a2dd95SBruce Richardson { 6629290f8beSTyler Retzlaff return rte_atomic_fetch_sub_explicit((volatile __rte_atomic int32_t *)&v->cnt, dec, 6639290f8beSTyler Retzlaff rte_memory_order_seq_cst) - dec; 66499a2dd95SBruce Richardson } 66599a2dd95SBruce Richardson 66699a2dd95SBruce Richardson /** 66799a2dd95SBruce Richardson * Atomically increment a 32-bit counter by one and test. 66899a2dd95SBruce Richardson * 66999a2dd95SBruce Richardson * Atomically increments the atomic counter (v) by one and returns true if 67099a2dd95SBruce Richardson * the result is 0, or false in all other cases. 67199a2dd95SBruce Richardson * 67299a2dd95SBruce Richardson * @param v 67399a2dd95SBruce Richardson * A pointer to the atomic counter. 67499a2dd95SBruce Richardson * @return 67599a2dd95SBruce Richardson * True if the result after the increment operation is 0; false otherwise. 67699a2dd95SBruce Richardson */ 67799a2dd95SBruce Richardson static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v); 67899a2dd95SBruce Richardson 67999a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 68099a2dd95SBruce Richardson static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v) 68199a2dd95SBruce Richardson { 6829290f8beSTyler Retzlaff return rte_atomic_fetch_add_explicit((volatile __rte_atomic int32_t *)&v->cnt, 1, 6839290f8beSTyler Retzlaff rte_memory_order_seq_cst) + 1 == 0; 68499a2dd95SBruce Richardson } 68599a2dd95SBruce Richardson #endif 68699a2dd95SBruce Richardson 68799a2dd95SBruce Richardson /** 68899a2dd95SBruce Richardson * Atomically decrement a 32-bit counter by one and test. 68999a2dd95SBruce Richardson * 69099a2dd95SBruce Richardson * Atomically decrements the atomic counter (v) by one and returns true if 69199a2dd95SBruce Richardson * the result is 0, or false in all other cases. 69299a2dd95SBruce Richardson * 69399a2dd95SBruce Richardson * @param v 69499a2dd95SBruce Richardson * A pointer to the atomic counter. 69599a2dd95SBruce Richardson * @return 69699a2dd95SBruce Richardson * True if the result after the decrement operation is 0; false otherwise. 69799a2dd95SBruce Richardson */ 69899a2dd95SBruce Richardson static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v); 69999a2dd95SBruce Richardson 70099a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 70199a2dd95SBruce Richardson static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v) 70299a2dd95SBruce Richardson { 7039290f8beSTyler Retzlaff return rte_atomic_fetch_sub_explicit((volatile __rte_atomic int32_t *)&v->cnt, 1, 7049290f8beSTyler Retzlaff rte_memory_order_seq_cst) - 1 == 0; 70599a2dd95SBruce Richardson } 70699a2dd95SBruce Richardson #endif 70799a2dd95SBruce Richardson 70899a2dd95SBruce Richardson /** 70999a2dd95SBruce Richardson * Atomically test and set a 32-bit atomic counter. 71099a2dd95SBruce Richardson * 71199a2dd95SBruce Richardson * If the counter value is already set, return 0 (failed). Otherwise, set 71299a2dd95SBruce Richardson * the counter value to 1 and return 1 (success). 71399a2dd95SBruce Richardson * 71499a2dd95SBruce Richardson * @param v 71599a2dd95SBruce Richardson * A pointer to the atomic counter. 71699a2dd95SBruce Richardson * @return 71799a2dd95SBruce Richardson * 0 if failed; else 1, success. 71899a2dd95SBruce Richardson */ 71999a2dd95SBruce Richardson static inline int rte_atomic32_test_and_set(rte_atomic32_t *v); 72099a2dd95SBruce Richardson 72199a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 72299a2dd95SBruce Richardson static inline int rte_atomic32_test_and_set(rte_atomic32_t *v) 72399a2dd95SBruce Richardson { 72499a2dd95SBruce Richardson return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1); 72599a2dd95SBruce Richardson } 72699a2dd95SBruce Richardson #endif 72799a2dd95SBruce Richardson 72899a2dd95SBruce Richardson /** 72999a2dd95SBruce Richardson * Atomically set a 32-bit counter to 0. 73099a2dd95SBruce Richardson * 73199a2dd95SBruce Richardson * @param v 73299a2dd95SBruce Richardson * A pointer to the atomic counter. 73399a2dd95SBruce Richardson */ 73499a2dd95SBruce Richardson static inline void rte_atomic32_clear(rte_atomic32_t *v) 73599a2dd95SBruce Richardson { 73699a2dd95SBruce Richardson v->cnt = 0; 73799a2dd95SBruce Richardson } 73899a2dd95SBruce Richardson 73999a2dd95SBruce Richardson /*------------------------- 64 bit atomic operations -------------------------*/ 74099a2dd95SBruce Richardson 74199a2dd95SBruce Richardson /** 74299a2dd95SBruce Richardson * An atomic compare and set function used by the mutex functions. 74399a2dd95SBruce Richardson * (atomic) equivalent to: 74499a2dd95SBruce Richardson * if (*dst == exp) 74599a2dd95SBruce Richardson * *dst = src (all 64-bit words) 74699a2dd95SBruce Richardson * 74799a2dd95SBruce Richardson * @param dst 74899a2dd95SBruce Richardson * The destination into which the value will be written. 74999a2dd95SBruce Richardson * @param exp 75099a2dd95SBruce Richardson * The expected value. 75199a2dd95SBruce Richardson * @param src 75299a2dd95SBruce Richardson * The new value. 75399a2dd95SBruce Richardson * @return 75499a2dd95SBruce Richardson * Non-zero on success; 0 on failure. 75599a2dd95SBruce Richardson */ 75699a2dd95SBruce Richardson static inline int 75799a2dd95SBruce Richardson rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src); 75899a2dd95SBruce Richardson 75999a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 76099a2dd95SBruce Richardson static inline int 76199a2dd95SBruce Richardson rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src) 76299a2dd95SBruce Richardson { 76399a2dd95SBruce Richardson return __sync_bool_compare_and_swap(dst, exp, src); 76499a2dd95SBruce Richardson } 76599a2dd95SBruce Richardson #endif 76699a2dd95SBruce Richardson 76799a2dd95SBruce Richardson /** 76899a2dd95SBruce Richardson * Atomic exchange. 76999a2dd95SBruce Richardson * 77099a2dd95SBruce Richardson * (atomic) equivalent to: 77199a2dd95SBruce Richardson * ret = *dst 77299a2dd95SBruce Richardson * *dst = val; 77399a2dd95SBruce Richardson * return ret; 77499a2dd95SBruce Richardson * 77599a2dd95SBruce Richardson * @param dst 77699a2dd95SBruce Richardson * The destination location into which the value will be written. 77799a2dd95SBruce Richardson * @param val 77899a2dd95SBruce Richardson * The new value. 77999a2dd95SBruce Richardson * @return 78099a2dd95SBruce Richardson * The original value at that location 78199a2dd95SBruce Richardson */ 78299a2dd95SBruce Richardson static inline uint64_t 78399a2dd95SBruce Richardson rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val); 78499a2dd95SBruce Richardson 78599a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 78699a2dd95SBruce Richardson static inline uint64_t 78799a2dd95SBruce Richardson rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val) 78899a2dd95SBruce Richardson { 7891ec6a845STyler Retzlaff return rte_atomic_exchange_explicit(dst, val, rte_memory_order_seq_cst); 79099a2dd95SBruce Richardson } 79199a2dd95SBruce Richardson #endif 79299a2dd95SBruce Richardson 79399a2dd95SBruce Richardson /** 79499a2dd95SBruce Richardson * The atomic counter structure. 79599a2dd95SBruce Richardson */ 79699a2dd95SBruce Richardson typedef struct { 79799a2dd95SBruce Richardson volatile int64_t cnt; /**< Internal counter value. */ 79899a2dd95SBruce Richardson } rte_atomic64_t; 79999a2dd95SBruce Richardson 80099a2dd95SBruce Richardson /** 80199a2dd95SBruce Richardson * Static initializer for an atomic counter. 80299a2dd95SBruce Richardson */ 80399a2dd95SBruce Richardson #define RTE_ATOMIC64_INIT(val) { (val) } 80499a2dd95SBruce Richardson 80599a2dd95SBruce Richardson /** 80699a2dd95SBruce Richardson * Initialize the atomic counter. 80799a2dd95SBruce Richardson * 80899a2dd95SBruce Richardson * @param v 80999a2dd95SBruce Richardson * A pointer to the atomic counter. 81099a2dd95SBruce Richardson */ 81199a2dd95SBruce Richardson static inline void 81299a2dd95SBruce Richardson rte_atomic64_init(rte_atomic64_t *v); 81399a2dd95SBruce Richardson 81499a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 81599a2dd95SBruce Richardson static inline void 81699a2dd95SBruce Richardson rte_atomic64_init(rte_atomic64_t *v) 81799a2dd95SBruce Richardson { 81899a2dd95SBruce Richardson #ifdef __LP64__ 81999a2dd95SBruce Richardson v->cnt = 0; 82099a2dd95SBruce Richardson #else 82199a2dd95SBruce Richardson int success = 0; 82299a2dd95SBruce Richardson uint64_t tmp; 82399a2dd95SBruce Richardson 82499a2dd95SBruce Richardson while (success == 0) { 82599a2dd95SBruce Richardson tmp = v->cnt; 82699a2dd95SBruce Richardson success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 82799a2dd95SBruce Richardson tmp, 0); 82899a2dd95SBruce Richardson } 82999a2dd95SBruce Richardson #endif 83099a2dd95SBruce Richardson } 83199a2dd95SBruce Richardson #endif 83299a2dd95SBruce Richardson 83399a2dd95SBruce Richardson /** 83499a2dd95SBruce Richardson * Atomically read a 64-bit counter. 83599a2dd95SBruce Richardson * 83699a2dd95SBruce Richardson * @param v 83799a2dd95SBruce Richardson * A pointer to the atomic counter. 83899a2dd95SBruce Richardson * @return 83999a2dd95SBruce Richardson * The value of the counter. 84099a2dd95SBruce Richardson */ 84199a2dd95SBruce Richardson static inline int64_t 84299a2dd95SBruce Richardson rte_atomic64_read(rte_atomic64_t *v); 84399a2dd95SBruce Richardson 84499a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 84599a2dd95SBruce Richardson static inline int64_t 84699a2dd95SBruce Richardson rte_atomic64_read(rte_atomic64_t *v) 84799a2dd95SBruce Richardson { 84899a2dd95SBruce Richardson #ifdef __LP64__ 84999a2dd95SBruce Richardson return v->cnt; 85099a2dd95SBruce Richardson #else 85199a2dd95SBruce Richardson int success = 0; 85299a2dd95SBruce Richardson uint64_t tmp; 85399a2dd95SBruce Richardson 85499a2dd95SBruce Richardson while (success == 0) { 85599a2dd95SBruce Richardson tmp = v->cnt; 85699a2dd95SBruce Richardson /* replace the value by itself */ 85799a2dd95SBruce Richardson success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 85899a2dd95SBruce Richardson tmp, tmp); 85999a2dd95SBruce Richardson } 86099a2dd95SBruce Richardson return tmp; 86199a2dd95SBruce Richardson #endif 86299a2dd95SBruce Richardson } 86399a2dd95SBruce Richardson #endif 86499a2dd95SBruce Richardson 86599a2dd95SBruce Richardson /** 86699a2dd95SBruce Richardson * Atomically set a 64-bit counter. 86799a2dd95SBruce Richardson * 86899a2dd95SBruce Richardson * @param v 86999a2dd95SBruce Richardson * A pointer to the atomic counter. 87099a2dd95SBruce Richardson * @param new_value 87199a2dd95SBruce Richardson * The new value of the counter. 87299a2dd95SBruce Richardson */ 87399a2dd95SBruce Richardson static inline void 87499a2dd95SBruce Richardson rte_atomic64_set(rte_atomic64_t *v, int64_t new_value); 87599a2dd95SBruce Richardson 87699a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 87799a2dd95SBruce Richardson static inline void 87899a2dd95SBruce Richardson rte_atomic64_set(rte_atomic64_t *v, int64_t new_value) 87999a2dd95SBruce Richardson { 88099a2dd95SBruce Richardson #ifdef __LP64__ 88199a2dd95SBruce Richardson v->cnt = new_value; 88299a2dd95SBruce Richardson #else 88399a2dd95SBruce Richardson int success = 0; 88499a2dd95SBruce Richardson uint64_t tmp; 88599a2dd95SBruce Richardson 88699a2dd95SBruce Richardson while (success == 0) { 88799a2dd95SBruce Richardson tmp = v->cnt; 88899a2dd95SBruce Richardson success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 88999a2dd95SBruce Richardson tmp, new_value); 89099a2dd95SBruce Richardson } 89199a2dd95SBruce Richardson #endif 89299a2dd95SBruce Richardson } 89399a2dd95SBruce Richardson #endif 89499a2dd95SBruce Richardson 89599a2dd95SBruce Richardson /** 89699a2dd95SBruce Richardson * Atomically add a 64-bit value to a counter. 89799a2dd95SBruce Richardson * 89899a2dd95SBruce Richardson * @param v 89999a2dd95SBruce Richardson * A pointer to the atomic counter. 90099a2dd95SBruce Richardson * @param inc 90199a2dd95SBruce Richardson * The value to be added to the counter. 90299a2dd95SBruce Richardson */ 90399a2dd95SBruce Richardson static inline void 90499a2dd95SBruce Richardson rte_atomic64_add(rte_atomic64_t *v, int64_t inc); 90599a2dd95SBruce Richardson 90699a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 90799a2dd95SBruce Richardson static inline void 90899a2dd95SBruce Richardson rte_atomic64_add(rte_atomic64_t *v, int64_t inc) 90999a2dd95SBruce Richardson { 9109290f8beSTyler Retzlaff rte_atomic_fetch_add_explicit((volatile __rte_atomic int64_t *)&v->cnt, inc, 9119290f8beSTyler Retzlaff rte_memory_order_seq_cst); 91299a2dd95SBruce Richardson } 91399a2dd95SBruce Richardson #endif 91499a2dd95SBruce Richardson 91599a2dd95SBruce Richardson /** 91699a2dd95SBruce Richardson * Atomically subtract a 64-bit value from a counter. 91799a2dd95SBruce Richardson * 91899a2dd95SBruce Richardson * @param v 91999a2dd95SBruce Richardson * A pointer to the atomic counter. 92099a2dd95SBruce Richardson * @param dec 92199a2dd95SBruce Richardson * The value to be subtracted from the counter. 92299a2dd95SBruce Richardson */ 92399a2dd95SBruce Richardson static inline void 92499a2dd95SBruce Richardson rte_atomic64_sub(rte_atomic64_t *v, int64_t dec); 92599a2dd95SBruce Richardson 92699a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 92799a2dd95SBruce Richardson static inline void 92899a2dd95SBruce Richardson rte_atomic64_sub(rte_atomic64_t *v, int64_t dec) 92999a2dd95SBruce Richardson { 9309290f8beSTyler Retzlaff rte_atomic_fetch_sub_explicit((volatile __rte_atomic int64_t *)&v->cnt, dec, 9319290f8beSTyler Retzlaff rte_memory_order_seq_cst); 93299a2dd95SBruce Richardson } 93399a2dd95SBruce Richardson #endif 93499a2dd95SBruce Richardson 93599a2dd95SBruce Richardson /** 93699a2dd95SBruce Richardson * Atomically increment a 64-bit counter by one and test. 93799a2dd95SBruce Richardson * 93899a2dd95SBruce Richardson * @param v 93999a2dd95SBruce Richardson * A pointer to the atomic counter. 94099a2dd95SBruce Richardson */ 94199a2dd95SBruce Richardson static inline void 94299a2dd95SBruce Richardson rte_atomic64_inc(rte_atomic64_t *v); 94399a2dd95SBruce Richardson 94499a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 94599a2dd95SBruce Richardson static inline void 94699a2dd95SBruce Richardson rte_atomic64_inc(rte_atomic64_t *v) 94799a2dd95SBruce Richardson { 94899a2dd95SBruce Richardson rte_atomic64_add(v, 1); 94999a2dd95SBruce Richardson } 95099a2dd95SBruce Richardson #endif 95199a2dd95SBruce Richardson 95299a2dd95SBruce Richardson /** 95399a2dd95SBruce Richardson * Atomically decrement a 64-bit counter by one and test. 95499a2dd95SBruce Richardson * 95599a2dd95SBruce Richardson * @param v 95699a2dd95SBruce Richardson * A pointer to the atomic counter. 95799a2dd95SBruce Richardson */ 95899a2dd95SBruce Richardson static inline void 95999a2dd95SBruce Richardson rte_atomic64_dec(rte_atomic64_t *v); 96099a2dd95SBruce Richardson 96199a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 96299a2dd95SBruce Richardson static inline void 96399a2dd95SBruce Richardson rte_atomic64_dec(rte_atomic64_t *v) 96499a2dd95SBruce Richardson { 96599a2dd95SBruce Richardson rte_atomic64_sub(v, 1); 96699a2dd95SBruce Richardson } 96799a2dd95SBruce Richardson #endif 96899a2dd95SBruce Richardson 96999a2dd95SBruce Richardson /** 97099a2dd95SBruce Richardson * Add a 64-bit value to an atomic counter and return the result. 97199a2dd95SBruce Richardson * 97299a2dd95SBruce Richardson * Atomically adds the 64-bit value (inc) to the atomic counter (v) and 97399a2dd95SBruce Richardson * returns the value of v after the addition. 97499a2dd95SBruce Richardson * 97599a2dd95SBruce Richardson * @param v 97699a2dd95SBruce Richardson * A pointer to the atomic counter. 97799a2dd95SBruce Richardson * @param inc 97899a2dd95SBruce Richardson * The value to be added to the counter. 97999a2dd95SBruce Richardson * @return 98099a2dd95SBruce Richardson * The value of v after the addition. 98199a2dd95SBruce Richardson */ 98299a2dd95SBruce Richardson static inline int64_t 98399a2dd95SBruce Richardson rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc); 98499a2dd95SBruce Richardson 98599a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 98699a2dd95SBruce Richardson static inline int64_t 98799a2dd95SBruce Richardson rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc) 98899a2dd95SBruce Richardson { 9899290f8beSTyler Retzlaff return rte_atomic_fetch_add_explicit((volatile __rte_atomic int64_t *)&v->cnt, inc, 9909290f8beSTyler Retzlaff rte_memory_order_seq_cst) + inc; 99199a2dd95SBruce Richardson } 99299a2dd95SBruce Richardson #endif 99399a2dd95SBruce Richardson 99499a2dd95SBruce Richardson /** 99599a2dd95SBruce Richardson * Subtract a 64-bit value from an atomic counter and return the result. 99699a2dd95SBruce Richardson * 99799a2dd95SBruce Richardson * Atomically subtracts the 64-bit value (dec) from the atomic counter (v) 99899a2dd95SBruce Richardson * and returns the value of v after the subtraction. 99999a2dd95SBruce Richardson * 100099a2dd95SBruce Richardson * @param v 100199a2dd95SBruce Richardson * A pointer to the atomic counter. 100299a2dd95SBruce Richardson * @param dec 100399a2dd95SBruce Richardson * The value to be subtracted from the counter. 100499a2dd95SBruce Richardson * @return 100599a2dd95SBruce Richardson * The value of v after the subtraction. 100699a2dd95SBruce Richardson */ 100799a2dd95SBruce Richardson static inline int64_t 100899a2dd95SBruce Richardson rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec); 100999a2dd95SBruce Richardson 101099a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 101199a2dd95SBruce Richardson static inline int64_t 101299a2dd95SBruce Richardson rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec) 101399a2dd95SBruce Richardson { 10149290f8beSTyler Retzlaff return rte_atomic_fetch_sub_explicit((volatile __rte_atomic int64_t *)&v->cnt, dec, 10159290f8beSTyler Retzlaff rte_memory_order_seq_cst) - dec; 101699a2dd95SBruce Richardson } 101799a2dd95SBruce Richardson #endif 101899a2dd95SBruce Richardson 101999a2dd95SBruce Richardson /** 102099a2dd95SBruce Richardson * Atomically increment a 64-bit counter by one and test. 102199a2dd95SBruce Richardson * 102299a2dd95SBruce Richardson * Atomically increments the atomic counter (v) by one and returns 102399a2dd95SBruce Richardson * true if the result is 0, or false in all other cases. 102499a2dd95SBruce Richardson * 102599a2dd95SBruce Richardson * @param v 102699a2dd95SBruce Richardson * A pointer to the atomic counter. 102799a2dd95SBruce Richardson * @return 102899a2dd95SBruce Richardson * True if the result after the addition is 0; false otherwise. 102999a2dd95SBruce Richardson */ 103099a2dd95SBruce Richardson static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v); 103199a2dd95SBruce Richardson 103299a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 103399a2dd95SBruce Richardson static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v) 103499a2dd95SBruce Richardson { 103599a2dd95SBruce Richardson return rte_atomic64_add_return(v, 1) == 0; 103699a2dd95SBruce Richardson } 103799a2dd95SBruce Richardson #endif 103899a2dd95SBruce Richardson 103999a2dd95SBruce Richardson /** 104099a2dd95SBruce Richardson * Atomically decrement a 64-bit counter by one and test. 104199a2dd95SBruce Richardson * 104299a2dd95SBruce Richardson * Atomically decrements the atomic counter (v) by one and returns true if 104399a2dd95SBruce Richardson * the result is 0, or false in all other cases. 104499a2dd95SBruce Richardson * 104599a2dd95SBruce Richardson * @param v 104699a2dd95SBruce Richardson * A pointer to the atomic counter. 104799a2dd95SBruce Richardson * @return 104899a2dd95SBruce Richardson * True if the result after subtraction is 0; false otherwise. 104999a2dd95SBruce Richardson */ 105099a2dd95SBruce Richardson static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v); 105199a2dd95SBruce Richardson 105299a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 105399a2dd95SBruce Richardson static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v) 105499a2dd95SBruce Richardson { 105599a2dd95SBruce Richardson return rte_atomic64_sub_return(v, 1) == 0; 105699a2dd95SBruce Richardson } 105799a2dd95SBruce Richardson #endif 105899a2dd95SBruce Richardson 105999a2dd95SBruce Richardson /** 106099a2dd95SBruce Richardson * Atomically test and set a 64-bit atomic counter. 106199a2dd95SBruce Richardson * 106299a2dd95SBruce Richardson * If the counter value is already set, return 0 (failed). Otherwise, set 106399a2dd95SBruce Richardson * the counter value to 1 and return 1 (success). 106499a2dd95SBruce Richardson * 106599a2dd95SBruce Richardson * @param v 106699a2dd95SBruce Richardson * A pointer to the atomic counter. 106799a2dd95SBruce Richardson * @return 106899a2dd95SBruce Richardson * 0 if failed; else 1, success. 106999a2dd95SBruce Richardson */ 107099a2dd95SBruce Richardson static inline int rte_atomic64_test_and_set(rte_atomic64_t *v); 107199a2dd95SBruce Richardson 107299a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 107399a2dd95SBruce Richardson static inline int rte_atomic64_test_and_set(rte_atomic64_t *v) 107499a2dd95SBruce Richardson { 107599a2dd95SBruce Richardson return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1); 107699a2dd95SBruce Richardson } 107799a2dd95SBruce Richardson #endif 107899a2dd95SBruce Richardson 107999a2dd95SBruce Richardson /** 108099a2dd95SBruce Richardson * Atomically set a 64-bit counter to 0. 108199a2dd95SBruce Richardson * 108299a2dd95SBruce Richardson * @param v 108399a2dd95SBruce Richardson * A pointer to the atomic counter. 108499a2dd95SBruce Richardson */ 108599a2dd95SBruce Richardson static inline void rte_atomic64_clear(rte_atomic64_t *v); 108699a2dd95SBruce Richardson 108799a2dd95SBruce Richardson #ifdef RTE_FORCE_INTRINSICS 108899a2dd95SBruce Richardson static inline void rte_atomic64_clear(rte_atomic64_t *v) 108999a2dd95SBruce Richardson { 109099a2dd95SBruce Richardson rte_atomic64_set(v, 0); 109199a2dd95SBruce Richardson } 109299a2dd95SBruce Richardson #endif 109399a2dd95SBruce Richardson 109427da6a12STyler Retzlaff #endif 109527da6a12STyler Retzlaff 109699a2dd95SBruce Richardson /*------------------------ 128 bit atomic operations -------------------------*/ 109799a2dd95SBruce Richardson 109899a2dd95SBruce Richardson /** 109999a2dd95SBruce Richardson * 128-bit integer structure. 110099a2dd95SBruce Richardson */ 1101c6552d9aSTyler Retzlaff typedef struct __rte_aligned(16) { 110299a2dd95SBruce Richardson union { 110399a2dd95SBruce Richardson uint64_t val[2]; 110499a2dd95SBruce Richardson #ifdef RTE_ARCH_64 110527da6a12STyler Retzlaff #ifndef RTE_TOOLCHAIN_MSVC 110699a2dd95SBruce Richardson __extension__ __int128 int128; 110799a2dd95SBruce Richardson #endif 110827da6a12STyler Retzlaff #endif 110999a2dd95SBruce Richardson }; 1110c6552d9aSTyler Retzlaff } rte_int128_t; 111199a2dd95SBruce Richardson 111299a2dd95SBruce Richardson #ifdef __DOXYGEN__ 111399a2dd95SBruce Richardson 111499a2dd95SBruce Richardson /** 111599a2dd95SBruce Richardson * An atomic compare and set function used by the mutex functions. 111699a2dd95SBruce Richardson * (Atomically) Equivalent to: 111799a2dd95SBruce Richardson * @code 111899a2dd95SBruce Richardson * if (*dst == *exp) 111999a2dd95SBruce Richardson * *dst = *src 112099a2dd95SBruce Richardson * else 112199a2dd95SBruce Richardson * *exp = *dst 112299a2dd95SBruce Richardson * @endcode 112399a2dd95SBruce Richardson * 112499a2dd95SBruce Richardson * @note This function is currently available for the x86-64 and aarch64 112599a2dd95SBruce Richardson * platforms. 112699a2dd95SBruce Richardson * 112799a2dd95SBruce Richardson * @note The success and failure arguments must be one of the __ATOMIC_* values 112899a2dd95SBruce Richardson * defined in the C++11 standard. For details on their behavior, refer to the 112999a2dd95SBruce Richardson * standard. 113099a2dd95SBruce Richardson * 113199a2dd95SBruce Richardson * @param dst 113299a2dd95SBruce Richardson * The destination into which the value will be written. 113399a2dd95SBruce Richardson * @param exp 113499a2dd95SBruce Richardson * Pointer to the expected value. If the operation fails, this memory is 113599a2dd95SBruce Richardson * updated with the actual value. 113699a2dd95SBruce Richardson * @param src 113799a2dd95SBruce Richardson * Pointer to the new value. 113899a2dd95SBruce Richardson * @param weak 113999a2dd95SBruce Richardson * A value of true allows the comparison to spuriously fail and allows the 114099a2dd95SBruce Richardson * 'exp' update to occur non-atomically (i.e. a torn read may occur). 114199a2dd95SBruce Richardson * Implementations may ignore this argument and only implement the strong 114299a2dd95SBruce Richardson * variant. 114399a2dd95SBruce Richardson * @param success 114499a2dd95SBruce Richardson * If successful, the operation's memory behavior conforms to this (or a 114599a2dd95SBruce Richardson * stronger) model. 114699a2dd95SBruce Richardson * @param failure 114799a2dd95SBruce Richardson * If unsuccessful, the operation's memory behavior conforms to this (or a 11481ec6a845STyler Retzlaff * stronger) model. This argument cannot be rte_memory_order_release, 11491ec6a845STyler Retzlaff * rte_memory_order_acq_rel, or a stronger model than success. 115099a2dd95SBruce Richardson * @return 115199a2dd95SBruce Richardson * Non-zero on success; 0 on failure. 115299a2dd95SBruce Richardson */ 115399a2dd95SBruce Richardson static inline int 115499a2dd95SBruce Richardson rte_atomic128_cmp_exchange(rte_int128_t *dst, 115599a2dd95SBruce Richardson rte_int128_t *exp, 115699a2dd95SBruce Richardson const rte_int128_t *src, 115799a2dd95SBruce Richardson unsigned int weak, 115899a2dd95SBruce Richardson int success, 115999a2dd95SBruce Richardson int failure); 116099a2dd95SBruce Richardson 116199a2dd95SBruce Richardson #endif /* __DOXYGEN__ */ 116299a2dd95SBruce Richardson 1163*719834a6SMattias Rönnblom #ifdef __cplusplus 1164*719834a6SMattias Rönnblom } 1165*719834a6SMattias Rönnblom #endif 1166*719834a6SMattias Rönnblom 116799a2dd95SBruce Richardson #endif /* _RTE_ATOMIC_H_ */ 1168