199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * 399a2dd95SBruce Richardson * Copyright (c) 2010-2020 Intel Corporation 499a2dd95SBruce Richardson * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org 599a2dd95SBruce Richardson * All rights reserved. 699a2dd95SBruce Richardson * Derived from FreeBSD's bufring.h 799a2dd95SBruce Richardson * Used as BSD-3 Licensed with permission from Kip Macy. 899a2dd95SBruce Richardson */ 999a2dd95SBruce Richardson 1099a2dd95SBruce Richardson #ifndef _RTE_RING_RTS_H_ 1199a2dd95SBruce Richardson #define _RTE_RING_RTS_H_ 1299a2dd95SBruce Richardson 1399a2dd95SBruce Richardson /** 1499a2dd95SBruce Richardson * @file rte_ring_rts.h 1599a2dd95SBruce Richardson * It is not recommended to include this file directly. 1699a2dd95SBruce Richardson * Please include <rte_ring.h> instead. 1799a2dd95SBruce Richardson * 1899a2dd95SBruce Richardson * Contains functions for Relaxed Tail Sync (RTS) ring mode. 1999a2dd95SBruce Richardson * The main idea remains the same as for our original MP/MC synchronization 2099a2dd95SBruce Richardson * mechanism. 2199a2dd95SBruce Richardson * The main difference is that tail value is increased not 2299a2dd95SBruce Richardson * by every thread that finished enqueue/dequeue, 2399a2dd95SBruce Richardson * but only by the current last one doing enqueue/dequeue. 2499a2dd95SBruce Richardson * That allows threads to skip spinning on tail value, 2599a2dd95SBruce Richardson * leaving actual tail value change to last thread at a given instance. 2699a2dd95SBruce Richardson * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation: 2799a2dd95SBruce Richardson * one for head update, second for tail update. 2899a2dd95SBruce Richardson * As a gain it allows thread to avoid spinning/waiting on tail value. 2999a2dd95SBruce Richardson * In comparison original MP/MC algorithm requires one 32-bit CAS 3099a2dd95SBruce Richardson * for head update and waiting/spinning on tail value. 3199a2dd95SBruce Richardson * 3299a2dd95SBruce Richardson * Brief outline: 3399a2dd95SBruce Richardson * - introduce update counter (cnt) for both head and tail. 3499a2dd95SBruce Richardson * - increment head.cnt for each head.value update 3599a2dd95SBruce Richardson * - write head.value and head.cnt atomically (64-bit CAS) 3699a2dd95SBruce Richardson * - move tail.value ahead only when tail.cnt + 1 == head.cnt 3799a2dd95SBruce Richardson * (indicating that this is the last thread updating the tail) 3899a2dd95SBruce Richardson * - increment tail.cnt when each enqueue/dequeue op finishes 3999a2dd95SBruce Richardson * (no matter if tail.value going to change or not) 4099a2dd95SBruce Richardson * - write tail.value and tail.cnt atomically (64-bit CAS) 4199a2dd95SBruce Richardson * 4299a2dd95SBruce Richardson * To avoid producer/consumer starvation: 4399a2dd95SBruce Richardson * - limit max allowed distance between head and tail value (HTD_MAX). 4499a2dd95SBruce Richardson * I.E. thread is allowed to proceed with changing head.value, 4599a2dd95SBruce Richardson * only when: head.value - tail.value <= HTD_MAX 4699a2dd95SBruce Richardson * HTD_MAX is an optional parameter. 4799a2dd95SBruce Richardson * With HTD_MAX == 0 we'll have fully serialized ring - 4899a2dd95SBruce Richardson * i.e. only one thread at a time will be able to enqueue/dequeue 4999a2dd95SBruce Richardson * to/from the ring. 5099a2dd95SBruce Richardson * With HTD_MAX >= ring.capacity - no limitation. 5199a2dd95SBruce Richardson * By default HTD_MAX == ring.capacity / 8. 5299a2dd95SBruce Richardson */ 5399a2dd95SBruce Richardson 54*719834a6SMattias Rönnblom #include <rte_ring_rts_elem_pvt.h> 55*719834a6SMattias Rönnblom 5699a2dd95SBruce Richardson #ifdef __cplusplus 5799a2dd95SBruce Richardson extern "C" { 5899a2dd95SBruce Richardson #endif 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson /** 6199a2dd95SBruce Richardson * Enqueue several objects on the RTS ring (multi-producers safe). 6299a2dd95SBruce Richardson * 6399a2dd95SBruce Richardson * @param r 6499a2dd95SBruce Richardson * A pointer to the ring structure. 6599a2dd95SBruce Richardson * @param obj_table 6699a2dd95SBruce Richardson * A pointer to a table of objects. 6799a2dd95SBruce Richardson * @param esize 6899a2dd95SBruce Richardson * The size of ring element, in bytes. It must be a multiple of 4. 6999a2dd95SBruce Richardson * This must be the same value used while creating the ring. Otherwise 7099a2dd95SBruce Richardson * the results are undefined. 7199a2dd95SBruce Richardson * @param n 7299a2dd95SBruce Richardson * The number of objects to add in the ring from the obj_table. 7399a2dd95SBruce Richardson * @param free_space 7499a2dd95SBruce Richardson * if non-NULL, returns the amount of space in the ring after the 7599a2dd95SBruce Richardson * enqueue operation has finished. 7699a2dd95SBruce Richardson * @return 7799a2dd95SBruce Richardson * The number of objects enqueued, either 0 or n 7899a2dd95SBruce Richardson */ 7999a2dd95SBruce Richardson static __rte_always_inline unsigned int 8099a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table, 8199a2dd95SBruce Richardson unsigned int esize, unsigned int n, unsigned int *free_space) 8299a2dd95SBruce Richardson { 8399a2dd95SBruce Richardson return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n, 8499a2dd95SBruce Richardson RTE_RING_QUEUE_FIXED, free_space); 8599a2dd95SBruce Richardson } 8699a2dd95SBruce Richardson 8799a2dd95SBruce Richardson /** 8899a2dd95SBruce Richardson * Dequeue several objects from an RTS ring (multi-consumers safe). 8999a2dd95SBruce Richardson * 9099a2dd95SBruce Richardson * @param r 9199a2dd95SBruce Richardson * A pointer to the ring structure. 9299a2dd95SBruce Richardson * @param obj_table 9399a2dd95SBruce Richardson * A pointer to a table of objects that will be filled. 9499a2dd95SBruce Richardson * @param esize 9599a2dd95SBruce Richardson * The size of ring element, in bytes. It must be a multiple of 4. 9699a2dd95SBruce Richardson * This must be the same value used while creating the ring. Otherwise 9799a2dd95SBruce Richardson * the results are undefined. 9899a2dd95SBruce Richardson * @param n 9999a2dd95SBruce Richardson * The number of objects to dequeue from the ring to the obj_table. 10099a2dd95SBruce Richardson * @param available 10199a2dd95SBruce Richardson * If non-NULL, returns the number of remaining ring entries after the 10299a2dd95SBruce Richardson * dequeue has finished. 10399a2dd95SBruce Richardson * @return 10499a2dd95SBruce Richardson * The number of objects dequeued, either 0 or n 10599a2dd95SBruce Richardson */ 10699a2dd95SBruce Richardson static __rte_always_inline unsigned int 10799a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void *obj_table, 10899a2dd95SBruce Richardson unsigned int esize, unsigned int n, unsigned int *available) 10999a2dd95SBruce Richardson { 11099a2dd95SBruce Richardson return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n, 11199a2dd95SBruce Richardson RTE_RING_QUEUE_FIXED, available); 11299a2dd95SBruce Richardson } 11399a2dd95SBruce Richardson 11499a2dd95SBruce Richardson /** 11599a2dd95SBruce Richardson * Enqueue several objects on the RTS ring (multi-producers safe). 11699a2dd95SBruce Richardson * 11799a2dd95SBruce Richardson * @param r 11899a2dd95SBruce Richardson * A pointer to the ring structure. 11999a2dd95SBruce Richardson * @param obj_table 12099a2dd95SBruce Richardson * A pointer to a table of objects. 12199a2dd95SBruce Richardson * @param esize 12299a2dd95SBruce Richardson * The size of ring element, in bytes. It must be a multiple of 4. 12399a2dd95SBruce Richardson * This must be the same value used while creating the ring. Otherwise 12499a2dd95SBruce Richardson * the results are undefined. 12599a2dd95SBruce Richardson * @param n 12699a2dd95SBruce Richardson * The number of objects to add in the ring from the obj_table. 12799a2dd95SBruce Richardson * @param free_space 12899a2dd95SBruce Richardson * if non-NULL, returns the amount of space in the ring after the 12999a2dd95SBruce Richardson * enqueue operation has finished. 13099a2dd95SBruce Richardson * @return 13199a2dd95SBruce Richardson * - n: Actual number of objects enqueued. 13299a2dd95SBruce Richardson */ 13399a2dd95SBruce Richardson static __rte_always_inline unsigned int 13499a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, const void *obj_table, 13599a2dd95SBruce Richardson unsigned int esize, unsigned int n, unsigned int *free_space) 13699a2dd95SBruce Richardson { 13799a2dd95SBruce Richardson return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n, 13899a2dd95SBruce Richardson RTE_RING_QUEUE_VARIABLE, free_space); 13999a2dd95SBruce Richardson } 14099a2dd95SBruce Richardson 14199a2dd95SBruce Richardson /** 14299a2dd95SBruce Richardson * Dequeue several objects from an RTS ring (multi-consumers safe). 14399a2dd95SBruce Richardson * When the requested objects are more than the available objects, 14499a2dd95SBruce Richardson * only dequeue the actual number of objects. 14599a2dd95SBruce Richardson * 14699a2dd95SBruce Richardson * @param r 14799a2dd95SBruce Richardson * A pointer to the ring structure. 14899a2dd95SBruce Richardson * @param obj_table 14999a2dd95SBruce Richardson * A pointer to a table of objects that will be filled. 15099a2dd95SBruce Richardson * @param esize 15199a2dd95SBruce Richardson * The size of ring element, in bytes. It must be a multiple of 4. 15299a2dd95SBruce Richardson * This must be the same value used while creating the ring. Otherwise 15399a2dd95SBruce Richardson * the results are undefined. 15499a2dd95SBruce Richardson * @param n 15599a2dd95SBruce Richardson * The number of objects to dequeue from the ring to the obj_table. 15699a2dd95SBruce Richardson * @param available 15799a2dd95SBruce Richardson * If non-NULL, returns the number of remaining ring entries after the 15899a2dd95SBruce Richardson * dequeue has finished. 15999a2dd95SBruce Richardson * @return 16099a2dd95SBruce Richardson * - n: Actual number of objects dequeued, 0 if ring is empty 16199a2dd95SBruce Richardson */ 16299a2dd95SBruce Richardson static __rte_always_inline unsigned int 16399a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void *obj_table, 16499a2dd95SBruce Richardson unsigned int esize, unsigned int n, unsigned int *available) 16599a2dd95SBruce Richardson { 16699a2dd95SBruce Richardson return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n, 16799a2dd95SBruce Richardson RTE_RING_QUEUE_VARIABLE, available); 16899a2dd95SBruce Richardson } 16999a2dd95SBruce Richardson 17099a2dd95SBruce Richardson /** 17199a2dd95SBruce Richardson * Enqueue several objects on the RTS ring (multi-producers safe). 17299a2dd95SBruce Richardson * 17399a2dd95SBruce Richardson * @param r 17499a2dd95SBruce Richardson * A pointer to the ring structure. 17599a2dd95SBruce Richardson * @param obj_table 17699a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects). 17799a2dd95SBruce Richardson * @param n 17899a2dd95SBruce Richardson * The number of objects to add in the ring from the obj_table. 17999a2dd95SBruce Richardson * @param free_space 18099a2dd95SBruce Richardson * if non-NULL, returns the amount of space in the ring after the 18199a2dd95SBruce Richardson * enqueue operation has finished. 18299a2dd95SBruce Richardson * @return 18399a2dd95SBruce Richardson * The number of objects enqueued, either 0 or n 18499a2dd95SBruce Richardson */ 18599a2dd95SBruce Richardson static __rte_always_inline unsigned int 18699a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table, 18799a2dd95SBruce Richardson unsigned int n, unsigned int *free_space) 18899a2dd95SBruce Richardson { 18999a2dd95SBruce Richardson return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table, 19099a2dd95SBruce Richardson sizeof(uintptr_t), n, free_space); 19199a2dd95SBruce Richardson } 19299a2dd95SBruce Richardson 19399a2dd95SBruce Richardson /** 19499a2dd95SBruce Richardson * Dequeue several objects from an RTS ring (multi-consumers safe). 19599a2dd95SBruce Richardson * 19699a2dd95SBruce Richardson * @param r 19799a2dd95SBruce Richardson * A pointer to the ring structure. 19899a2dd95SBruce Richardson * @param obj_table 19999a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects) that will be filled. 20099a2dd95SBruce Richardson * @param n 20199a2dd95SBruce Richardson * The number of objects to dequeue from the ring to the obj_table. 20299a2dd95SBruce Richardson * @param available 20399a2dd95SBruce Richardson * If non-NULL, returns the number of remaining ring entries after the 20499a2dd95SBruce Richardson * dequeue has finished. 20599a2dd95SBruce Richardson * @return 20699a2dd95SBruce Richardson * The number of objects dequeued, either 0 or n 20799a2dd95SBruce Richardson */ 20899a2dd95SBruce Richardson static __rte_always_inline unsigned int 20999a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table, 21099a2dd95SBruce Richardson unsigned int n, unsigned int *available) 21199a2dd95SBruce Richardson { 21299a2dd95SBruce Richardson return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table, 21399a2dd95SBruce Richardson sizeof(uintptr_t), n, available); 21499a2dd95SBruce Richardson } 21599a2dd95SBruce Richardson 21699a2dd95SBruce Richardson /** 21799a2dd95SBruce Richardson * Enqueue several objects on the RTS ring (multi-producers safe). 21899a2dd95SBruce Richardson * 21999a2dd95SBruce Richardson * @param r 22099a2dd95SBruce Richardson * A pointer to the ring structure. 22199a2dd95SBruce Richardson * @param obj_table 22299a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects). 22399a2dd95SBruce Richardson * @param n 22499a2dd95SBruce Richardson * The number of objects to add in the ring from the obj_table. 22599a2dd95SBruce Richardson * @param free_space 22699a2dd95SBruce Richardson * if non-NULL, returns the amount of space in the ring after the 22799a2dd95SBruce Richardson * enqueue operation has finished. 22899a2dd95SBruce Richardson * @return 22999a2dd95SBruce Richardson * - n: Actual number of objects enqueued. 23099a2dd95SBruce Richardson */ 23199a2dd95SBruce Richardson static __rte_always_inline unsigned int 23299a2dd95SBruce Richardson rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table, 23399a2dd95SBruce Richardson unsigned int n, unsigned int *free_space) 23499a2dd95SBruce Richardson { 23599a2dd95SBruce Richardson return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table, 23699a2dd95SBruce Richardson sizeof(uintptr_t), n, free_space); 23799a2dd95SBruce Richardson } 23899a2dd95SBruce Richardson 23999a2dd95SBruce Richardson /** 24099a2dd95SBruce Richardson * Dequeue several objects from an RTS ring (multi-consumers safe). 24199a2dd95SBruce Richardson * When the requested objects are more than the available objects, 24299a2dd95SBruce Richardson * only dequeue the actual number of objects. 24399a2dd95SBruce Richardson * 24499a2dd95SBruce Richardson * @param r 24599a2dd95SBruce Richardson * A pointer to the ring structure. 24699a2dd95SBruce Richardson * @param obj_table 24799a2dd95SBruce Richardson * A pointer to a table of void * pointers (objects) that will be filled. 24899a2dd95SBruce Richardson * @param n 24999a2dd95SBruce Richardson * The number of objects to dequeue from the ring to the obj_table. 25099a2dd95SBruce Richardson * @param available 25199a2dd95SBruce Richardson * If non-NULL, returns the number of remaining ring entries after the 25299a2dd95SBruce Richardson * dequeue has finished. 25399a2dd95SBruce Richardson * @return 25499a2dd95SBruce Richardson * - n: Actual number of objects dequeued, 0 if ring is empty 25599a2dd95SBruce Richardson */ 25699a2dd95SBruce Richardson static __rte_always_inline unsigned int 25799a2dd95SBruce Richardson rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table, 25899a2dd95SBruce Richardson unsigned int n, unsigned int *available) 25999a2dd95SBruce Richardson { 26099a2dd95SBruce Richardson return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table, 26199a2dd95SBruce Richardson sizeof(uintptr_t), n, available); 26299a2dd95SBruce Richardson } 26399a2dd95SBruce Richardson 26499a2dd95SBruce Richardson /** 26599a2dd95SBruce Richardson * Return producer max Head-Tail-Distance (HTD). 26699a2dd95SBruce Richardson * 26799a2dd95SBruce Richardson * @param r 26899a2dd95SBruce Richardson * A pointer to the ring structure. 26999a2dd95SBruce Richardson * @return 27099a2dd95SBruce Richardson * Producer HTD value, if producer is set in appropriate sync mode, 27199a2dd95SBruce Richardson * or UINT32_MAX otherwise. 27299a2dd95SBruce Richardson */ 27399a2dd95SBruce Richardson static inline uint32_t 27499a2dd95SBruce Richardson rte_ring_get_prod_htd_max(const struct rte_ring *r) 27599a2dd95SBruce Richardson { 27699a2dd95SBruce Richardson if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS) 27799a2dd95SBruce Richardson return r->rts_prod.htd_max; 27899a2dd95SBruce Richardson return UINT32_MAX; 27999a2dd95SBruce Richardson } 28099a2dd95SBruce Richardson 28199a2dd95SBruce Richardson /** 28299a2dd95SBruce Richardson * Set producer max Head-Tail-Distance (HTD). 28399a2dd95SBruce Richardson * Note that producer has to use appropriate sync mode (RTS). 28499a2dd95SBruce Richardson * 28599a2dd95SBruce Richardson * @param r 28699a2dd95SBruce Richardson * A pointer to the ring structure. 28799a2dd95SBruce Richardson * @param v 28899a2dd95SBruce Richardson * new HTD value to setup. 28999a2dd95SBruce Richardson * @return 29099a2dd95SBruce Richardson * Zero on success, or negative error code otherwise. 29199a2dd95SBruce Richardson */ 29299a2dd95SBruce Richardson static inline int 29399a2dd95SBruce Richardson rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v) 29499a2dd95SBruce Richardson { 29599a2dd95SBruce Richardson if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS) 29699a2dd95SBruce Richardson return -ENOTSUP; 29799a2dd95SBruce Richardson 29899a2dd95SBruce Richardson r->rts_prod.htd_max = v; 29999a2dd95SBruce Richardson return 0; 30099a2dd95SBruce Richardson } 30199a2dd95SBruce Richardson 30299a2dd95SBruce Richardson /** 30399a2dd95SBruce Richardson * Return consumer max Head-Tail-Distance (HTD). 30499a2dd95SBruce Richardson * 30599a2dd95SBruce Richardson * @param r 30699a2dd95SBruce Richardson * A pointer to the ring structure. 30799a2dd95SBruce Richardson * @return 30899a2dd95SBruce Richardson * Consumer HTD value, if consumer is set in appropriate sync mode, 30999a2dd95SBruce Richardson * or UINT32_MAX otherwise. 31099a2dd95SBruce Richardson */ 31199a2dd95SBruce Richardson static inline uint32_t 31299a2dd95SBruce Richardson rte_ring_get_cons_htd_max(const struct rte_ring *r) 31399a2dd95SBruce Richardson { 31499a2dd95SBruce Richardson if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS) 31599a2dd95SBruce Richardson return r->rts_cons.htd_max; 31699a2dd95SBruce Richardson return UINT32_MAX; 31799a2dd95SBruce Richardson } 31899a2dd95SBruce Richardson 31999a2dd95SBruce Richardson /** 32099a2dd95SBruce Richardson * Set consumer max Head-Tail-Distance (HTD). 32199a2dd95SBruce Richardson * Note that consumer has to use appropriate sync mode (RTS). 32299a2dd95SBruce Richardson * 32399a2dd95SBruce Richardson * @param r 32499a2dd95SBruce Richardson * A pointer to the ring structure. 32599a2dd95SBruce Richardson * @param v 32699a2dd95SBruce Richardson * new HTD value to setup. 32799a2dd95SBruce Richardson * @return 32899a2dd95SBruce Richardson * Zero on success, or negative error code otherwise. 32999a2dd95SBruce Richardson */ 33099a2dd95SBruce Richardson static inline int 33199a2dd95SBruce Richardson rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v) 33299a2dd95SBruce Richardson { 33399a2dd95SBruce Richardson if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS) 33499a2dd95SBruce Richardson return -ENOTSUP; 33599a2dd95SBruce Richardson 33699a2dd95SBruce Richardson r->rts_cons.htd_max = v; 33799a2dd95SBruce Richardson return 0; 33899a2dd95SBruce Richardson } 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson #ifdef __cplusplus 34199a2dd95SBruce Richardson } 34299a2dd95SBruce Richardson #endif 34399a2dd95SBruce Richardson 34499a2dd95SBruce Richardson #endif /* _RTE_RING_RTS_H_ */ 345