4 * Copyright 2017 6WIND S.A.
5 * Copyright 2017 Mellanox
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Tx queues configuration for mlx4 driver.
45 /* Verbs headers do not support -pedantic. */
47 #pragma GCC diagnostic ignored "-Wpedantic"
49 #include <infiniband/verbs.h>
51 #pragma GCC diagnostic error "-Wpedantic"
54 #include <rte_common.h>
55 #include <rte_errno.h>
56 #include <rte_ethdev.h>
57 #include <rte_malloc.h>
59 #include <rte_mempool.h>
62 #include "mlx4_autoconf.h"
63 #include "mlx4_rxtx.h"
64 #include "mlx4_utils.h"
67 * Allocate Tx queue elements.
70 * Pointer to Tx queue structure.
72 * Number of elements to allocate.
75 * 0 on success, negative errno value otherwise and rte_errno is set.
78 mlx4_txq_alloc_elts(struct txq *txq, unsigned int elts_n)
81 struct txq_elt (*elts)[elts_n] =
82 rte_calloc_socket("TXQ", 1, sizeof(*elts), 0, txq->socket);
86 ERROR("%p: can't allocate packets array", (void *)txq);
90 for (i = 0; (i != elts_n); ++i) {
91 struct txq_elt *elt = &(*elts)[i];
95 DEBUG("%p: allocated and configured %u WRs", (void *)txq, elts_n);
102 * Request send completion every MLX4_PMD_TX_PER_COMP_REQ packets or
103 * at least 4 times per ring.
105 txq->elts_comp_cd_init =
106 ((MLX4_PMD_TX_PER_COMP_REQ < (elts_n / 4)) ?
107 MLX4_PMD_TX_PER_COMP_REQ : (elts_n / 4));
108 txq->elts_comp_cd = txq->elts_comp_cd_init;
113 DEBUG("%p: failed, freed everything", (void *)txq);
120 * Free Tx queue elements.
123 * Pointer to Tx queue structure.
126 mlx4_txq_free_elts(struct txq *txq)
128 unsigned int elts_n = txq->elts_n;
129 unsigned int elts_head = txq->elts_head;
130 unsigned int elts_tail = txq->elts_tail;
131 struct txq_elt (*elts)[elts_n] = txq->elts;
133 DEBUG("%p: freeing WRs", (void *)txq);
138 txq->elts_comp_cd = 0;
139 txq->elts_comp_cd_init = 0;
143 while (elts_tail != elts_head) {
144 struct txq_elt *elt = &(*elts)[elts_tail];
146 assert(elt->buf != NULL);
147 rte_pktmbuf_free(elt->buf);
150 memset(elt, 0x77, sizeof(*elt));
152 if (++elts_tail == elts_n)
158 struct txq_mp2mr_mbuf_check_data {
163 * Callback function for rte_mempool_obj_iter() to check whether a given
164 * mempool object looks like a mbuf.
167 * The mempool pointer
169 * Context data (struct mlx4_txq_mp2mr_mbuf_check_data). Contains the
174 * Object index, unused.
177 mlx4_txq_mp2mr_mbuf_check(struct rte_mempool *mp, void *arg, void *obj,
180 struct txq_mp2mr_mbuf_check_data *data = arg;
181 struct rte_mbuf *buf = obj;
185 * Check whether mbuf structure fits element size and whether mempool
188 if (sizeof(*buf) > mp->elt_size || buf->pool != mp)
193 * Iterator function for rte_mempool_walk() to register existing mempools and
194 * fill the MP to MR cache of a Tx queue.
197 * Memory Pool to register.
199 * Pointer to Tx queue structure.
202 mlx4_txq_mp2mr_iter(struct rte_mempool *mp, void *arg)
204 struct txq *txq = arg;
205 struct txq_mp2mr_mbuf_check_data data = {
209 /* Register mempool only if the first element looks like a mbuf. */
210 if (rte_mempool_obj_iter(mp, mlx4_txq_mp2mr_mbuf_check, &data) == 0 ||
213 mlx4_txq_mp2mr(txq, mp);
217 * DPDK callback to configure a Tx queue.
220 * Pointer to Ethernet device structure.
224 * Number of descriptors to configure in queue.
226 * NUMA socket on which memory must be allocated.
228 * Thresholds parameters.
231 * 0 on success, negative errno value otherwise and rte_errno is set.
234 mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
235 unsigned int socket, const struct rte_eth_txconf *conf)
237 struct priv *priv = dev->data->dev_private;
238 struct ibv_qp_init_attr qp_init_attr;
242 (void)conf; /* Thresholds configuration (ignored). */
243 DEBUG("%p: configuring queue %u for %u descriptors",
244 (void *)dev, idx, desc);
245 if (idx >= dev->data->nb_tx_queues) {
246 rte_errno = EOVERFLOW;
247 ERROR("%p: queue index out of range (%u >= %u)",
248 (void *)dev, idx, dev->data->nb_tx_queues);
251 txq = dev->data->tx_queues[idx];
254 DEBUG("%p: Tx queue %u already configured, release it first",
260 ERROR("%p: invalid number of Tx descriptors", (void *)dev);
263 /* Allocate and initialize Tx queue. */
264 txq = rte_calloc_socket("TXQ", 1, sizeof(*txq), 0, socket);
267 ERROR("%p: unable to allocate queue index %u",
276 txq->cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
279 ERROR("%p: CQ creation failure: %s",
280 (void *)dev, strerror(rte_errno));
283 qp_init_attr = (struct ibv_qp_init_attr){
288 RTE_MIN(priv->device_attr.max_qp_wr, desc),
290 .max_inline_data = MLX4_PMD_MAX_INLINE,
292 .qp_type = IBV_QPT_RAW_PACKET,
293 /* No completion events must occur by default. */
296 txq->qp = ibv_create_qp(priv->pd, &qp_init_attr);
298 rte_errno = errno ? errno : EINVAL;
299 ERROR("%p: QP creation failure: %s",
300 (void *)dev, strerror(rte_errno));
303 txq->max_inline = qp_init_attr.cap.max_inline_data;
306 &(struct ibv_qp_attr){
307 .qp_state = IBV_QPS_INIT,
308 .port_num = priv->port,
310 IBV_QP_STATE | IBV_QP_PORT);
313 ERROR("%p: QP state to IBV_QPS_INIT failed: %s",
314 (void *)dev, strerror(rte_errno));
317 ret = mlx4_txq_alloc_elts(txq, desc);
319 ERROR("%p: TXQ allocation failed: %s",
320 (void *)dev, strerror(rte_errno));
325 &(struct ibv_qp_attr){
326 .qp_state = IBV_QPS_RTR,
331 ERROR("%p: QP state to IBV_QPS_RTR failed: %s",
332 (void *)dev, strerror(rte_errno));
337 &(struct ibv_qp_attr){
338 .qp_state = IBV_QPS_RTS,
343 ERROR("%p: QP state to IBV_QPS_RTS failed: %s",
344 (void *)dev, strerror(rte_errno));
347 /* Pre-register known mempools. */
348 rte_mempool_walk(mlx4_txq_mp2mr_iter, txq);
349 DEBUG("%p: adding Tx queue %p to list", (void *)dev, (void *)txq);
350 dev->data->tx_queues[idx] = txq;
353 dev->data->tx_queues[idx] = NULL;
355 mlx4_tx_queue_release(txq);
357 assert(rte_errno > 0);
362 * DPDK callback to release a Tx queue.
365 * Generic Tx queue pointer.
368 mlx4_tx_queue_release(void *dpdk_txq)
370 struct txq *txq = (struct txq *)dpdk_txq;
377 for (i = 0; i != priv->dev->data->nb_tx_queues; ++i)
378 if (priv->dev->data->tx_queues[i] == txq) {
379 DEBUG("%p: removing Tx queue %p from list",
380 (void *)priv->dev, (void *)txq);
381 priv->dev->data->tx_queues[i] = NULL;
384 mlx4_txq_free_elts(txq);
386 claim_zero(ibv_destroy_qp(txq->qp));
388 claim_zero(ibv_destroy_cq(txq->cq));
389 for (i = 0; i != RTE_DIM(txq->mp2mr); ++i) {
390 if (!txq->mp2mr[i].mp)
392 assert(txq->mp2mr[i].mr);
393 claim_zero(ibv_dereg_mr(txq->mp2mr[i].mr));