net/mlx5: fix secondary process Tx error
[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         /*
250          * As rdma-core, UARs are mapped in size of OS page size.
251          * Use aligned address to avoid duplicate mmap.
252          * Ref to libmlx5 function: mlx5_init_context()
253          */
254         for (i = 0; i != priv->txqs_n; ++i) {
255                 txq = (*priv->txqs)[i];
256                 txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
257                 uar_va = (uintptr_t)txq_ctrl->txq.bf_reg;
258                 uar_va = RTE_ALIGN_FLOOR(uar_va, page_size);
259                 already_mapped = 0;
260                 for (j = 0; j != pages_n; ++j) {
261                         if (pages[j] == uar_va) {
262                                 already_mapped = 1;
263                                 break;
264                         }
265                 }
266                 if (already_mapped)
267                         continue;
268                 pages[pages_n++] = uar_va;
269                 addr = mmap((void *)uar_va, page_size,
270                             PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
271                             txq_ctrl->uar_mmap_offset);
272                 if (addr != (void *)uar_va) {
273                         ERROR("call to mmap failed on UAR for txq %d\n", i);
274                         return -1;
275                 }
276         }
277         return 0;
278 }
279
280 /**
281  * Create the Tx queue Verbs object.
282  *
283  * @param priv
284  *   Pointer to private structure.
285  * @param idx
286  *   Queue index in DPDK Rx queue array
287  *
288  * @return
289  *   The Verbs object initialised if it can be created.
290  */
291 struct mlx5_txq_ibv*
292 mlx5_priv_txq_ibv_new(struct priv *priv, uint16_t idx)
293 {
294         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
295         struct mlx5_txq_ctrl *txq_ctrl =
296                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
297         struct mlx5_txq_ibv tmpl;
298         struct mlx5_txq_ibv *txq_ibv;
299         union {
300                 struct ibv_qp_init_attr_ex init;
301                 struct ibv_cq_init_attr_ex cq;
302                 struct ibv_qp_attr mod;
303                 struct ibv_cq_ex cq_attr;
304         } attr;
305         unsigned int cqe_n;
306         struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
307         struct mlx5dv_cq cq_info;
308         struct mlx5dv_obj obj;
309         const int desc = 1 << txq_data->elts_n;
310         int ret = 0;
311
312         assert(txq_data);
313         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
314                 ERROR("MLX5_ENABLE_CQE_COMPRESSION must never be set");
315                 goto error;
316         }
317         memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
318         /* MRs will be registered in mp2mr[] later. */
319         attr.cq = (struct ibv_cq_init_attr_ex){
320                 .comp_mask = 0,
321         };
322         cqe_n = ((desc / MLX5_TX_COMP_THRESH) - 1) ?
323                 ((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
324         if (priv->mps == MLX5_MPW_ENHANCED)
325                 cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
326         tmpl.cq = ibv_create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
327         if (tmpl.cq == NULL) {
328                 ERROR("%p: CQ creation failure", (void *)txq_ctrl);
329                 goto error;
330         }
331         attr.init = (struct ibv_qp_init_attr_ex){
332                 /* CQ to be associated with the send queue. */
333                 .send_cq = tmpl.cq,
334                 /* CQ to be associated with the receive queue. */
335                 .recv_cq = tmpl.cq,
336                 .cap = {
337                         /* Max number of outstanding WRs. */
338                         .max_send_wr =
339                                 ((priv->device_attr.orig_attr.max_qp_wr <
340                                   desc) ?
341                                  priv->device_attr.orig_attr.max_qp_wr :
342                                  desc),
343                         /*
344                          * Max number of scatter/gather elements in a WR,
345                          * must be 1 to prevent libmlx5 from trying to affect
346                          * too much memory. TX gather is not impacted by the
347                          * priv->device_attr.max_sge limit and will still work
348                          * properly.
349                          */
350                         .max_send_sge = 1,
351                 },
352                 .qp_type = IBV_QPT_RAW_PACKET,
353                 /*
354                  * Do *NOT* enable this, completions events are managed per
355                  * Tx burst.
356                  */
357                 .sq_sig_all = 0,
358                 .pd = priv->pd,
359                 .comp_mask = IBV_QP_INIT_ATTR_PD,
360         };
361         if (txq_data->inline_en)
362                 attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
363         if (txq_data->tso_en) {
364                 attr.init.max_tso_header = txq_ctrl->max_tso_header;
365                 attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
366         }
367         tmpl.qp = ibv_create_qp_ex(priv->ctx, &attr.init);
368         if (tmpl.qp == NULL) {
369                 ERROR("%p: QP creation failure", (void *)txq_ctrl);
370                 goto error;
371         }
372         attr.mod = (struct ibv_qp_attr){
373                 /* Move the QP to this state. */
374                 .qp_state = IBV_QPS_INIT,
375                 /* Primary port number. */
376                 .port_num = priv->port
377         };
378         ret = ibv_modify_qp(tmpl.qp, &attr.mod, (IBV_QP_STATE | IBV_QP_PORT));
379         if (ret) {
380                 ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
381                 goto error;
382         }
383         attr.mod = (struct ibv_qp_attr){
384                 .qp_state = IBV_QPS_RTR
385         };
386         ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
387         if (ret) {
388                 ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
389                 goto error;
390         }
391         attr.mod.qp_state = IBV_QPS_RTS;
392         ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
393         if (ret) {
394                 ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
395                 goto error;
396         }
397         txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
398                                     txq_ctrl->socket);
399         if (!txq_ibv) {
400                 ERROR("%p: cannot allocate memory", (void *)txq_ctrl);
401                 goto error;
402         }
403         obj.cq.in = tmpl.cq;
404         obj.cq.out = &cq_info;
405         obj.qp.in = tmpl.qp;
406         obj.qp.out = &qp;
407         ret = mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
408         if (ret != 0)
409                 goto error;
410         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
411                 ERROR("Wrong MLX5_CQE_SIZE environment variable value: "
412                       "it should be set to %u", RTE_CACHE_LINE_SIZE);
413                 goto error;
414         }
415         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
416         txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
417         txq_data->wqes = qp.sq.buf;
418         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
419         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
420         txq_data->bf_reg = qp.bf.reg;
421         txq_data->cq_db = cq_info.dbrec;
422         txq_data->cqes =
423                 (volatile struct mlx5_cqe (*)[])
424                 (uintptr_t)cq_info.buf;
425         txq_data->cq_ci = 0;
426         txq_data->cq_pi = 0;
427         txq_data->wqe_ci = 0;
428         txq_data->wqe_pi = 0;
429         txq_ibv->qp = tmpl.qp;
430         txq_ibv->cq = tmpl.cq;
431         rte_atomic32_inc(&txq_ibv->refcnt);
432         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
433                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
434         } else {
435                 ERROR("Failed to retrieve UAR info, invalid libmlx5.so version");
436                 goto error;
437         }
438         DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
439               (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
440         LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
441         return txq_ibv;
442 error:
443         if (tmpl.cq)
444                 claim_zero(ibv_destroy_cq(tmpl.cq));
445         if (tmpl.qp)
446                 claim_zero(ibv_destroy_qp(tmpl.qp));
447         return NULL;
448 }
449
450 /**
451  * Get an Tx queue Verbs object.
452  *
453  * @param priv
454  *   Pointer to private structure.
455  * @param idx
456  *   Queue index in DPDK Rx queue array
457  *
458  * @return
459  *   The Verbs object if it exists.
460  */
461 struct mlx5_txq_ibv*
462 mlx5_priv_txq_ibv_get(struct priv *priv, uint16_t idx)
463 {
464         struct mlx5_txq_ctrl *txq_ctrl;
465
466         if (idx >= priv->txqs_n)
467                 return NULL;
468         if (!(*priv->txqs)[idx])
469                 return NULL;
470         txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
471         if (txq_ctrl->ibv) {
472                 rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
473                 DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
474                       (void *)txq_ctrl->ibv,
475                       rte_atomic32_read(&txq_ctrl->ibv->refcnt));
476         }
477         return txq_ctrl->ibv;
478 }
479
480 /**
481  * Release an Tx verbs queue object.
482  *
483  * @param priv
484  *   Pointer to private structure.
485  * @param txq_ibv
486  *   Verbs Tx queue object.
487  *
488  * @return
489  *   0 on success, errno on failure.
490  */
491 int
492 mlx5_priv_txq_ibv_release(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
493 {
494         (void)priv;
495         assert(txq_ibv);
496         DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)priv,
497               (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
498         if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
499                 claim_zero(ibv_destroy_qp(txq_ibv->qp));
500                 claim_zero(ibv_destroy_cq(txq_ibv->cq));
501                 LIST_REMOVE(txq_ibv, next);
502                 rte_free(txq_ibv);
503                 return 0;
504         }
505         return EBUSY;
506 }
507
508 /**
509  * Return true if a single reference exists on the object.
510  *
511  * @param priv
512  *   Pointer to private structure.
513  * @param txq_ibv
514  *   Verbs Tx queue object.
515  */
516 int
517 mlx5_priv_txq_ibv_releasable(struct priv *priv, struct mlx5_txq_ibv *txq_ibv)
518 {
519         (void)priv;
520         assert(txq_ibv);
521         return (rte_atomic32_read(&txq_ibv->refcnt) == 1);
522 }
523
524 /**
525  * Verify the Verbs Tx queue list is empty
526  *
527  * @param priv
528  *  Pointer to private structure.
529  *
530  * @return the number of object not released.
531  */
532 int
533 mlx5_priv_txq_ibv_verify(struct priv *priv)
534 {
535         int ret = 0;
536         struct mlx5_txq_ibv *txq_ibv;
537
538         LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
539                 DEBUG("%p: Verbs Tx queue %p still referenced", (void *)priv,
540                       (void *)txq_ibv);
541                 ++ret;
542         }
543         return ret;
544 }
545
546 /**
547  * Create a DPDK Tx queue.
548  *
549  * @param priv
550  *   Pointer to private structure.
551  * @param idx
552  *   TX queue index.
553  * @param desc
554  *   Number of descriptors to configure in queue.
555  * @param socket
556  *   NUMA socket on which memory must be allocated.
557  * @param[in] conf
558  *  Thresholds parameters.
559  *
560  * @return
561  *   A DPDK queue object on success.
562  */
563 struct mlx5_txq_ctrl*
564 mlx5_priv_txq_new(struct priv *priv, uint16_t idx, uint16_t desc,
565                   unsigned int socket,
566                   const struct rte_eth_txconf *conf)
567 {
568         const unsigned int max_tso_inline =
569                 ((MLX5_MAX_TSO_HEADER + (RTE_CACHE_LINE_SIZE - 1)) /
570                  RTE_CACHE_LINE_SIZE);
571         struct mlx5_txq_ctrl *tmpl;
572
573         tmpl = rte_calloc_socket("TXQ", 1,
574                                  sizeof(*tmpl) +
575                                  desc * sizeof(struct rte_mbuf *),
576                                  0, socket);
577         if (!tmpl)
578                 return NULL;
579         assert(desc > MLX5_TX_COMP_THRESH);
580         tmpl->txq.flags = conf->txq_flags;
581         tmpl->priv = priv;
582         tmpl->txq.elts_n = log2above(desc);
583         if (priv->mps == MLX5_MPW_ENHANCED)
584                 tmpl->txq.mpw_hdr_dseg = priv->mpw_hdr_dseg;
585         /* MRs will be registered in mp2mr[] later. */
586         DEBUG("priv->device_attr.max_qp_wr is %d",
587               priv->device_attr.orig_attr.max_qp_wr);
588         DEBUG("priv->device_attr.max_sge is %d",
589               priv->device_attr.orig_attr.max_sge);
590         if (priv->txq_inline && (priv->txqs_n >= priv->txqs_inline)) {
591                 unsigned int ds_cnt;
592
593                 tmpl->txq.max_inline =
594                         ((priv->txq_inline + (RTE_CACHE_LINE_SIZE - 1)) /
595                          RTE_CACHE_LINE_SIZE);
596                 tmpl->txq.inline_en = 1;
597                 /* TSO and MPS can't be enabled concurrently. */
598                 assert(!priv->tso || !priv->mps);
599                 if (priv->mps == MLX5_MPW_ENHANCED) {
600                         tmpl->txq.inline_max_packet_sz =
601                                 priv->inline_max_packet_sz;
602                         /* To minimize the size of data set, avoid requesting
603                          * too large WQ.
604                          */
605                         tmpl->max_inline_data =
606                                 ((RTE_MIN(priv->txq_inline,
607                                           priv->inline_max_packet_sz) +
608                                   (RTE_CACHE_LINE_SIZE - 1)) /
609                                  RTE_CACHE_LINE_SIZE) * RTE_CACHE_LINE_SIZE;
610                 } else if (priv->tso) {
611                         int inline_diff = tmpl->txq.max_inline - max_tso_inline;
612
613                         /*
614                          * Adjust inline value as Verbs aggregates
615                          * tso_inline and txq_inline fields.
616                          */
617                         tmpl->max_inline_data = inline_diff > 0 ?
618                                                inline_diff *
619                                                RTE_CACHE_LINE_SIZE :
620                                                0;
621                 } else {
622                         tmpl->max_inline_data =
623                                 tmpl->txq.max_inline * RTE_CACHE_LINE_SIZE;
624                 }
625                 /*
626                  * Check if the inline size is too large in a way which
627                  * can make the WQE DS to overflow.
628                  * Considering in calculation:
629                  *      WQE CTRL (1 DS)
630                  *      WQE ETH  (1 DS)
631                  *      Inline part (N DS)
632                  */
633                 ds_cnt = 2 + (tmpl->txq.max_inline / MLX5_WQE_DWORD_SIZE);
634                 if (ds_cnt > MLX5_DSEG_MAX) {
635                         unsigned int max_inline = (MLX5_DSEG_MAX - 2) *
636                                                   MLX5_WQE_DWORD_SIZE;
637
638                         max_inline = max_inline - (max_inline %
639                                                    RTE_CACHE_LINE_SIZE);
640                         WARN("txq inline is too large (%d) setting it to "
641                              "the maximum possible: %d\n",
642                              priv->txq_inline, max_inline);
643                         tmpl->txq.max_inline = max_inline / RTE_CACHE_LINE_SIZE;
644                 }
645         }
646         if (priv->tso) {
647                 tmpl->max_tso_header = max_tso_inline * RTE_CACHE_LINE_SIZE;
648                 tmpl->txq.max_inline = RTE_MAX(tmpl->txq.max_inline,
649                                                max_tso_inline);
650                 tmpl->txq.tso_en = 1;
651         }
652         if (priv->tunnel_en)
653                 tmpl->txq.tunnel_en = 1;
654         tmpl->txq.elts =
655                 (struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
656         tmpl->txq.stats.idx = idx;
657         rte_atomic32_inc(&tmpl->refcnt);
658         DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
659               (void *)tmpl, rte_atomic32_read(&tmpl->refcnt));
660         LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
661         return tmpl;
662 }
663
664 /**
665  * Get a Tx queue.
666  *
667  * @param priv
668  *   Pointer to private structure.
669  * @param idx
670  *   TX queue index.
671  *
672  * @return
673  *   A pointer to the queue if it exists.
674  */
675 struct mlx5_txq_ctrl*
676 mlx5_priv_txq_get(struct priv *priv, uint16_t idx)
677 {
678         struct mlx5_txq_ctrl *ctrl = NULL;
679
680         if ((*priv->txqs)[idx]) {
681                 ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
682                                     txq);
683                 unsigned int i;
684
685                 mlx5_priv_txq_ibv_get(priv, idx);
686                 for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
687                         struct mlx5_mr *mr = NULL;
688
689                         (void)mr;
690                         if (ctrl->txq.mp2mr[i]) {
691                                 mr = priv_mr_get(priv, ctrl->txq.mp2mr[i]->mp);
692                                 assert(mr);
693                         }
694                 }
695                 rte_atomic32_inc(&ctrl->refcnt);
696                 DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
697                       (void *)ctrl, rte_atomic32_read(&ctrl->refcnt));
698         }
699         return ctrl;
700 }
701
702 /**
703  * Release a Tx queue.
704  *
705  * @param priv
706  *   Pointer to private structure.
707  * @param idx
708  *   TX queue index.
709  *
710  * @return
711  *   0 on success, errno on failure.
712  */
713 int
714 mlx5_priv_txq_release(struct priv *priv, uint16_t idx)
715 {
716         unsigned int i;
717         struct mlx5_txq_ctrl *txq;
718
719         if (!(*priv->txqs)[idx])
720                 return 0;
721         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
722         DEBUG("%p: Tx queue %p: refcnt %d", (void *)priv,
723               (void *)txq, rte_atomic32_read(&txq->refcnt));
724         if (txq->ibv) {
725                 int ret;
726
727                 ret = mlx5_priv_txq_ibv_release(priv, txq->ibv);
728                 if (!ret)
729                         txq->ibv = NULL;
730         }
731         for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
732                 if (txq->txq.mp2mr[i]) {
733                         priv_mr_release(priv, txq->txq.mp2mr[i]);
734                         txq->txq.mp2mr[i] = NULL;
735                 }
736         }
737         if (rte_atomic32_dec_and_test(&txq->refcnt)) {
738                 txq_free_elts(txq);
739                 LIST_REMOVE(txq, next);
740                 rte_free(txq);
741                 (*priv->txqs)[idx] = NULL;
742                 return 0;
743         }
744         return EBUSY;
745 }
746
747 /**
748  * Verify if the queue can be released.
749  *
750  * @param priv
751  *   Pointer to private structure.
752  * @param idx
753  *   TX queue index.
754  *
755  * @return
756  *   1 if the queue can be released.
757  */
758 int
759 mlx5_priv_txq_releasable(struct priv *priv, uint16_t idx)
760 {
761         struct mlx5_txq_ctrl *txq;
762
763         if (!(*priv->txqs)[idx])
764                 return -1;
765         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
766         return (rte_atomic32_read(&txq->refcnt) == 1);
767 }
768
769 /**
770  * Verify the Tx Queue list is empty
771  *
772  * @param priv
773  *  Pointer to private structure.
774  *
775  * @return the number of object not released.
776  */
777 int
778 mlx5_priv_txq_verify(struct priv *priv)
779 {
780         struct mlx5_txq_ctrl *txq;
781         int ret = 0;
782
783         LIST_FOREACH(txq, &priv->txqsctrl, next) {
784                 DEBUG("%p: Tx Queue %p still referenced", (void *)priv,
785                       (void *)txq);
786                 ++ret;
787         }
788         return ret;
789 }