[dpdk-dev,v3,01/15] eal: introduce atomic exchange operation
Checks
Commit Message
To handle atomic update of link status (64 bit), every driver
was doing its own version using cmpset.
Atomic exchange is a useful primitive in its own right;
therefore make it a EAL routine.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
.../common/include/arch/x86/rte_atomic.h | 24 +++++++
.../common/include/arch/x86/rte_atomic_32.h | 12 ++++
.../common/include/arch/x86/rte_atomic_64.h | 12 ++++
lib/librte_eal/common/include/generic/rte_atomic.h | 78 ++++++++++++++++++++++
4 files changed, 126 insertions(+)
Comments
On 1/8/2018 5:45 PM, Stephen Hemminger wrote:
> To handle atomic update of link status (64 bit), every driver
> was doing its own version using cmpset.
> Atomic exchange is a useful primitive in its own right;
> therefore make it a EAL routine.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
<...>
> @@ -98,6 +98,18 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
> return res;
> }
>
> +static inline uint64_t
> +rte_atomic64_exchange(volatile uint64_t *dest, uint64_t val)
> +{
> + uint64_t old;
> +
> + do {
> + old = *dest;
> + } while (rte_atomic64_t_cmpset(dest, old, val));
rte_atomic64_cmpset ? (without _t)
> +
> + return old;
> +}
<...>
On Thu, 11 Jan 2018 17:01:10 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> On 1/8/2018 5:45 PM, Stephen Hemminger wrote:
> > To handle atomic update of link status (64 bit), every driver
> > was doing its own version using cmpset.
> > Atomic exchange is a useful primitive in its own right;
> > therefore make it a EAL routine.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>
> <...>
>
> > @@ -98,6 +98,18 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
> > return res;
> > }
> >
> > +static inline uint64_t
> > +rte_atomic64_exchange(volatile uint64_t *dest, uint64_t val)
> > +{
> > + uint64_t old;
> > +
> > + do {
> > + old = *dest;
> > + } while (rte_atomic64_t_cmpset(dest, old, val));
>
> rte_atomic64_cmpset ? (without _t)
>
> > +
> > + return old;
> > +}
>
> <...>
>
Addressed in followup patch, needed to build on 32bit.
Will fold into next version.
On Thu, 11 Jan 2018 17:01:10 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> On 1/8/2018 5:45 PM, Stephen Hemminger wrote:
> > To handle atomic update of link status (64 bit), every driver
> > was doing its own version using cmpset.
> > Atomic exchange is a useful primitive in its own right;
> > therefore make it a EAL routine.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>
> <...>
>
> > @@ -98,6 +98,18 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
> > return res;
> > }
> >
> > +static inline uint64_t
> > +rte_atomic64_exchange(volatile uint64_t *dest, uint64_t val)
> > +{
> > + uint64_t old;
> > +
> > + do {
> > + old = *dest;
> > + } while (rte_atomic64_t_cmpset(dest, old, val));
>
> rte_atomic64_cmpset ? (without _t)
Wasn't that fixed in later version?
@@ -59,6 +59,18 @@ rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
return res;
}
+static inline uint16_t
+rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val)
+{
+ asm volatile(
+ MPLOCKED
+ "xchgw %0, %1;"
+ : "=r" (val), "=m" (*dst)
+ : "0" (val), "m" (*dst)
+ : "memory"); /* no-clobber list */
+ return val;
+}
+
static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
{
return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
@@ -133,6 +145,18 @@ rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
return res;
}
+static inline uint32_t
+rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val)
+{
+ asm volatile(
+ MPLOCKED
+ "xchgl %0, %1;"
+ : "=r" (val), "=m" (*dst)
+ : "0" (val), "m" (*dst)
+ : "memory"); /* no-clobber list */
+ return val;
+}
+
static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
{
return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
@@ -98,6 +98,18 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
return res;
}
+static inline uint64_t
+rte_atomic64_exchange(volatile uint64_t *dest, uint64_t val)
+{
+ uint64_t old;
+
+ do {
+ old = *dest;
+ } while (rte_atomic64_t_cmpset(dest, old, val));
+
+ return old;
+}
+
static inline void
rte_atomic64_init(rte_atomic64_t *v)
{
@@ -71,6 +71,18 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
return res;
}
+static inline uint64_t
+rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val)
+{
+ asm volatile(
+ MPLOCKED
+ "xchgq %0, %1;"
+ : "=r" (val), "=m" (*dst)
+ : "0" (val), "m" (*dst)
+ : "memory"); /* no-clobber list */
+ return val;
+}
+
static inline void
rte_atomic64_init(rte_atomic64_t *v)
{
@@ -139,6 +139,32 @@ rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
}
#endif
+/**
+ * Atomic exchange.
+ *
+ * (atomic) equivalent to:
+ * ret = *dst
+ * *dst = val;
+ * return ret;
+ *
+ * @param dst
+ * The destination location into which the value will be written.
+ * @param val
+ * The new value.
+ * @return
+ * The original value at that location
+ */
+static inline uint16_t
+rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val);
+
+#ifdef RTE_FORCE_INTRINSICS
+static inline uint16_t
+rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val)
+{
+ return __atomic_exchange_2(dst, val, __ATOMIC_SEQ_CST);
+}
+#endif
+
/**
* The atomic counter structure.
*/
@@ -392,6 +418,32 @@ rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
}
#endif
+/**
+ * Atomic exchange.
+ *
+ * (atomic) equivalent to:
+ * ret = *dst
+ * *dst = val;
+ * return ret;
+ *
+ * @param dst
+ * The destination location into which the value will be written.
+ * @param val
+ * The new value.
+ * @return
+ * The original value at that location
+ */
+static inline uint32_t
+rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val);
+
+#ifdef RTE_FORCE_INTRINSICS
+static inline uint32_t
+rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val)
+{
+ return __atomic_exchange_4(dst, val, __ATOMIC_SEQ_CST);
+}
+#endif
+
/**
* The atomic counter structure.
*/
@@ -644,6 +696,32 @@ rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
}
#endif
+/**
+ * Atomic exchange.
+ *
+ * (atomic) equivalent to:
+ * ret = *dst
+ * *dst = val;
+ * return ret;
+ *
+ * @param dst
+ * The destination location into which the value will be written.
+ * @param val
+ * The new value.
+ * @return
+ * The original value at that location
+ */
+static inline uint64_t
+rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val);
+
+#ifdef RTE_FORCE_INTRINSICS
+static inline uint64_t
+rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val)
+{
+ return __atomic_exchange_4(dst, val, __ATOMIC_SEQ_CST);
+}
+#endif
+
/**
* The atomic counter structure.
*/