| From 792dd52ca1a513fc16ee56b789c7e3177cb782f7 Mon Sep 17 00:00:00 2001 |
| From: Michal Krawczyk <mk@semihalf.com> |
| Date: Wed, 24 Oct 2018 11:37:17 +0200 |
| Subject: [PATCH] net/ena: recreate HW IO rings on start and stop |
| |
| On the start the driver was refilling all Rx buffs, but the old ones |
| were not released. That way running start/stop for a few times was |
| causing device to run out of descriptors. |
| |
| To fix the issue, IO rings are now being destroyed on stop, and |
| recreated on start. That is way the device is not losing any |
| descriptors. |
| |
| Furthermore, there was also memory leak for the Rx mbufs, which were |
| created on start and not destroyed on stop. |
| |
| Change-Id: I01dfd036d0bff517e42e35257481de4983679763 |
| --- |
| drivers/net/ena/ena_ethdev.c | 196 ++++++++++++++++++++----------------------- |
| 1 file changed, 91 insertions(+), 105 deletions(-) |
| |
| diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c |
| index c255dc6..de5d2ed 100644 |
| --- a/drivers/net/ena/ena_ethdev.c |
| +++ b/drivers/net/ena/ena_ethdev.c |
| @@ -239,6 +239,8 @@ static void ena_rx_queue_release_bufs(struct ena_ring *ring); |
| static void ena_tx_queue_release_bufs(struct ena_ring *ring); |
| static int ena_link_update(struct rte_eth_dev *dev, |
| int wait_to_complete); |
| +static int ena_create_io_queue(struct ena_ring *ring); |
| +static void ena_free_io_queues_all(struct ena_adapter *adapter); |
| static int ena_queue_restart(struct ena_ring *ring); |
| static int ena_queue_restart_all(struct rte_eth_dev *dev, |
| enum ena_ring_type ring_type); |
| @@ -510,7 +512,8 @@ static void ena_close(struct rte_eth_dev *dev) |
| struct ena_adapter *adapter = |
| (struct ena_adapter *)(dev->data->dev_private); |
| |
| - ena_stop(dev); |
| + if (adapter->state == ENA_ADAPTER_STATE_RUNNING) |
| + ena_stop(dev); |
| adapter->state = ENA_ADAPTER_STATE_CLOSED; |
| |
| ena_rx_queue_release_all(dev); |
| @@ -746,21 +749,12 @@ static void ena_tx_queue_release_all(struct rte_eth_dev *dev) |
| static void ena_rx_queue_release(void *queue) |
| { |
| struct ena_ring *ring = (struct ena_ring *)queue; |
| - struct ena_adapter *adapter = ring->adapter; |
| - int ena_qid; |
| |
| ena_assert_msg(ring->configured, |
| "API violation - releasing not configured queue"); |
| ena_assert_msg(ring->adapter->state != ENA_ADAPTER_STATE_RUNNING, |
| "API violation"); |
| |
| - /* Destroy HW queue */ |
| - ena_qid = ENA_IO_RXQ_IDX(ring->id); |
| - ena_com_destroy_io_queue(&adapter->ena_dev, ena_qid); |
| - |
| - /* Free all bufs */ |
| - ena_rx_queue_release_bufs(ring); |
| - |
| /* Free ring resources */ |
| if (ring->rx_buffer_info) |
| rte_free(ring->rx_buffer_info); |
| @@ -779,18 +773,12 @@ static void ena_rx_queue_release(void *queue) |
| static void ena_tx_queue_release(void *queue) |
| { |
| struct ena_ring *ring = (struct ena_ring *)queue; |
| - struct ena_adapter *adapter = ring->adapter; |
| - int ena_qid; |
| |
| ena_assert_msg(ring->configured, |
| "API violation. Releasing not configured queue"); |
| ena_assert_msg(ring->adapter->state != ENA_ADAPTER_STATE_RUNNING, |
| "API violation"); |
| |
| - /* Destroy HW queue */ |
| - ena_qid = ENA_IO_TXQ_IDX(ring->id); |
| - ena_com_destroy_io_queue(&adapter->ena_dev, ena_qid); |
| - |
| /* Free all bufs */ |
| ena_tx_queue_release_bufs(ring); |
| |
| @@ -1078,10 +1066,86 @@ static void ena_stop(struct rte_eth_dev *dev) |
| (struct ena_adapter *)(dev->data->dev_private); |
| |
| rte_timer_stop_sync(&adapter->timer_wd); |
| + ena_free_io_queues_all(adapter); |
| |
| adapter->state = ENA_ADAPTER_STATE_STOPPED; |
| } |
| |
| +static int ena_create_io_queue(struct ena_ring *ring) |
| +{ |
| + struct ena_adapter *adapter; |
| + struct ena_com_dev *ena_dev; |
| + struct ena_com_create_io_ctx ctx = |
| + /* policy set to _HOST just to satisfy icc compiler */ |
| + { ENA_ADMIN_PLACEMENT_POLICY_HOST, |
| + 0, 0, 0, 0, 0 }; |
| + uint16_t ena_qid; |
| + int rc; |
| + |
| + adapter = ring->adapter; |
| + ena_dev = &adapter->ena_dev; |
| + |
| + if (ring->type == ENA_RING_TYPE_TX) { |
| + ena_qid = ENA_IO_TXQ_IDX(ring->id); |
| + ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX; |
| + ctx.mem_queue_type = ena_dev->tx_mem_queue_type; |
| + ctx.queue_size = adapter->tx_ring_size; |
| + } else { |
| + ena_qid = ENA_IO_RXQ_IDX(ring->id); |
| + ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX; |
| + ctx.queue_size = adapter->rx_ring_size; |
| + } |
| + ctx.qid = ena_qid; |
| + ctx.msix_vector = -1; /* interrupts not used */ |
| + ctx.numa_node = ena_cpu_to_node(ring->id); |
| + |
| + rc = ena_com_create_io_queue(ena_dev, &ctx); |
| + if (rc) { |
| + RTE_LOG(ERR, PMD, |
| + "failed to create io queue #%d (qid:%d) rc: %d\n", |
| + ring->id, ena_qid, rc); |
| + return rc; |
| + } |
| + |
| + rc = ena_com_get_io_handlers(ena_dev, ena_qid, |
| + &ring->ena_com_io_sq, |
| + &ring->ena_com_io_cq); |
| + if (rc) { |
| + RTE_LOG(ERR, PMD, |
| + "Failed to get io queue handlers. queue num %d rc: %d\n", |
| + ring->id, rc); |
| + ena_com_destroy_io_queue(ena_dev, ena_qid); |
| + return rc; |
| + } |
| + |
| + if (ring->type == ENA_RING_TYPE_TX) |
| + ena_com_update_numa_node(ring->ena_com_io_cq, ctx.numa_node); |
| + |
| + return 0; |
| +} |
| + |
| +static void ena_free_io_queues_all(struct ena_adapter *adapter) |
| +{ |
| + struct rte_eth_dev *eth_dev = adapter->rte_dev; |
| + struct ena_com_dev *ena_dev = &adapter->ena_dev; |
| + int i; |
| + uint16_t ena_qid; |
| + uint16_t nb_rxq = eth_dev->data->nb_rx_queues; |
| + uint16_t nb_txq = eth_dev->data->nb_tx_queues; |
| + |
| + for (i = 0; i < nb_txq; ++i) { |
| + ena_qid = ENA_IO_TXQ_IDX(i); |
| + ena_com_destroy_io_queue(ena_dev, ena_qid); |
| + } |
| + |
| + for (i = 0; i < nb_rxq; ++i) { |
| + ena_qid = ENA_IO_RXQ_IDX(i); |
| + ena_com_destroy_io_queue(ena_dev, ena_qid); |
| + |
| + ena_rx_queue_release_bufs(&adapter->rx_ring[i]); |
| + } |
| +} |
| + |
| static int ena_queue_restart(struct ena_ring *ring) |
| { |
| int rc, bufs_num; |
| @@ -1089,6 +1153,12 @@ static int ena_queue_restart(struct ena_ring *ring) |
| ena_assert_msg(ring->configured == 1, |
| "Trying to restart unconfigured queue\n"); |
| |
| + rc = ena_create_io_queue(ring); |
| + if (rc) { |
| + PMD_INIT_LOG(ERR, "Failed to create IO queue!\n"); |
| + return rc; |
| + } |
| + |
| ring->next_to_clean = 0; |
| ring->next_to_use = 0; |
| |
| @@ -1111,17 +1181,10 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, |
| __rte_unused unsigned int socket_id, |
| const struct rte_eth_txconf *tx_conf) |
| { |
| - struct ena_com_create_io_ctx ctx = |
| - /* policy set to _HOST just to satisfy icc compiler */ |
| - { ENA_ADMIN_PLACEMENT_POLICY_HOST, |
| - ENA_COM_IO_QUEUE_DIRECTION_TX, 0, 0, 0, 0 }; |
| struct ena_ring *txq = NULL; |
| struct ena_adapter *adapter = |
| (struct ena_adapter *)(dev->data->dev_private); |
| unsigned int i; |
| - int ena_qid; |
| - int rc; |
| - struct ena_com_dev *ena_dev = &adapter->ena_dev; |
| |
| txq = &adapter->tx_ring[queue_idx]; |
| |
| @@ -1146,37 +1209,6 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, |
| return -EINVAL; |
| } |
| |
| - ena_qid = ENA_IO_TXQ_IDX(queue_idx); |
| - |
| - ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX; |
| - ctx.qid = ena_qid; |
| - ctx.msix_vector = -1; /* admin interrupts not used */ |
| - ctx.mem_queue_type = ena_dev->tx_mem_queue_type; |
| - ctx.queue_size = adapter->tx_ring_size; |
| - ctx.numa_node = ena_cpu_to_node(queue_idx); |
| - |
| - rc = ena_com_create_io_queue(ena_dev, &ctx); |
| - if (rc) { |
| - RTE_LOG(ERR, PMD, |
| - "failed to create io TX queue #%d (qid:%d) rc: %d\n", |
| - queue_idx, ena_qid, rc); |
| - return rc; |
| - } |
| - txq->ena_com_io_cq = &ena_dev->io_cq_queues[ena_qid]; |
| - txq->ena_com_io_sq = &ena_dev->io_sq_queues[ena_qid]; |
| - |
| - rc = ena_com_get_io_handlers(ena_dev, ena_qid, |
| - &txq->ena_com_io_sq, |
| - &txq->ena_com_io_cq); |
| - if (rc) { |
| - RTE_LOG(ERR, PMD, |
| - "Failed to get TX queue handlers. TX queue num %d rc: %d\n", |
| - queue_idx, rc); |
| - goto err_destroy_io_queue; |
| - } |
| - |
| - ena_com_update_numa_node(txq->ena_com_io_cq, ctx.numa_node); |
| - |
| txq->port_id = dev->data->port_id; |
| txq->next_to_clean = 0; |
| txq->next_to_use = 0; |
| @@ -1188,8 +1220,7 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, |
| RTE_CACHE_LINE_SIZE); |
| if (!txq->tx_buffer_info) { |
| RTE_LOG(ERR, PMD, "failed to alloc mem for tx buffer info\n"); |
| - rc = -ENOMEM; |
| - goto err_destroy_io_queue; |
| + return -ENOMEM; |
| } |
| |
| txq->empty_tx_reqs = rte_zmalloc("txq->empty_tx_reqs", |
| @@ -1197,8 +1228,8 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, |
| RTE_CACHE_LINE_SIZE); |
| if (!txq->empty_tx_reqs) { |
| RTE_LOG(ERR, PMD, "failed to alloc mem for tx reqs\n"); |
| - rc = -ENOMEM; |
| - goto err_free; |
| + rte_free(txq->tx_buffer_info); |
| + return -ENOMEM; |
| } |
| |
| for (i = 0; i < txq->ring_size; i++) |
| @@ -1214,13 +1245,6 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, |
| dev->data->tx_queues[queue_idx] = txq; |
| |
| return 0; |
| - |
| -err_free: |
| - rte_free(txq->tx_buffer_info); |
| - |
| -err_destroy_io_queue: |
| - ena_com_destroy_io_queue(ena_dev, ena_qid); |
| - return rc; |
| } |
| |
| static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| @@ -1230,16 +1254,10 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| __rte_unused const struct rte_eth_rxconf *rx_conf, |
| struct rte_mempool *mp) |
| { |
| - struct ena_com_create_io_ctx ctx = |
| - /* policy set to _HOST just to satisfy icc compiler */ |
| - { ENA_ADMIN_PLACEMENT_POLICY_HOST, |
| - ENA_COM_IO_QUEUE_DIRECTION_RX, 0, 0, 0, 0 }; |
| struct ena_adapter *adapter = |
| (struct ena_adapter *)(dev->data->dev_private); |
| struct ena_ring *rxq = NULL; |
| - uint16_t ena_qid = 0; |
| - int i, rc = 0; |
| - struct ena_com_dev *ena_dev = &adapter->ena_dev; |
| + int i; |
| |
| rxq = &adapter->rx_ring[queue_idx]; |
| if (rxq->configured) { |
| @@ -1263,36 +1281,6 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| return -EINVAL; |
| } |
| |
| - ena_qid = ENA_IO_RXQ_IDX(queue_idx); |
| - |
| - ctx.qid = ena_qid; |
| - ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX; |
| - ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; |
| - ctx.msix_vector = -1; /* admin interrupts not used */ |
| - ctx.queue_size = adapter->rx_ring_size; |
| - ctx.numa_node = ena_cpu_to_node(queue_idx); |
| - |
| - rc = ena_com_create_io_queue(ena_dev, &ctx); |
| - if (rc) { |
| - RTE_LOG(ERR, PMD, "failed to create io RX queue #%d rc: %d\n", |
| - queue_idx, rc); |
| - return rc; |
| - } |
| - |
| - rxq->ena_com_io_cq = &ena_dev->io_cq_queues[ena_qid]; |
| - rxq->ena_com_io_sq = &ena_dev->io_sq_queues[ena_qid]; |
| - |
| - rc = ena_com_get_io_handlers(ena_dev, ena_qid, |
| - &rxq->ena_com_io_sq, |
| - &rxq->ena_com_io_cq); |
| - if (rc) { |
| - RTE_LOG(ERR, PMD, |
| - "Failed to get RX queue handlers. RX queue num %d rc: %d\n", |
| - queue_idx, rc); |
| - ena_com_destroy_io_queue(ena_dev, ena_qid); |
| - return rc; |
| - } |
| - |
| rxq->port_id = dev->data->port_id; |
| rxq->next_to_clean = 0; |
| rxq->next_to_use = 0; |
| @@ -1304,7 +1292,6 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| RTE_CACHE_LINE_SIZE); |
| if (!rxq->rx_buffer_info) { |
| RTE_LOG(ERR, PMD, "failed to alloc mem for rx buffer info\n"); |
| - ena_com_destroy_io_queue(ena_dev, ena_qid); |
| return -ENOMEM; |
| } |
| |
| @@ -1315,7 +1302,6 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| RTE_LOG(ERR, PMD, "failed to alloc mem for empty rx reqs\n"); |
| rte_free(rxq->rx_buffer_info); |
| rxq->rx_buffer_info = NULL; |
| - ena_com_destroy_io_queue(ena_dev, ena_qid); |
| return -ENOMEM; |
| } |
| |
| @@ -1326,7 +1312,7 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, |
| rxq->configured = 1; |
| dev->data->rx_queues[queue_idx] = rxq; |
| |
| - return rc; |
| + return 0; |
| } |
| |
| static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count) |
| -- |
| 2.7.4 |
| |