9c5860ff4b16d84571588a9b54dcf9500caecb48
[deb_dpdk.git] / drivers / net / mlx5 / mlx5_txq.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
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
16  *       distribution.
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.
20  *
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.
32  */
33
34 #include <stddef.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdint.h>
39 #include <unistd.h>
40 #include <sys/mman.h>
41
42 /* Verbs header. */
43 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
44 #ifdef PEDANTIC
45 #pragma GCC diagnostic ignored "-Wpedantic"
46 #endif
47 #include <infiniband/verbs.h>
48 #ifdef PEDANTIC
49 #pragma GCC diagnostic error "-Wpedantic"
50 #endif
51
52 #include <rte_mbuf.h>
53 #include <rte_malloc.h>
54 #include <rte_ethdev.h>
55 #include <rte_common.h>
56
57 #include "mlx5_utils.h"
58 #include "mlx5_defs.h"
59 #include "mlx5.h"
60 #include "mlx5_rxtx.h"
61 #include "mlx5_autoconf.h"
62
63 /**
64  * Allocate TX queue elements.
65  *
66  * @param txq_ctrl
67  *   Pointer to TX queue structure.
68  */
69 void
70 txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl)
71 {
72         const unsigned int elts_n = 1 << txq_ctrl->txq.elts_n;
73         unsigned int i;
74
75         for (i = 0; (i != elts_n); ++i)
76                 (*txq_ctrl->txq.elts)[i] = NULL;
77         DEBUG("%p: allocated and configured %u WRs", (void *)txq_ctrl, elts_n);
78         txq_ctrl->txq.elts_head = 0;
79         txq_ctrl->txq.elts_tail = 0;
80         txq_ctrl->txq.elts_comp = 0;
81 }
82
83 /**
84  * Free TX queue elements.
85  *
86  * @param txq_ctrl
87  *   Pointer to TX queue structure.
88  */
89 static void
90 txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl)
91 {
92         const uint16_t elts_n = 1 << txq_ctrl->txq.elts_n;
93         const uint16_t elts_m = elts_n - 1;
94         uint16_t elts_head = txq_ctrl->txq.elts_head;
95         uint16_t elts_tail = txq_ctrl->txq.elts_tail;
96         struct rte_mbuf *(*elts)[elts_n] = txq_ctrl->txq.elts;
97
98         DEBUG("%p: freeing WRs", (void *)txq_ctrl);
99         txq_ctrl->txq.elts_head = 0;
100         txq_ctrl->txq.elts_tail = 0;
101         txq_ctrl->txq.elts_comp = 0;
102
103         while (elts_tail != elts_head) {
104                 struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
105
106                 assert(elt != NULL);
107                 rte_pktmbuf_free_seg(elt);
108 #ifndef NDEBUG
109                 /* Poisoning. */
110                 memset(&(*elts)[elts_tail & elts_m],
111                        0x77,
112                        sizeof((*elts)[elts_tail & elts_m]));
113 #endif
114                 ++elts_tail;
115         }
116 }
117
118 /**
119  * DPDK callback to configure a TX queue.
120  *
121  * @param dev
122  *   Pointer to Ethernet device structure.
123  * @param idx
124  *   TX queue index.
125  * @param desc
126  *   Number of descriptors to configure in queue.
127  * @param socket
128  *   NUMA socket on which memory must be allocated.
129  * @param[in] conf
130  *   Thresholds parameters.
131  *
132  * @return
133  *   0 on success, negative errno value on failure.
134  */
135 int
136 mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
137                     unsigned int socket, const struct rte_eth_txconf *conf)
138 {
139         struct priv *priv = dev->data->dev_private;
140         struct mlx5_txq_data *txq = (*priv->txqs)[idx];
141         struct mlx5_txq_ctrl *txq_ctrl =
142                 container_of(txq, struct mlx5_txq_ctrl, txq);
143         int ret = 0;
144
145         if (mlx5_is_secondary())
146                 return -E_RTE_SECONDARY;
147
148         priv_lock(priv);
149         if (desc <= MLX5_TX_COMP_THRESH) {
150                 WARN("%p: number of descriptors requested for TX queue %u"
151                      " must be higher than MLX5_TX_COMP_THRESH, using"
152                      " %u instead of %u",
153                      (void *)dev, idx, MLX5_TX_COMP_THRESH + 1, desc);
154                 desc = MLX5_TX_COMP_THRESH + 1;
155         }
156         if (!rte_is_power_of_2(desc)) {
157                 desc = 1 << log2above(desc);
158                 WARN("%p: increased number of descriptors in TX queue %u"
159                      " to the next power of two (%d)",
160                      (void *)dev, idx, desc);
161         }
162         DEBUG("%p: configuring queue %u for %u descriptors",
163               (void *)dev, idx, desc);
164         if (idx >= priv->txqs_n) {
165                 ERROR("%p: queue index out of range (%u >= %u)",
166                       (void *)dev, idx, priv->txqs_n);
167                 priv_unlock(priv);
168                 return -EOVERFLOW;
169         }
170         if (!mlx5_priv_txq_releasable(priv, idx)) {
171                 ret = EBUSY;
172                 ERROR("%p: unable to release queue index %u",
173                       (void *)dev, idx);
174                 goto out;
175         }
176         mlx5_priv_txq_release(priv, idx);
177         txq_ctrl = mlx5_priv_txq_new(priv, idx, desc, socket, conf);
178         if (!txq_ctrl) {
179                 ERROR("%p: unable to allocate queue index %u",
180                       (void *)dev, idx);
181                 ret = ENOMEM;
182                 goto out;
183         }
184         DEBUG("%p: adding TX queue %p to list",
185               (void *)dev, (void *)txq_ctrl);
186         (*priv->txqs)[idx] = &txq_ctrl->txq;
187 out:
188         priv_unlock(priv);
189         return -ret;
190 }
191
192 /**
193  * DPDK callback to release a TX queue.
194  *
195  * @param dpdk_txq
196  *   Generic TX queue pointer.
197  */
198 void
199 mlx5_tx_queue_release(void *dpdk_txq)
200 {
201         struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
202         struct mlx5_txq_ctrl *txq_ctrl;
203         struct priv *priv;
204         unsigned int i;
205
206         if (mlx5_is_secondary())
207                 return;
208
209         if (txq == NULL)
210                 return;
211         txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
212         priv = txq_ctrl->priv;
213         priv_lock(priv);
214         for (i = 0; (i != priv->txqs_n); ++i)
215                 if ((*priv->txqs)[i] == txq) {
216                         DEBUG("%p: removing TX queue %p from list",
217                               (void *)priv->dev, (void *)txq_ctrl);
218                         mlx5_priv_txq_release(priv, i);
219                         break;
220                 }
221         priv_unlock(priv);
222 }
223
224
225 /**
226  * Map locally UAR used in Tx queues for BlueFlame doorbell.
227  *
228  * @param[in] priv
229  *   Pointer to private structure.
230  * @param fd
231  *   Verbs file descriptor to map UAR pages.
232  *
233  * @return
234  *   0 on success, errno value on failure.
235  */
236 int
237 priv_tx_uar_remap(struct priv *priv, int fd)
238 {
239         unsigned int i, j;
240         uintptr_t pages[priv->txqs_n];
241         unsigned int pages_n = 0;
242         uintptr_t uar_va;
243         void *addr;
244         struct mlx5_txq_data *txq;
245         struct mlx5_txq_ctrl *txq_ctrl;
246         int already_mapped;
247         size_t page_size = sysconf(_SC_PAGESIZE);
248
249         memset(pages, 0, priv->txqs_n * sizeof(uintptr_t));
250         /*
251          * As rdma-core, UARs are mapped in size of OS page size.
252          * Use aligned address to avoid duplicate mmap.
253          * Ref to libmlx5 function: mlx5_init_context()
254          */
255         for (i = 0; i != priv->txqs_n; ++i) {
256                 txq = (*priv->txqs)[i];
257                 txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
258                 uar_va = (uintptr_t)txq_ctrl->txq.bf_reg;
259                 uar_va = RTE_ALIGN_FLOOR(uar_va, page_size);
260                 already_mapped = 0;
261                 for (j = 0; j != pages_n; ++j) {
262                         if (pages[j] == uar_va) {
263                                 already_mapped = 1;
264                                 break;
265                         }
266                 }
267                 if (already_mapped)
268                         continue;
269                 pages[pages_n++] = uar_va;
270                 addr = mmap((void *)uar_va, page_size,
271                             PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
272                             txq_ctrl->uar_mmap_offset);
273                 if (addr != (void *)uar_va) {
274                         ERROR("call to mmap failed on UAR for txq %d\n", i);
275                         return -1;
276                 }
277         }
278         return 0;
279 }
280
281 /**
282  * Create the Tx queue Verbs object.
283  *
284  * @param priv
285  *   Pointer to private structure.
286  * @param idx
287  *   Queue index in DPDK Rx queue array
288  *
289  * @return
290  *   The Verbs object initialised if it can be created.
291  */
292 struct mlx5_txq_ibv*
293 mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
294 {
295         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
296         struct mlx5_txq_ctrl *txq_ctrl =
297                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
298         struct mlx5_txq_ibv tmpl;
299         struct mlx5_txq_ibv *txq_ibv;
300         union {
301                 struct ibv_qp_init_attr_ex init;
302                 struct ibv_cq_init_attr_ex cq;
303                 struct ibv_qp_attr mod;
304                 struct ibv_cq_ex cq_attr;
305         } attr;
306         unsigned int cqe_n;
307         struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
308         struct mlx5dv_cq cq_info;
309         struct mlx5dv_obj obj;
310         const int desc = 1 << txq_data->elts_n;
311         int ret = 0;
312
313         assert(txq_data);
314         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
315                 ERROR("MLX5_ENABLE_CQE_COMPRESSION must never be set");
316                 goto error;
317         }
318         memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
319         /* MRs will be registered in mp2mr[] later. */
320         attr.cq = (struct ibv_cq_init_attr_ex){
321                 .comp_mask = 0,
322         };
323         cqe_n = ((desc / MLX5_TX_COMP_THRESH) - 1) ?
324                 ((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
325         if (priv->mps == MLX5_MPW_ENHANCED)
326                 cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
327         tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
328         if (tmpl.cq == NULL) {
329                 ERROR("%p: CQ creation failure", (void *)txq_ctrl);
330                 goto error;
331         }
332         attr.init = (struct ibv_qp_init_attr_ex){
333                 /* CQ to be associated with the send queue. */
334                 .send_cq = tmpl.cq,
335                 /* CQ to be associated with the receive queue. */
336                 .recv_cq = tmpl.cq,
337                 .cap = {
338                         /* Max number of outstanding WRs. */
339                         .max_send_wr =
340                                 ((priv->device_attr.orig_attr.max_qp_wr <
341                                   desc) ?
342                                  priv->device_attr.orig_attr.max_qp_wr :
343                                  desc),
344                         /*
345                          * Max number of scatter/gather elements in a WR,
346                          * must be 1 to prevent libmlx5 from trying to affect
347                          * too much memory. TX gather is not impacted by the
348                          * priv->device_attr.max_sge limit and will still work
349                          * properly.
350                          */
351                         .max_send_sge = 1,
352                 },
353                 .qp_type = IBV_QPT_RAW_PACKET,
354                 /*
355                  * Do *NOT* enable this, completions events are managed per
356                  * Tx burst.
357                  */
358                 .sq_sig_all = 0,
359                 .pd = priv->pd,
360                 .comp_mask = IBV_QP_INIT_ATTR_PD,
361         };
362         if (txq_data->inline_en)
363                 attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
364         if (txq_data->tso_en) {
365                 attr.init.max_tso_header = txq_ctrl->max_tso_header;
366                 attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
367         }
368         tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
369         if (tmpl.qp == NULL) {
370                 ERROR("%p: QP creation failure", (void *)txq_ctrl);
371                 goto error;
372         }
373         attr.mod = (struct ibv_qp_attr){
374                 /* Move the QP to this state. */
375                 .qp_state = IBV_QPS_INIT,
376                 /* Primary port number. */
377                 .port_num = priv->port
378         };
379         ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
380         if (ret) {
381                 ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
382                 goto error;
383         }
384         attr.mod = (struct ibv_qp_attr){
385                 .qp_state = IBV_QPS_RTR
386         };
387         ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
388         if (ret) {
389                 ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
390                 goto error;
391         }
392         attr.mod.qp_state = IBV_QPS_RTS;
393         ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
394         if (ret) {
395                 ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
396                 goto error;
397         }
398         txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
399                                     txq_ctrl->socket);
400         if (!txq_ibv) {
401                 ERROR("%p: cannot allocate memory", (void *)txq_ctrl);
402                 goto error;
403         }
404         obj.cq.in = tmpl.cq;
405         obj.cq.out = &cq_info;
406         obj.qp.in = tmpl.qp;
407         obj.qp.out = &qp;
408         ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
409         if (ret != 0)
410                 goto error;
411         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
412                 ERROR("Wrong MLX5_CQE_SIZE environment variable value: "
413                       "it should be set to %u", RTE_CACHE_LINE_SIZE);
414                 goto error;
415         }
416         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
417         txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
418         txq_data->wqes = qp.sq.buf;
419         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
420         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
421         txq_data->bf_reg = qp.bf.reg;
422         txq_data->cq_db = cq_info.dbrec;
423         txq_data->cqes =
424                 (volatile struct mlx5_cqe (*)[])
425                 (uintptr_t)cq_info.buf;
426         txq_data->cq_ci = 0;
427         txq_data->cq_pi = 0;
428         txq_data->wqe_ci = 0;
429         txq_data->wqe_pi = 0;
430         txq_ibv->qp = tmpl.qp;
431         txq_ibv->cq = tmpl.cq;
432         rte_atomic32_inc(&txq_ibv->refcnt);
433         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
434                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
435         } else {
436                 ERROR("Failed to retrieve UAR info, invalid libmlx5.so version");
437                 goto error;
438         }
439         DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
440               (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
441         LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
442         return txq_ibv;
443 error:
444         if (tmpl.cq)
445                 claim_zero(ibv_destroy_cq(tmpl.cq));
446         if (tmpl.qp)
447                 claim_zero(ibv_destroy_qp(tmpl.qp));
448         return NULL;
449 }
450
451 /**
452  * Get an Tx queue Verbs object.
453  *
454  * @param priv
455  *   Pointer to private structure.
456  * @param idx
457  *   Queue index in DPDK Rx queue array
458  *
459  * @return
460  *   The Verbs object if it exists.
461  */
462 struct mlx5_txq_ibv*
463 mlx5_priv_txq_ibv_get(struct priv *priv, uint16_t idx)
464 {
465         struct mlx5_txq_ctrl *txq_ctrl;
466
467         if (idx >= priv->txqs_n)
468                 return NULL;
469         if (!(*priv->txqs)[idx])
470                 return NULL;
471         txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
472         if (txq_ctrl->ibv) {
473                 rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
474                 DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
475                       (void *)txq_ctrl->ibv,
476                       rte_atomic32_read(&txq_ctrl->ibv->refcnt));
477         }
478         return txq_ctrl->ibv;
479 }
480
481 /**
482  * Release an Tx verbs queue object.
483  *
484  * @param priv
485  *   Pointer to private structure.
486  * @param txq_ibv
487  *   Verbs Tx queue object.
488  *
489  * @return
490  *   0 on success, errno on failure.
491  */
492 int
493 mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
494 {
495         (void)priv;
496         assert(txq_ibv);
497         DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
498               (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
499         if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
500                 claim_zero(ibv_destroy_qp(txq_ibv->qp));
501                 claim_zero(ibv_destroy_cq(txq_ibv->cq));
502                 LIST_REMOVE(txq_ibv, next);
503                 rte_free(txq_ibv);
504                 return 0;
505         }
506         return EBUSY;
507 }
508
509 /**
510  * Return true if a single reference exists on the object.
511  *
512  * @param priv
513  *   Pointer to private structure.
514  * @param txq_ibv
515  *   Verbs Tx queue object.
516  */
517 int
518 mlx5_priv_txq_ibv_releasable(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
519 {
520         (void)priv;
521         assert(txq_ibv);
522         return (rte_atomic32_read(&txq_ibv->refcnt) == 1);
523 }
524
525 /**
526  * Verify the Verbs Tx queue list is empty
527  *
528  * @param priv
529  *  Pointer to private structure.
530  *
531  * @return the number of object not released.
532  */
533 int
534 mlx5_priv_txq_ibv_verify(struct priv *priv)
535 {
536         int ret = 0;
537         struct mlx5_txq_ibv *txq_ibv;
538
539         LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
540                 DEBUG("%p: Verbs Tx queue %p still referenced", (void *)priv,
541                       (void *)txq_ibv);
542                 ++ret;
543         }
544         return ret;
545 }
546
547 /**
548  * Create a DPDK Tx queue.
549  *
550  * @param priv
551  *   Pointer to private structure.
552  * @param idx
553  *   TX queue index.
554  * @param desc
555  *   Number of descriptors to configure in queue.
556  * @param socket
557  *   NUMA socket on which memory must be allocated.
558  * @param[in] conf
559  *  Thresholds parameters.
560  *
561  * @return
562  *   A DPDK queue object on success.
563  */
564 struct mlx5_txq_ctrl*
565 mlx5_priv_txq_new(struct priv *priv, uint16_t idx, uint16_t desc,
566                   unsigned int socket,
567                   const struct rte_eth_txconf *conf)
568 {
569         const unsigned int max_tso_inline =
570                 ((MLX5_MAX_TSO_HEADER + (RTE_CACHE_LINE_SIZE - 1)) /
571                  RTE_CACHE_LINE_SIZE);
572         struct mlx5_txq_ctrl *tmpl;
573
574         tmpl = rte_calloc_socket("TXQ", 1,
575                                  sizeof(*tmpl) +
576                                  desc * sizeof(struct rte_mbuf *),
577                                  0, socket);
578         if (!tmpl)
579                 return NULL;
580         assert(desc > MLX5_TX_COMP_THRESH);
581         tmpl->txq.flags = conf->txq_flags;
582         tmpl->priv = priv;
583         tmpl->socket = socket;
584         tmpl->txq.elts_n = log2above(desc);
585         if (priv->mps == MLX5_MPW_ENHANCED)
586                 tmpl->txq.mpw_hdr_dseg = priv->mpw_hdr_dseg;
587         /* MRs will be registered in mp2mr[] later. */
588         DEBUG("priv->device_attr.max_qp_wr is %d",
589               priv->device_attr.orig_attr.max_qp_wr);
590         DEBUG("priv->device_attr.max_sge is %d",
591               priv->device_attr.orig_attr.max_sge);
592         if (priv->txq_inline && (priv->txqs_n >= priv->txqs_inline)) {
593                 unsigned int ds_cnt;
594
595                 tmpl->txq.max_inline =
596                         ((priv->txq_inline + (RTE_CACHE_LINE_SIZE - 1)) /
597                          RTE_CACHE_LINE_SIZE);
598                 tmpl->txq.inline_en = 1;
599                 /* TSO and MPS can't be enabled concurrently. */
600                 assert(!priv->tso || !priv->mps);
601                 if (priv->mps == MLX5_MPW_ENHANCED) {
602                         tmpl->txq.inline_max_packet_sz =
603                                 priv->inline_max_packet_sz;
604                         /* To minimize the size of data set, avoid requesting
605                          * too large WQ.
606                          */
607                         tmpl->max_inline_data =
608                                 ((RTE_MIN(priv->txq_inline,
609                                           priv->inline_max_packet_sz) +
610                                   (RTE_CACHE_LINE_SIZE - 1)) /
611                                  RTE_CACHE_LINE_SIZE) * RTE_CACHE_LINE_SIZE;
612                 } else if (priv->tso) {
613                         int inline_diff = tmpl->txq.max_inline - max_tso_inline;
614
615                         /*
616                          * Adjust inline value as Verbs aggregates
617                          * tso_inline and txq_inline fields.
618                          */
619                         tmpl->max_inline_data = inline_diff > 0 ?
620                                                inline_diff *
621                                                RTE_CACHE_LINE_SIZE :
622                                                0;
623                 } else {
624                         tmpl->max_inline_data =
625                                 tmpl->txq.max_inline * RTE_CACHE_LINE_SIZE;
626                 }
627                 /*
628                  * Check if the inline size is too large in a way which
629                  * can make the WQE DS to overflow.
630                  * Considering in calculation:
631                  *      WQE CTRL (1 DS)
632                  *      WQE ETH  (1 DS)
633                  *      Inline part (N DS)
634                  */
635                 ds_cnt = 2 + (tmpl->txq.max_inline / MLX5_WQE_DWORD_SIZE);
636                 if (ds_cnt > MLX5_DSEG_MAX) {
637                         unsigned int max_inline = (MLX5_DSEG_MAX - 2) *
638                                                   MLX5_WQE_DWORD_SIZE;
639
640                         max_inline = max_inline - (max_inline %
641                                                    RTE_CACHE_LINE_SIZE);
642                         WARN("txq inline is too large (%d) setting it to "
643                              "the maximum possible: %d\n",
644                              priv->txq_inline, max_inline);
645                         tmpl->txq.max_inline = max_inline / RTE_CACHE_LINE_SIZE;
646                 }
647         }
648         if (priv->tso) {
649                 tmpl->max_tso_header = max_tso_inline * RTE_CACHE_LINE_SIZE;
650                 tmpl->txq.max_inline = RTE_MAX(tmpl->txq.max_inline,
651                                                max_tso_inline);
652                 tmpl->txq.tso_en = 1;
653         }
654         if (priv->tunnel_en)
655                 tmpl->txq.tunnel_en = 1;
656         tmpl->txq.elts =
657                 (struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
658         tmpl->txq.stats.idx = idx;
659         rte_atomic32_inc(&tmpl->refcnt);
660         DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
661               (void *)tmpl, rte_atomic32_read(&tmpl->refcnt));
662         LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
663         return tmpl;
664 }
665
666 /**
667  * Get a Tx queue.
668  *
669  * @param priv
670  *   Pointer to private structure.
671  * @param idx
672  *   TX queue index.
673  *
674  * @return
675  *   A pointer to the queue if it exists.
676  */
677 struct mlx5_txq_ctrl*
678 mlx5_priv_txq_get(struct priv *priv, uint16_t idx)
679 {
680         struct mlx5_txq_ctrl *ctrl = NULL;
681
682         if ((*priv->txqs)[idx]) {
683                 ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
684                                     txq);
685                 unsigned int i;
686
687                 mlx5_priv_txq_ibv_get(priv, idx);
688                 for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
689                         struct mlx5_mr *mr = NULL;
690
691                         (void)mr;
692                         if (ctrl->txq.mp2mr[i]) {
693                                 mr = priv_mr_get(priv, ctrl->txq.mp2mr[i]->mp);
694                                 assert(mr);
695                         }
696                 }
697                 rte_atomic32_inc(&ctrl->refcnt);
698                 DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
699                       (void *)ctrl, rte_atomic32_read(&ctrl->refcnt));
700         }
701         return ctrl;
702 }
703
704 /**
705  * Release a Tx queue.
706  *
707  * @param priv
708  *   Pointer to private structure.
709  * @param idx
710  *   TX queue index.
711  *
712  * @return
713  *   0 on success, errno on failure.
714  */
715 int
716 mlx5_priv_txq_release(struct priv *priv, uint16_t idx)
717 {
718         unsigned int i;
719         struct mlx5_txq_ctrl *txq;
720
721         if (!(*priv->txqs)[idx])
722                 return 0;
723         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
724         DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
725               (void *)txq, rte_atomic32_read(&txq->refcnt));
726         if (txq->ibv) {
727                 int ret;
728
729                 ret = mlx5_priv_txq_ibv_release(priv, txq->ibv);
730                 if (!ret)
731                         txq->ibv = NULL;
732         }
733         for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
734                 if (txq->txq.mp2mr[i]) {
735                         priv_mr_release(priv, txq->txq.mp2mr[i]);
736                         txq->txq.mp2mr[i] = NULL;
737                 }
738         }
739         if (rte_atomic32_dec_and_test(&txq->refcnt)) {
740                 txq_free_elts(txq);
741                 LIST_REMOVE(txq, next);
742                 rte_free(txq);
743                 (*priv->txqs)[idx] = NULL;
744                 return 0;
745         }
746         return EBUSY;
747 }
748
749 /**
750  * Verify if the queue can be released.
751  *
752  * @param priv
753  *   Pointer to private structure.
754  * @param idx
755  *   TX queue index.
756  *
757  * @return
758  *   1 if the queue can be released.
759  */
760 int
761 mlx5_priv_txq_releasable(struct priv *priv, uint16_t idx)
762 {
763         struct mlx5_txq_ctrl *txq;
764
765         if (!(*priv->txqs)[idx])
766                 return -1;
767         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
768         return (rte_atomic32_read(&txq->refcnt) == 1);
769 }
770
771 /**
772  * Verify the Tx Queue list is empty
773  *
774  * @param priv
775  *  Pointer to private structure.
776  *
777  * @return the number of object not released.
778  */
779 int
780 mlx5_priv_txq_verify(struct priv *priv)
781 {
782         struct mlx5_txq_ctrl *txq;
783         int ret = 0;
784
785         LIST_FOREACH(txq, &priv->txqsctrl, next) {
786                 DEBUG("%p: Tx Queue %p still referenced", (void *)priv,
787                       (void *)txq);
788                 ++ret;
789         }
790         return ret;
791 }