/*-
* BSD LICENSE
*
- * Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#endif
#include <stdint.h>
-#include "arch/rte_atomic.h"
-
-#ifdef __DOXYGEN__
+#if RTE_MAX_LCORE == 1
+#define MPLOCKED /**< No need to insert MP lock prefix. */
+#else
+#define MPLOCKED "lock ; " /**< Insert MP lock prefix. */
+#endif
/**
* General memory barrier.
*/
#define rte_rmb() asm volatile("lfence;" : : : "memory")
+/**
+ * @file
+ * Atomic Operations on x86_64
+ */
+
/*------------------------- 16 bit atomic operations -------------------------*/
/**
* Non-zero on success; 0 on failure.
*/
static inline int
-rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src);
+rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
+{
+ uint8_t res;
+
+ asm volatile(
+ MPLOCKED
+ "cmpxchgw %[src], %[dst];"
+ "sete %[res];"
+ : [res] "=a" (res), /* output */
+ [dst] "=m" (*dst)
+ : [src] "r" (src), /* input */
+ "a" (exp),
+ "m" (*dst)
+ : "memory"); /* no-clobber list */
+ return res;
+}
/**
* The atomic counter structure.
* The value of the counter.
*/
static inline int16_t
-rte_atomic16_read(const rte_atomic16_t *v);
+rte_atomic16_read(const rte_atomic16_t *v)
+{
+ return v->cnt;
+}
/**
* Atomically set a counter to a 16-bit value.
* The new value for the counter.
*/
static inline void
-rte_atomic16_set(rte_atomic16_t *v, int16_t new_value);
+rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
+{
+ v->cnt = new_value;
+}
/**
* Atomically add a 16-bit value to an atomic counter.
* The value to be added to the counter.
*/
static inline void
-rte_atomic16_add(rte_atomic16_t *v, int16_t inc);
+rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
+{
+ __sync_fetch_and_add(&v->cnt, inc);
+}
/**
* Atomically subtract a 16-bit value from an atomic counter.
* The value to be subtracted from the counter.
*/
static inline void
-rte_atomic16_sub(rte_atomic16_t *v, int16_t dec);
+rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
+{
+ __sync_fetch_and_sub(&v->cnt, dec);
+}
/**
* Atomically increment a counter by one.
* A pointer to the atomic counter.
*/
static inline void
-rte_atomic16_inc(rte_atomic16_t *v);
+rte_atomic16_inc(rte_atomic16_t *v)
+{
+ asm volatile(
+ MPLOCKED
+ "incw %[cnt]"
+ : [cnt] "=m" (v->cnt) /* output */
+ : "m" (v->cnt) /* input */
+ );
+}
/**
* Atomically decrement a counter by one.
* A pointer to the atomic counter.
*/
static inline void
-rte_atomic16_dec(rte_atomic16_t *v);
+rte_atomic16_dec(rte_atomic16_t *v)
+{
+ asm volatile(
+ MPLOCKED
+ "decw %[cnt]"
+ : [cnt] "=m" (v->cnt) /* output */
+ : "m" (v->cnt) /* input */
+ );
+}
/**
* Atomically add a 16-bit value to a counter and return the result.
* The value of v after the addition.
*/
static inline int16_t
-rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc);
+rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
+{
+ return __sync_add_and_fetch(&v->cnt, inc);
+}
/**
* Atomically subtract a 16-bit value from a counter and return
* The value of v after the subtraction.
*/
static inline int16_t
-rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec);
+rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
+{
+ return __sync_sub_and_fetch(&v->cnt, dec);
+}
/**
* Atomically increment a 16-bit counter by one and test.
* @return
* True if the result after the increment operation is 0; false otherwise.
*/
-static inline int
-rte_atomic16_inc_and_test(rte_atomic16_t *v);
+static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
+{
+ uint8_t ret;
+
+ asm volatile(
+ MPLOCKED
+ "incw %[cnt] ; "
+ "sete %[ret]"
+ : [cnt] "+m" (v->cnt), /* output */
+ [ret] "=qm" (ret)
+ );
+ return (ret != 0);
+}
/**
* Atomically decrement a 16-bit counter by one and test.
* @return
* True if the result after the decrement operation is 0; false otherwise.
*/
-static inline int
-rte_atomic16_dec_and_test(rte_atomic16_t *v);
+static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
+{
+ uint8_t ret;
+
+ asm volatile(MPLOCKED
+ "decw %[cnt] ; "
+ "sete %[ret]"
+ : [cnt] "+m" (v->cnt), /* output */
+ [ret] "=qm" (ret)
+ );
+ return (ret != 0);
+}
/**
* Atomically test and set a 16-bit atomic counter.
* @return
* 0 if failed; else 1, success.
*/
-static inline int
-rte_atomic16_test_and_set(rte_atomic16_t *v);
+static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
+{
+ return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
+}
/**
* Atomically set a 16-bit counter to 0.
* @param v
* A pointer to the atomic counter.
*/
-static inline void
-rte_atomic16_clear(rte_atomic16_t *v);
+static inline void rte_atomic16_clear(rte_atomic16_t *v)
+{
+ v->cnt = 0;
+}
/*------------------------- 32 bit atomic operations -------------------------*/
* Non-zero on success; 0 on failure.
*/
static inline int
-rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src);
+rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
+{
+ uint8_t res;
+
+ asm volatile(
+ MPLOCKED
+ "cmpxchgl %[src], %[dst];"
+ "sete %[res];"
+ : [res] "=a" (res), /* output */
+ [dst] "=m" (*dst)
+ : [src] "r" (src), /* input */
+ "a" (exp),
+ "m" (*dst)
+ : "memory"); /* no-clobber list */
+ return res;
+}
/**
* The atomic counter structure.
* A pointer to the atomic counter.
*/
static inline void
-rte_atomic32_init(rte_atomic32_t *v);
+rte_atomic32_init(rte_atomic32_t *v)
+{
+ v->cnt = 0;
+}
/**
* Atomically read a 32-bit value from a counter.
* The value of the counter.
*/
static inline int32_t
-rte_atomic32_read(const rte_atomic32_t *v);
+rte_atomic32_read(const rte_atomic32_t *v)
+{
+ return v->cnt;
+}
/**
* Atomically set a counter to a 32-bit value.
* The new value for the counter.
*/
static inline void
-rte_atomic32_set(rte_atomic32_t *v, int32_t new_value);
+rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
+{
+ v->cnt = new_value;
+}
/**
* Atomically add a 32-bit value to an atomic counter.
* The value to be added to the counter.
*/
static inline void
-rte_atomic32_add(rte_atomic32_t *v, int32_t inc);
+rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
+{
+ __sync_fetch_and_add(&v->cnt, inc);
+}
/**
* Atomically subtract a 32-bit value from an atomic counter.
* The value to be subtracted from the counter.
*/
static inline void
-rte_atomic32_sub(rte_atomic32_t *v, int32_t dec);
+rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
+{
+ __sync_fetch_and_sub(&v->cnt, dec);
+}
/**
* Atomically increment a counter by one.
* A pointer to the atomic counter.
*/
static inline void
-rte_atomic32_inc(rte_atomic32_t *v);
+rte_atomic32_inc(rte_atomic32_t *v)
+{
+ asm volatile(
+ MPLOCKED
+ "incl %[cnt]"
+ : [cnt] "=m" (v->cnt) /* output */
+ : "m" (v->cnt) /* input */
+ );
+}
/**
* Atomically decrement a counter by one.
* A pointer to the atomic counter.
*/
static inline void
-rte_atomic32_dec(rte_atomic32_t *v);
+rte_atomic32_dec(rte_atomic32_t *v)
+{
+ asm volatile(
+ MPLOCKED
+ "decl %[cnt]"
+ : [cnt] "=m" (v->cnt) /* output */
+ : "m" (v->cnt) /* input */
+ );
+}
/**
* Atomically add a 32-bit value to a counter and return the result.
* The value of v after the addition.
*/
static inline int32_t
-rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc);
+rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
+{
+ return __sync_add_and_fetch(&v->cnt, inc);
+}
/**
* Atomically subtract a 32-bit value from a counter and return
* The value of v after the subtraction.
*/
static inline int32_t
-rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec);
+rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
+{
+ return __sync_sub_and_fetch(&v->cnt, dec);
+}
/**
* Atomically increment a 32-bit counter by one and test.
* @return
* True if the result after the increment operation is 0; false otherwise.
*/
-static inline int
-rte_atomic32_inc_and_test(rte_atomic32_t *v);
+static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
+{
+ uint8_t ret;
+
+ asm volatile(
+ MPLOCKED
+ "incl %[cnt] ; "
+ "sete %[ret]"
+ : [cnt] "+m" (v->cnt), /* output */
+ [ret] "=qm" (ret)
+ );
+ return (ret != 0);
+}
/**
* Atomically decrement a 32-bit counter by one and test.
* @return
* True if the result after the decrement operation is 0; false otherwise.
*/
-static inline int
-rte_atomic32_dec_and_test(rte_atomic32_t *v);
+static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
+{
+ uint8_t ret;
+
+ asm volatile(MPLOCKED
+ "decl %[cnt] ; "
+ "sete %[ret]"
+ : [cnt] "+m" (v->cnt), /* output */
+ [ret] "=qm" (ret)
+ );
+ return (ret != 0);
+}
/**
* Atomically test and set a 32-bit atomic counter.
* @return
* 0 if failed; else 1, success.
*/
-static inline int
-rte_atomic32_test_and_set(rte_atomic32_t *v);
+static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
+{
+ return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
+}
/**
* Atomically set a 32-bit counter to 0.
* @param v
* A pointer to the atomic counter.
*/
-static inline void
-rte_atomic32_clear(rte_atomic32_t *v);
+static inline void rte_atomic32_clear(rte_atomic32_t *v)
+{
+ v->cnt = 0;
+}
+
+/* any other functions are in arch specific files */
+#include "arch/rte_atomic.h"
+
+
+#ifdef __DOXYGEN__
/*------------------------- 64 bit atomic operations -------------------------*/