eventdev/eth_tx: add queue start/stop API

Add support to start or stop a particular queue
that is associated with the adapter.

Start function enables the Tx adapter to start enqueueing
packets to the Tx queue.

Stop function stops the Tx adapter from enqueueing any
packets to the Tx queue. The stop API also frees any packets
that may have been buffered for this queue. All in-flight packets
destined to the queue are freed by the adapter runtime until the
queue is started again.

Signed-off-by: Naga Harish K S V <s.v.naga.harish.k@intel.com>
Acked-by: Jay Jayatheerthan <jay.jayatheerthan@intel.com>
This commit is contained in:
Naga Harish K S V 2022-09-25 21:04:12 -05:00 committed by Jerin Jacob
parent 2367e7e0cf
commit 3c3328aef3
7 changed files with 323 additions and 4 deletions

View File

@ -711,6 +711,90 @@ tx_adapter_instance_get(void)
return TEST_SUCCESS;
}
static int
tx_adapter_queue_start_stop(void)
{
int err;
uint16_t eth_dev_id;
struct rte_eth_dev_info dev_info;
/* Case 1: Test without adding eth Tx queue */
err = rte_event_eth_tx_adapter_queue_start(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
err = rte_event_eth_tx_adapter_queue_stop(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
/* Case 2: Test with wrong eth port */
eth_dev_id = rte_eth_dev_count_total() + 1;
err = rte_event_eth_tx_adapter_queue_start(eth_dev_id,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
err = rte_event_eth_tx_adapter_queue_stop(eth_dev_id,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
/* Case 3: Test with wrong tx queue */
err = rte_eth_dev_info_get(TEST_ETHDEV_ID, &dev_info);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
err = rte_event_eth_tx_adapter_queue_start(TEST_ETHDEV_ID,
dev_info.max_tx_queues + 1);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
err = rte_event_eth_tx_adapter_queue_stop(TEST_ETHDEV_ID,
dev_info.max_tx_queues + 1);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
/* Case 4: Test with right instance, port & rxq */
/* Add queue to tx adapter */
err = rte_event_eth_tx_adapter_queue_add(TEST_INST_ID,
TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
err = rte_event_eth_tx_adapter_queue_stop(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
err = rte_event_eth_tx_adapter_queue_start(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
/* Add another queue to tx adapter */
err = rte_event_eth_tx_adapter_queue_add(TEST_INST_ID,
TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID + 1);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
err = rte_event_eth_tx_adapter_queue_stop(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID + 1);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
err = rte_event_eth_tx_adapter_queue_start(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID + 1);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
/* Case 5: Test with right instance, port & wrong rxq */
err = rte_event_eth_tx_adapter_queue_stop(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID + 2);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
err = rte_event_eth_tx_adapter_queue_start(TEST_ETHDEV_ID,
TEST_ETH_QUEUE_ID + 2);
TEST_ASSERT(err == -EINVAL, "Expected -EINVAL got %d", err);
/* Delete all queues from the Tx adapter */
err = rte_event_eth_tx_adapter_queue_del(TEST_INST_ID,
TEST_ETHDEV_ID,
-1);
TEST_ASSERT(err == 0, "Expected 0 got %d", err);
return TEST_SUCCESS;
}
static int
tx_adapter_dynamic_device(void)
{
@ -770,6 +854,8 @@ static struct unit_test_suite event_eth_tx_tests = {
tx_adapter_service),
TEST_CASE_ST(tx_adapter_create, tx_adapter_free,
tx_adapter_instance_get),
TEST_CASE_ST(tx_adapter_create, tx_adapter_free,
tx_adapter_queue_start_stop),
TEST_CASE_ST(NULL, NULL, tx_adapter_dynamic_device),
TEST_CASES_END() /**< NULL terminate unit test array */
}

View File

@ -182,3 +182,28 @@ mbufs are destined to the same ethernet port and queue by setting the bit
``rte_event_vector::queue``.
If ``rte_event_vector::attr_valid`` is not set then the Tx adapter should peek
into each mbuf and transmit them to the requested ethernet port and queue pair.
Queue start/stop
~~~~~~~~~~~~~~~~
The adapter can be configured to start/stop enqueueing of packets to a
associated NIC queue using ``rte_event_eth_tx_adapter_queue_start()`` or
``rte_event_eth_tx_adapter_queue_stop()`` respectively. By default the queue
is in start state.
These APIs help avoid some unexpected behavior with application stopping ethdev
Tx queues and adapter being unaware of it. With these APIs, the application can
call stop API to notify adapter that corresponding ethdev Tx queue is stopped
and any in-flight packets are freed by adapter dataplane code. Adapter queue
stop API is called before stopping the ethdev Tx queue. When ethdev Tx queue
is enabled, application can notify adapter to resume processing of the packets
for that queue by calling the start API. The ethdev Tx queue is started before
calling adapter start API.
Start function enables the adapter runtime to start enqueueing of packets
to the Tx queue.
Stop function stops the adapter runtime function from enqueueing any
packets to the associated Tx queue. This API also frees any packets that
may have been buffered for this queue. All inflight packets destined to the
queue are freed by the adapter runtime until the queue is started again.

View File

@ -80,6 +80,13 @@ New Features
* Added ``rte_event_eth_tx_adapter_instance_get`` to get Tx adapter
instance ID for specified ethernet device ID and Tx queue index.
* **Added eventdev Tx adapter queue start/stop API.**
* Added ``rte_event_eth_tx_adapter_queue_start`` to start
enqueueing packets to the Tx queue by Tx adapter.
* Added ``rte_event_eth_tx_adapter_queue_stop`` to stop the Tx Adapter
from enqueueing any packets to the Tx queue.
Removed Items
-------------

View File

@ -1277,6 +1277,43 @@ typedef int (*eventdev_eth_tx_adapter_stats_reset_t)(uint8_t id,
typedef int (*eventdev_eth_tx_adapter_instance_get_t)
(uint16_t eth_dev_id, uint16_t tx_queue_id, uint8_t *txa_inst_id);
/**
* Start a Tx queue that is assigned to Tx adapter instance
*
* @param id
* Adapter identifier
*
* @param eth_dev_id
* Port identifier of Ethernet device
*
* @param tx_queue_id
* Ethernet device Tx queue index
*
* @return
* - 0: Success
* - <0: Error code on failure
*/
typedef int (*eventdev_eth_tx_adapter_queue_start)
(uint8_t id, uint16_t eth_dev_id, uint16_t tx_queue_id);
/**
* Stop a Tx queue that is assigned to Tx adapter instance
*
* @param id
* Adapter identifier
*
* @param eth_dev_id
* Port identifier of Ethernet device
*
* @param tx_queue_id
* Ethernet device Tx queue index
*
* @return
* - 0: Success
* - <0: Error code on failure
*/
typedef int (*eventdev_eth_tx_adapter_queue_stop)
(uint8_t id, uint16_t eth_dev_id, uint16_t tx_queue_id);
/** Event device operations function pointer table */
struct eventdev_ops {
@ -1390,6 +1427,10 @@ struct eventdev_ops {
/**< Reset eth Tx adapter statistics */
eventdev_eth_tx_adapter_instance_get_t eth_tx_adapter_instance_get;
/**< Get Tx adapter instance ID for Tx queue */
eventdev_eth_tx_adapter_queue_start eth_tx_adapter_queue_start;
/**< Start Tx queue assigned to Tx adapter instance */
eventdev_eth_tx_adapter_queue_stop eth_tx_adapter_queue_stop;
/**< Stop Tx queue assigned to Tx adapter instance */
eventdev_selftest dev_selftest;
/**< Start eventdev Selftest */

View File

@ -47,6 +47,12 @@
#define txa_dev_instance_get(id) \
txa_evdev(id)->dev_ops->eth_tx_adapter_instance_get
#define txa_dev_queue_start(id) \
txa_evdev(id)->dev_ops->eth_tx_adapter_queue_start
#define txa_dev_queue_stop(id) \
txa_evdev(id)->dev_ops->eth_tx_adapter_queue_stop
#define RTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET(id, retval) \
do { \
if (!txa_valid_id(id)) { \
@ -94,6 +100,8 @@ struct txa_retry {
struct txa_service_queue_info {
/* Queue has been added */
uint8_t added;
/* Queue is stopped */
bool stopped;
/* Retry callback argument */
struct txa_retry txa_retry;
/* Tx buffer */
@ -556,7 +564,7 @@ txa_process_event_vector(struct txa_service_data *txa,
port = vec->port;
queue = vec->queue;
tqi = txa_service_queue(txa, port, queue);
if (unlikely(tqi == NULL || !tqi->added)) {
if (unlikely(tqi == NULL || !tqi->added || tqi->stopped)) {
rte_pktmbuf_free_bulk(&mbufs[vec->elem_offset],
vec->nb_elem);
rte_mempool_put(rte_mempool_from_obj(vec), vec);
@ -572,7 +580,8 @@ txa_process_event_vector(struct txa_service_data *txa,
port = mbufs[i]->port;
queue = rte_event_eth_tx_adapter_txq_get(mbufs[i]);
tqi = txa_service_queue(txa, port, queue);
if (unlikely(tqi == NULL || !tqi->added)) {
if (unlikely(tqi == NULL || !tqi->added ||
tqi->stopped)) {
rte_pktmbuf_free(mbufs[i]);
continue;
}
@ -609,7 +618,8 @@ txa_service_tx(struct txa_service_data *txa, struct rte_event *ev,
queue = rte_event_eth_tx_adapter_txq_get(m);
tqi = txa_service_queue(txa, port, queue);
if (unlikely(tqi == NULL || !tqi->added)) {
if (unlikely(tqi == NULL || !tqi->added ||
tqi->stopped)) {
rte_pktmbuf_free(m);
continue;
}
@ -673,7 +683,8 @@ txa_service_func(void *args)
for (q = 0; q < dev->data->nb_tx_queues; q++) {
tqi = txa_service_queue(txa, i, q);
if (unlikely(tqi == NULL || !tqi->added))
if (unlikely(tqi == NULL || !tqi->added ||
tqi->stopped))
continue;
nb_tx += rte_eth_tx_buffer_flush(i, q,
@ -868,6 +879,7 @@ txa_service_queue_add(uint8_t id,
tqi->tx_buf = tb;
tqi->added = 1;
tqi->stopped = false;
tdi->nb_queues++;
txa->nb_queues++;
@ -886,6 +898,20 @@ txa_service_queue_add(uint8_t id,
return -1;
}
static inline void
txa_txq_buffer_drain(struct txa_service_queue_info *tqi)
{
struct rte_eth_dev_tx_buffer *b;
uint16_t i;
b = tqi->tx_buf;
for (i = 0; i < b->length; i++)
rte_pktmbuf_free(b->pkts[i]);
b->length = 0;
}
static int
txa_service_queue_del(uint8_t id,
const struct rte_eth_dev *dev,
@ -931,6 +957,8 @@ txa_service_queue_del(uint8_t id,
if (tqi == NULL || !tqi->added)
goto ret_unlock;
/* Drain the buffered mbufs */
txa_txq_buffer_drain(tqi);
tb = tqi->tx_buf;
tqi->added = 0;
tqi->tx_buf = NULL;
@ -1321,3 +1349,79 @@ rte_event_eth_tx_adapter_instance_get(uint16_t eth_dev_id,
return -EINVAL;
}
static inline int
txa_sw_queue_start_state_set(uint16_t eth_dev_id, uint16_t tx_queue_id,
bool start_state, struct txa_service_data *txa)
{
struct txa_service_queue_info *tqi = NULL;
rte_spinlock_lock(&txa->tx_lock);
tqi = txa_service_queue(txa, eth_dev_id, tx_queue_id);
if (unlikely(tqi == NULL || !tqi->added)) {
rte_spinlock_unlock(&txa->tx_lock);
return -EINVAL;
}
if (start_state == false)
txa_txq_buffer_drain(tqi);
tqi->stopped = !start_state;
rte_spinlock_unlock(&txa->tx_lock);
return 0;
}
static int
txa_queue_start_state_set(uint16_t eth_dev_id, uint16_t tx_queue_id,
bool start_state)
{
struct txa_service_data *txa;
uint8_t txa_inst_id;
int ret;
uint32_t caps = 0;
/* Below API already does validation of input parameters.
* Hence skipping the validation here.
*/
ret = rte_event_eth_tx_adapter_instance_get(eth_dev_id,
tx_queue_id,
&txa_inst_id);
if (ret < 0)
return -EINVAL;
txa = txa_service_id_to_data(txa_inst_id);
ret = rte_event_eth_tx_adapter_caps_get(txa->eventdev_id,
eth_dev_id,
&caps);
if (ret < 0)
return -EINVAL;
if (caps & RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT) {
if (start_state == true) {
ret = txa_dev_queue_start(txa_inst_id) ?
txa_dev_queue_start(txa_inst_id)(txa_inst_id,
eth_dev_id,
tx_queue_id) : 0;
} else {
ret = txa_dev_queue_stop(txa_inst_id) ?
txa_dev_queue_stop(txa_inst_id)(txa_inst_id,
eth_dev_id,
tx_queue_id) : 0;
}
return ret;
}
return txa_sw_queue_start_state_set(eth_dev_id, tx_queue_id,
start_state, txa);
}
int
rte_event_eth_tx_adapter_queue_start(uint16_t eth_dev_id, uint16_t tx_queue_id)
{
return txa_queue_start_state_set(eth_dev_id, tx_queue_id, true);
}
int
rte_event_eth_tx_adapter_queue_stop(uint16_t eth_dev_id, uint16_t tx_queue_id)
{
return txa_queue_start_state_set(eth_dev_id, tx_queue_id, false);
}

View File

@ -35,6 +35,8 @@
* - rte_event_eth_tx_adapter_event_port_get()
* - rte_event_eth_tx_adapter_service_id_get()
* - rte_event_eth_tx_adapter_instance_get()
* - rte_event_eth_tx_adapter_queue_start()
* - rte_event_eth_tx_adapter_queue_stop()
*
* The application creates the adapter using
* rte_event_eth_tx_adapter_create() or rte_event_eth_tx_adapter_create_ext().
@ -446,6 +448,58 @@ int
rte_event_eth_tx_adapter_instance_get(uint16_t eth_dev_id,
uint16_t tx_queue_id,
uint8_t *txa_inst_id);
/**
* Enables the adapter to start enqueueing of packets to the
* Tx queue.
*
* This function is provided so that the application can
* resume enqueueing packets that reference packets for
* <eth_dev_id, tx_queue_id> after calling
* rte_event_eth_tx_adapter_queue_stop().
* @see rte_event_eth_tx_adapter_queue_stop
*
* Use case:
* --------
* The queue start/stop APIs help avoid some unexpected behavior with
* application stopping ethdev Tx queues and adapter being unaware of it.
* With these APIs, the application can call stop API to notify adapter
* that corresponding ethdev Tx queue is stopped and any in-flight
* packets are freed by adapter dataplane code. Adapter queue stop API
* is called before stopping the ethdev Tx queue. When ethdev Tx queue
* is enabled, application can notify adapter to resume processing of
* the packets for that queue by calling the start API. The ethdev Tx
* queue is started before calling adapter start API.
*
* @param eth_dev_id
* Port identifier of Ethernet device.
* @param tx_queue_id
* Ethernet device transmit queue index.
* @return
* - 0: Success
* - <0: Error code on failure
*/
__rte_experimental
int
rte_event_eth_tx_adapter_queue_start(uint16_t eth_dev_id, uint16_t tx_queue_id);
/**
* Stops the adapter runtime function from enqueueing any packets
* to the associated Tx queue. This API also frees any packets that may
* have been buffered for this queue. All inflight packets destined to the
* queue are freed by the adapter runtime until the queue is started again.
* @see rte_event_eth_tx_adapter_queue_start
*
* @param eth_dev_id
* Port identifier of Ethernet device.
* @param tx_queue_id
* Ethernet device transmit queue index.
* @return
* - 0: Success
* - <0: Error code on failure
*/
__rte_experimental
int
rte_event_eth_tx_adapter_queue_stop(uint16_t eth_dev_id, uint16_t tx_queue_id);
#ifdef __cplusplus
}

View File

@ -116,6 +116,8 @@ EXPERIMENTAL {
# added in 22.11
rte_event_eth_rx_adapter_instance_get;
rte_event_eth_tx_adapter_instance_get;
rte_event_eth_tx_adapter_queue_start;
rte_event_eth_tx_adapter_queue_stop;
};
INTERNAL {