diff options
Diffstat (limited to 'src/vnet/dev/queue.c')
-rw-r--r-- | src/vnet/dev/queue.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/vnet/dev/queue.c b/src/vnet/dev/queue.c new file mode 100644 index 00000000000..9a016a626fb --- /dev/null +++ b/src/vnet/dev/queue.c @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2023 Cisco Systems, Inc. + */ + +#include <vnet/vnet.h> +#include <vnet/ethernet/ethernet.h> +#include <vnet/dev/dev.h> +#include <vnet/dev/counters.h> +#include <vnet/dev/log.h> + +VLIB_REGISTER_LOG_CLASS (dev_log, static) = { + .class_name = "dev", + .subclass_name = "error", +}; + +void +vnet_dev_rx_queue_free (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq) +{ + vnet_dev_port_t *port = rxq->port; + vnet_dev_t *dev = port->dev; + log_debug (dev, "queue %u", rxq->queue_id); + if (port->rx_queue_ops.free) + port->rx_queue_ops.free (vm, rxq); + + vnet_dev_rx_queue_free_counters (vm, rxq); + pool_put_index (port->rx_queues, rxq->index); + clib_mem_free (rxq); +} + +vnet_dev_rv_t +vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port, + u16 queue_size) +{ + vnet_dev_main_t *dm = &vnet_dev_main; + vnet_dev_rx_queue_t *rxq, **qp; + vnet_dev_t *dev = port->dev; + vnet_dev_rv_t rv = VNET_DEV_OK; + u16 n_threads = vlib_get_n_threads (); + u8 buffer_pool_index; + + vnet_dev_port_validate (vm, port); + + log_debug (dev, "port %u queue_size %u", port->port_id, queue_size); + + if (pool_elts (port->rx_queues) == port->attr.max_rx_queues) + return VNET_DEV_ERR_NO_AVAIL_QUEUES; + + rxq = vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), + port->rx_queue_config.data_size); + pool_get (port->rx_queues, qp); + qp[0] = rxq; + rxq->enabled = 1; + rxq->port = port; + rxq->size = queue_size; + rxq->index = qp - port->rx_queues; + + /* default queue id - can be changed by driver */ + rxq->queue_id = qp - port->rx_queues; + ASSERT (rxq->queue_id < port->attr.max_rx_queues); + + if (n_threads > 1) + { + rxq->rx_thread_index = dm->next_rx_queue_thread++; + if (dm->next_rx_queue_thread >= n_threads) + dm->next_rx_queue_thread = 1; + } + + buffer_pool_index = + vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node); + vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index); + + rxq->buffer_template = bp->buffer_template; + vnet_buffer (&rxq->buffer_template)->sw_if_index[VLIB_TX] = ~0; + + rxq->next_index = vnet_dev_default_next_index_by_port_type[port->attr.type]; + + if (port->rx_queue_ops.alloc) + rv = port->rx_queue_ops.alloc (vm, rxq); + + if (rv != VNET_DEV_OK) + { + log_err (dev, "driver rejected rx queue add with rv %d", rv); + vnet_dev_rx_queue_free (vm, rxq); + } + else + log_debug (dev, "queue %u added, assigned to thread %u", rxq->queue_id, + rxq->rx_thread_index); + + return rv; +} + +vnet_dev_rv_t +vnet_dev_rx_queue_start (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq) +{ + vnet_dev_rv_t rv = VNET_DEV_OK; + if (rxq->port->rx_queue_ops.start) + rv = rxq->port->rx_queue_ops.start (vm, rxq); + + if (rv == VNET_DEV_OK) + rxq->started = 1; + + return rv; +} + +void +vnet_dev_rx_queue_stop (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq) +{ + if (rxq->port->rx_queue_ops.stop) + rxq->port->rx_queue_ops.stop (vm, rxq); + vlib_node_set_state (vm, rxq->port->intf.rx_node_index, + VLIB_NODE_STATE_DISABLED); + rxq->started = 0; +} + +void +vnet_dev_tx_queue_free (vlib_main_t *vm, vnet_dev_tx_queue_t *txq) +{ + vnet_dev_port_t *port = txq->port; + vnet_dev_t *dev = port->dev; + + vnet_dev_port_validate (vm, port); + + log_debug (dev, "queue %u", txq->queue_id); + if (port->tx_queue_ops.free) + port->tx_queue_ops.free (vm, txq); + + clib_bitmap_free (txq->assigned_threads); + vnet_dev_tx_queue_free_counters (vm, txq); + pool_put_index (port->tx_queues, txq->index); + clib_mem_free (txq); +} + +vnet_dev_rv_t +vnet_dev_tx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port, + u16 queue_size) +{ + vnet_dev_tx_queue_t *txq, **qp; + vnet_dev_t *dev = port->dev; + vnet_dev_rv_t rv = VNET_DEV_OK; + + log_debug (dev, "port %u size %u", port->port_id, queue_size); + + if (pool_elts (port->tx_queues) == port->attr.max_tx_queues) + return VNET_DEV_ERR_NO_AVAIL_QUEUES; + + txq = vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), + port->tx_queue_config.data_size); + pool_get (port->tx_queues, qp); + qp[0] = txq; + txq->enabled = 1; + txq->port = port; + txq->size = queue_size; + txq->index = qp - port->tx_queues; + + /* default queue id - can be changed by driver */ + txq->queue_id = qp - port->tx_queues; + ASSERT (txq->queue_id < port->attr.max_tx_queues); + + if (port->tx_queue_ops.alloc) + rv = port->tx_queue_ops.alloc (vm, txq); + + if (rv != VNET_DEV_OK) + { + log_err (dev, "driver rejected tx queue alloc with rv %d", rv); + vnet_dev_tx_queue_free (vm, txq); + } + else + log_debug (dev, "queue %u added", txq->queue_id); + + return rv; +} + +vnet_dev_rv_t +vnet_dev_tx_queue_start (vlib_main_t *vm, vnet_dev_tx_queue_t *txq) +{ + vnet_dev_rv_t rv = VNET_DEV_OK; + if (txq->port->tx_queue_ops.start) + rv = txq->port->tx_queue_ops.start (vm, txq); + + if (rv == VNET_DEV_OK) + txq->started = 1; + + return rv; +} + +void +vnet_dev_tx_queue_stop (vlib_main_t *vm, vnet_dev_tx_queue_t *txq) +{ + if (txq->port->tx_queue_ops.stop) + txq->port->tx_queue_ops.stop (vm, txq); + txq->started = 0; +} + +void +vnet_dev_rx_queue_add_counters (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq, + vnet_dev_counter_t *counters, u16 n_counters) +{ + rxq->counter_main = vnet_dev_counters_alloc ( + vm, counters, n_counters, "%s port %u rx-queue %u counters", + rxq->port->dev->device_id, rxq->port->port_id, rxq->queue_id); +} + +void +vnet_dev_rx_queue_free_counters (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq) +{ + if (rxq->counter_main) + vnet_dev_counters_free (vm, rxq->counter_main); +} + +void +vnet_dev_tx_queue_add_counters (vlib_main_t *vm, vnet_dev_tx_queue_t *txq, + vnet_dev_counter_t *counters, u16 n_counters) +{ + txq->counter_main = vnet_dev_counters_alloc ( + vm, counters, n_counters, "%s port %u tx-queue %u counters", + txq->port->dev->device_id, txq->port->port_id, txq->queue_id); +} + +void +vnet_dev_tx_queue_free_counters (vlib_main_t *vm, vnet_dev_tx_queue_t *txq) +{ + if (!txq->counter_main) + return; + + log_debug (txq->port->dev, "free"); + vnet_dev_counters_free (vm, txq->counter_main); +} |