New upstream version 18.08
[deb_dpdk.git] / drivers / net / mlx5 / mlx5_txq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2015 6WIND S.A.
3  * Copyright 2015 Mellanox Technologies, Ltd
4  */
5
6 #include <stddef.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <stdint.h>
11 #include <unistd.h>
12 #include <sys/mman.h>
13
14 /* Verbs header. */
15 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
16 #ifdef PEDANTIC
17 #pragma GCC diagnostic ignored "-Wpedantic"
18 #endif
19 #include <infiniband/verbs.h>
20 #ifdef PEDANTIC
21 #pragma GCC diagnostic error "-Wpedantic"
22 #endif
23
24 #include <rte_mbuf.h>
25 #include <rte_malloc.h>
26 #include <rte_ethdev_driver.h>
27 #include <rte_common.h>
28
29 #include "mlx5_utils.h"
30 #include "mlx5_defs.h"
31 #include "mlx5.h"
32 #include "mlx5_rxtx.h"
33 #include "mlx5_autoconf.h"
34 #include "mlx5_glue.h"
35
36 /**
37  * Allocate TX queue elements.
38  *
39  * @param txq_ctrl
40  *   Pointer to TX queue structure.
41  */
42 void
43 txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl)
44 {
45         const unsigned int elts_n = 1 << txq_ctrl->txq.elts_n;
46         unsigned int i;
47
48         for (i = 0; (i != elts_n); ++i)
49                 (*txq_ctrl->txq.elts)[i] = NULL;
50         DRV_LOG(DEBUG, "port %u Tx queue %u allocated and configured %u WRs",
51                 PORT_ID(txq_ctrl->priv), txq_ctrl->idx, elts_n);
52         txq_ctrl->txq.elts_head = 0;
53         txq_ctrl->txq.elts_tail = 0;
54         txq_ctrl->txq.elts_comp = 0;
55 }
56
57 /**
58  * Free TX queue elements.
59  *
60  * @param txq_ctrl
61  *   Pointer to TX queue structure.
62  */
63 static void
64 txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl)
65 {
66         const uint16_t elts_n = 1 << txq_ctrl->txq.elts_n;
67         const uint16_t elts_m = elts_n - 1;
68         uint16_t elts_head = txq_ctrl->txq.elts_head;
69         uint16_t elts_tail = txq_ctrl->txq.elts_tail;
70         struct rte_mbuf *(*elts)[elts_n] = txq_ctrl->txq.elts;
71
72         DRV_LOG(DEBUG, "port %u Tx queue %u freeing WRs",
73                 PORT_ID(txq_ctrl->priv), txq_ctrl->idx);
74         txq_ctrl->txq.elts_head = 0;
75         txq_ctrl->txq.elts_tail = 0;
76         txq_ctrl->txq.elts_comp = 0;
77
78         while (elts_tail != elts_head) {
79                 struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
80
81                 assert(elt != NULL);
82                 rte_pktmbuf_free_seg(elt);
83 #ifndef NDEBUG
84                 /* Poisoning. */
85                 memset(&(*elts)[elts_tail & elts_m],
86                        0x77,
87                        sizeof((*elts)[elts_tail & elts_m]));
88 #endif
89                 ++elts_tail;
90         }
91 }
92
93 /**
94  * Returns the per-port supported offloads.
95  *
96  * @param dev
97  *   Pointer to Ethernet device.
98  *
99  * @return
100  *   Supported Tx offloads.
101  */
102 uint64_t
103 mlx5_get_tx_port_offloads(struct rte_eth_dev *dev)
104 {
105         struct priv *priv = dev->data->dev_private;
106         uint64_t offloads = (DEV_TX_OFFLOAD_MULTI_SEGS |
107                              DEV_TX_OFFLOAD_VLAN_INSERT);
108         struct mlx5_dev_config *config = &priv->config;
109
110         if (config->hw_csum)
111                 offloads |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
112                              DEV_TX_OFFLOAD_UDP_CKSUM |
113                              DEV_TX_OFFLOAD_TCP_CKSUM);
114         if (config->tso)
115                 offloads |= DEV_TX_OFFLOAD_TCP_TSO;
116         if (config->swp) {
117                 if (config->hw_csum)
118                         offloads |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
119                 if (config->tso)
120                         offloads |= (DEV_TX_OFFLOAD_IP_TNL_TSO |
121                                      DEV_TX_OFFLOAD_UDP_TNL_TSO);
122         }
123
124         if (config->tunnel_en) {
125                 if (config->hw_csum)
126                         offloads |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
127                 if (config->tso)
128                         offloads |= (DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
129                                      DEV_TX_OFFLOAD_GRE_TNL_TSO);
130         }
131         return offloads;
132 }
133
134 /**
135  * DPDK callback to configure a TX queue.
136  *
137  * @param dev
138  *   Pointer to Ethernet device structure.
139  * @param idx
140  *   TX queue index.
141  * @param desc
142  *   Number of descriptors to configure in queue.
143  * @param socket
144  *   NUMA socket on which memory must be allocated.
145  * @param[in] conf
146  *   Thresholds parameters.
147  *
148  * @return
149  *   0 on success, a negative errno value otherwise and rte_errno is set.
150  */
151 int
152 mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
153                     unsigned int socket, const struct rte_eth_txconf *conf)
154 {
155         struct priv *priv = dev->data->dev_private;
156         struct mlx5_txq_data *txq = (*priv->txqs)[idx];
157         struct mlx5_txq_ctrl *txq_ctrl =
158                 container_of(txq, struct mlx5_txq_ctrl, txq);
159
160         if (desc <= MLX5_TX_COMP_THRESH) {
161                 DRV_LOG(WARNING,
162                         "port %u number of descriptors requested for Tx queue"
163                         " %u must be higher than MLX5_TX_COMP_THRESH, using %u"
164                         " instead of %u",
165                         dev->data->port_id, idx, MLX5_TX_COMP_THRESH + 1, desc);
166                 desc = MLX5_TX_COMP_THRESH + 1;
167         }
168         if (!rte_is_power_of_2(desc)) {
169                 desc = 1 << log2above(desc);
170                 DRV_LOG(WARNING,
171                         "port %u increased number of descriptors in Tx queue"
172                         " %u to the next power of two (%d)",
173                         dev->data->port_id, idx, desc);
174         }
175         DRV_LOG(DEBUG, "port %u configuring queue %u for %u descriptors",
176                 dev->data->port_id, idx, desc);
177         if (idx >= priv->txqs_n) {
178                 DRV_LOG(ERR, "port %u Tx queue index out of range (%u >= %u)",
179                         dev->data->port_id, idx, priv->txqs_n);
180                 rte_errno = EOVERFLOW;
181                 return -rte_errno;
182         }
183         if (!mlx5_txq_releasable(dev, idx)) {
184                 rte_errno = EBUSY;
185                 DRV_LOG(ERR, "port %u unable to release queue index %u",
186                         dev->data->port_id, idx);
187                 return -rte_errno;
188         }
189         mlx5_txq_release(dev, idx);
190         txq_ctrl = mlx5_txq_new(dev, idx, desc, socket, conf);
191         if (!txq_ctrl) {
192                 DRV_LOG(ERR, "port %u unable to allocate queue index %u",
193                         dev->data->port_id, idx);
194                 return -rte_errno;
195         }
196         DRV_LOG(DEBUG, "port %u adding Tx queue %u to list",
197                 dev->data->port_id, idx);
198         (*priv->txqs)[idx] = &txq_ctrl->txq;
199         return 0;
200 }
201
202 /**
203  * DPDK callback to release a TX queue.
204  *
205  * @param dpdk_txq
206  *   Generic TX queue pointer.
207  */
208 void
209 mlx5_tx_queue_release(void *dpdk_txq)
210 {
211         struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
212         struct mlx5_txq_ctrl *txq_ctrl;
213         struct priv *priv;
214         unsigned int i;
215
216         if (txq == NULL)
217                 return;
218         txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
219         priv = txq_ctrl->priv;
220         for (i = 0; (i != priv->txqs_n); ++i)
221                 if ((*priv->txqs)[i] == txq) {
222                         mlx5_txq_release(ETH_DEV(priv), i);
223                         DRV_LOG(DEBUG, "port %u removing Tx queue %u from list",
224                                 PORT_ID(priv), txq_ctrl->idx);
225                         break;
226                 }
227 }
228
229
230 /**
231  * Mmap TX UAR(HW doorbell) pages into reserved UAR address space.
232  * Both primary and secondary process do mmap to make UAR address
233  * aligned.
234  *
235  * @param[in] dev
236  *   Pointer to Ethernet device.
237  * @param fd
238  *   Verbs file descriptor to map UAR pages.
239  *
240  * @return
241  *   0 on success, a negative errno value otherwise and rte_errno is set.
242  */
243 int
244 mlx5_tx_uar_remap(struct rte_eth_dev *dev, int fd)
245 {
246         struct priv *priv = dev->data->dev_private;
247         unsigned int i, j;
248         uintptr_t pages[priv->txqs_n];
249         unsigned int pages_n = 0;
250         uintptr_t uar_va;
251         uintptr_t off;
252         void *addr;
253         void *ret;
254         struct mlx5_txq_data *txq;
255         struct mlx5_txq_ctrl *txq_ctrl;
256         int already_mapped;
257         size_t page_size = sysconf(_SC_PAGESIZE);
258 #ifndef RTE_ARCH_64
259         unsigned int lock_idx;
260 #endif
261
262         memset(pages, 0, priv->txqs_n * sizeof(uintptr_t));
263         /*
264          * As rdma-core, UARs are mapped in size of OS page size.
265          * Use aligned address to avoid duplicate mmap.
266          * Ref to libmlx5 function: mlx5_init_context()
267          */
268         for (i = 0; i != priv->txqs_n; ++i) {
269                 if (!(*priv->txqs)[i])
270                         continue;
271                 txq = (*priv->txqs)[i];
272                 txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
273                 assert(txq_ctrl->idx == (uint16_t)i);
274                 /* UAR addr form verbs used to find dup and offset in page. */
275                 uar_va = (uintptr_t)txq_ctrl->bf_reg_orig;
276                 off = uar_va & (page_size - 1); /* offset in page. */
277                 uar_va = RTE_ALIGN_FLOOR(uar_va, page_size); /* page addr. */
278                 already_mapped = 0;
279                 for (j = 0; j != pages_n; ++j) {
280                         if (pages[j] == uar_va) {
281                                 already_mapped = 1;
282                                 break;
283                         }
284                 }
285                 /* new address in reserved UAR address space. */
286                 addr = RTE_PTR_ADD(priv->uar_base,
287                                    uar_va & (uintptr_t)(MLX5_UAR_SIZE - 1));
288                 if (!already_mapped) {
289                         pages[pages_n++] = uar_va;
290                         /* fixed mmap to specified address in reserved
291                          * address space.
292                          */
293                         ret = mmap(addr, page_size,
294                                    PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
295                                    txq_ctrl->uar_mmap_offset);
296                         if (ret != addr) {
297                                 /* fixed mmap have to return same address */
298                                 DRV_LOG(ERR,
299                                         "port %u call to mmap failed on UAR"
300                                         " for txq %u",
301                                         dev->data->port_id, txq_ctrl->idx);
302                                 rte_errno = ENXIO;
303                                 return -rte_errno;
304                         }
305                 }
306                 if (rte_eal_process_type() == RTE_PROC_PRIMARY) /* save once */
307                         txq_ctrl->txq.bf_reg = RTE_PTR_ADD((void *)addr, off);
308                 else
309                         assert(txq_ctrl->txq.bf_reg ==
310                                RTE_PTR_ADD((void *)addr, off));
311 #ifndef RTE_ARCH_64
312                 /* Assign a UAR lock according to UAR page number */
313                 lock_idx = (txq_ctrl->uar_mmap_offset / page_size) &
314                            MLX5_UAR_PAGE_NUM_MASK;
315                 txq->uar_lock = &priv->uar_lock[lock_idx];
316 #endif
317         }
318         return 0;
319 }
320
321 /**
322  * Check if the burst function is using eMPW.
323  *
324  * @param tx_pkt_burst
325  *   Tx burst function pointer.
326  *
327  * @return
328  *   1 if the burst function is using eMPW, 0 otherwise.
329  */
330 static int
331 is_empw_burst_func(eth_tx_burst_t tx_pkt_burst)
332 {
333         if (tx_pkt_burst == mlx5_tx_burst_raw_vec ||
334             tx_pkt_burst == mlx5_tx_burst_vec ||
335             tx_pkt_burst == mlx5_tx_burst_empw)
336                 return 1;
337         return 0;
338 }
339
340 /**
341  * Create the Tx queue Verbs object.
342  *
343  * @param dev
344  *   Pointer to Ethernet device.
345  * @param idx
346  *   Queue index in DPDK Rx queue array
347  *
348  * @return
349  *   The Verbs object initialised, NULL otherwise and rte_errno is set.
350  */
351 struct mlx5_txq_ibv *
352 mlx5_txq_ibv_new(struct rte_eth_dev *dev, uint16_t idx)
353 {
354         struct priv *priv = dev->data->dev_private;
355         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
356         struct mlx5_txq_ctrl *txq_ctrl =
357                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
358         struct mlx5_txq_ibv tmpl;
359         struct mlx5_txq_ibv *txq_ibv;
360         union {
361                 struct ibv_qp_init_attr_ex init;
362                 struct ibv_cq_init_attr_ex cq;
363                 struct ibv_qp_attr mod;
364                 struct ibv_cq_ex cq_attr;
365         } attr;
366         unsigned int cqe_n;
367         struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
368         struct mlx5dv_cq cq_info;
369         struct mlx5dv_obj obj;
370         const int desc = 1 << txq_data->elts_n;
371         eth_tx_burst_t tx_pkt_burst = mlx5_select_tx_function(dev);
372         int ret = 0;
373
374         assert(txq_data);
375         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_TX_QUEUE;
376         priv->verbs_alloc_ctx.obj = txq_ctrl;
377         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
378                 DRV_LOG(ERR,
379                         "port %u MLX5_ENABLE_CQE_COMPRESSION must never be set",
380                         dev->data->port_id);
381                 rte_errno = EINVAL;
382                 return NULL;
383         }
384         memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
385         attr.cq = (struct ibv_cq_init_attr_ex){
386                 .comp_mask = 0,
387         };
388         cqe_n = ((desc / MLX5_TX_COMP_THRESH) - 1) ?
389                 ((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
390         if (is_empw_burst_func(tx_pkt_burst))
391                 cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
392         tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
393         if (tmpl.cq == NULL) {
394                 DRV_LOG(ERR, "port %u Tx queue %u CQ creation failure",
395                         dev->data->port_id, idx);
396                 rte_errno = errno;
397                 goto error;
398         }
399         attr.init = (struct ibv_qp_init_attr_ex){
400                 /* CQ to be associated with the send queue. */
401                 .send_cq = tmpl.cq,
402                 /* CQ to be associated with the receive queue. */
403                 .recv_cq = tmpl.cq,
404                 .cap = {
405                         /* Max number of outstanding WRs. */
406                         .max_send_wr =
407                                 ((priv->device_attr.orig_attr.max_qp_wr <
408                                   desc) ?
409                                  priv->device_attr.orig_attr.max_qp_wr :
410                                  desc),
411                         /*
412                          * Max number of scatter/gather elements in a WR,
413                          * must be 1 to prevent libmlx5 from trying to affect
414                          * too much memory. TX gather is not impacted by the
415                          * priv->device_attr.max_sge limit and will still work
416                          * properly.
417                          */
418                         .max_send_sge = 1,
419                 },
420                 .qp_type = IBV_QPT_RAW_PACKET,
421                 /*
422                  * Do *NOT* enable this, completions events are managed per
423                  * Tx burst.
424                  */
425                 .sq_sig_all = 0,
426                 .pd = priv->pd,
427                 .comp_mask = IBV_QP_INIT_ATTR_PD,
428         };
429         if (txq_data->max_inline)
430                 attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
431         if (txq_data->tso_en) {
432                 attr.init.max_tso_header = txq_ctrl->max_tso_header;
433                 attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
434         }
435         tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
436         if (tmpl.qp == NULL) {
437                 DRV_LOG(ERR, "port %u Tx queue %u QP creation failure",
438                         dev->data->port_id, idx);
439                 rte_errno = errno;
440                 goto error;
441         }
442         attr.mod = (struct ibv_qp_attr){
443                 /* Move the QP to this state. */
444                 .qp_state = IBV_QPS_INIT,
445                 /* Primary port number. */
446                 .port_num = 1,
447         };
448         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
449                                    (IBV_QP_STATE | IBV_QP_PORT));
450         if (ret) {
451                 DRV_LOG(ERR,
452                         "port %u Tx queue %u QP state to IBV_QPS_INIT failed",
453                         dev->data->port_id, idx);
454                 rte_errno = errno;
455                 goto error;
456         }
457         attr.mod = (struct ibv_qp_attr){
458                 .qp_state = IBV_QPS_RTR
459         };
460         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
461         if (ret) {
462                 DRV_LOG(ERR,
463                         "port %u Tx queue %u QP state to IBV_QPS_RTR failed",
464                         dev->data->port_id, idx);
465                 rte_errno = errno;
466                 goto error;
467         }
468         attr.mod.qp_state = IBV_QPS_RTS;
469         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
470         if (ret) {
471                 DRV_LOG(ERR,
472                         "port %u Tx queue %u QP state to IBV_QPS_RTS failed",
473                         dev->data->port_id, idx);
474                 rte_errno = errno;
475                 goto error;
476         }
477         txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
478                                     txq_ctrl->socket);
479         if (!txq_ibv) {
480                 DRV_LOG(ERR, "port %u Tx queue %u cannot allocate memory",
481                         dev->data->port_id, idx);
482                 rte_errno = ENOMEM;
483                 goto error;
484         }
485         obj.cq.in = tmpl.cq;
486         obj.cq.out = &cq_info;
487         obj.qp.in = tmpl.qp;
488         obj.qp.out = &qp;
489         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
490         if (ret != 0) {
491                 rte_errno = errno;
492                 goto error;
493         }
494         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
495                 DRV_LOG(ERR,
496                         "port %u wrong MLX5_CQE_SIZE environment variable"
497                         " value: it should be set to %u",
498                         dev->data->port_id, RTE_CACHE_LINE_SIZE);
499                 rte_errno = EINVAL;
500                 goto error;
501         }
502         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
503         txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
504         txq_data->wqes = qp.sq.buf;
505         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
506         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
507         txq_ctrl->bf_reg_orig = qp.bf.reg;
508         txq_data->cq_db = cq_info.dbrec;
509         txq_data->cqes =
510                 (volatile struct mlx5_cqe (*)[])
511                 (uintptr_t)cq_info.buf;
512         txq_data->cq_ci = 0;
513 #ifndef NDEBUG
514         txq_data->cq_pi = 0;
515 #endif
516         txq_data->wqe_ci = 0;
517         txq_data->wqe_pi = 0;
518         txq_ibv->qp = tmpl.qp;
519         txq_ibv->cq = tmpl.cq;
520         rte_atomic32_inc(&txq_ibv->refcnt);
521         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
522                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
523                 DRV_LOG(DEBUG, "port %u: uar_mmap_offset 0x%lx",
524                         dev->data->port_id, txq_ctrl->uar_mmap_offset);
525         } else {
526                 DRV_LOG(ERR,
527                         "port %u failed to retrieve UAR info, invalid"
528                         " libmlx5.so",
529                         dev->data->port_id);
530                 rte_errno = EINVAL;
531                 goto error;
532         }
533         LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
534         txq_ibv->txq_ctrl = txq_ctrl;
535         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
536         return txq_ibv;
537 error:
538         ret = rte_errno; /* Save rte_errno before cleanup. */
539         if (tmpl.cq)
540                 claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
541         if (tmpl.qp)
542                 claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
543         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
544         rte_errno = ret; /* Restore rte_errno. */
545         return NULL;
546 }
547
548 /**
549  * Get an Tx queue Verbs object.
550  *
551  * @param dev
552  *   Pointer to Ethernet device.
553  * @param idx
554  *   Queue index in DPDK Rx queue array
555  *
556  * @return
557  *   The Verbs object if it exists.
558  */
559 struct mlx5_txq_ibv *
560 mlx5_txq_ibv_get(struct rte_eth_dev *dev, uint16_t idx)
561 {
562         struct priv *priv = dev->data->dev_private;
563         struct mlx5_txq_ctrl *txq_ctrl;
564
565         if (idx >= priv->txqs_n)
566                 return NULL;
567         if (!(*priv->txqs)[idx])
568                 return NULL;
569         txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
570         if (txq_ctrl->ibv)
571                 rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
572         return txq_ctrl->ibv;
573 }
574
575 /**
576  * Release an Tx verbs queue object.
577  *
578  * @param txq_ibv
579  *   Verbs Tx queue object.
580  *
581  * @return
582  *   1 while a reference on it exists, 0 when freed.
583  */
584 int
585 mlx5_txq_ibv_release(struct mlx5_txq_ibv *txq_ibv)
586 {
587         assert(txq_ibv);
588         if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
589                 claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
590                 claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
591                 LIST_REMOVE(txq_ibv, next);
592                 rte_free(txq_ibv);
593                 return 0;
594         }
595         return 1;
596 }
597
598 /**
599  * Return true if a single reference exists on the object.
600  *
601  * @param txq_ibv
602  *   Verbs Tx queue object.
603  */
604 int
605 mlx5_txq_ibv_releasable(struct mlx5_txq_ibv *txq_ibv)
606 {
607         assert(txq_ibv);
608         return (rte_atomic32_read(&txq_ibv->refcnt) == 1);
609 }
610
611 /**
612  * Verify the Verbs Tx queue list is empty
613  *
614  * @param dev
615  *   Pointer to Ethernet device.
616  *
617  * @return
618  *   The number of object not released.
619  */
620 int
621 mlx5_txq_ibv_verify(struct rte_eth_dev *dev)
622 {
623         struct priv *priv = dev->data->dev_private;
624         int ret = 0;
625         struct mlx5_txq_ibv *txq_ibv;
626
627         LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
628                 DRV_LOG(DEBUG, "port %u Verbs Tx queue %u still referenced",
629                         dev->data->port_id, txq_ibv->txq_ctrl->idx);
630                 ++ret;
631         }
632         return ret;
633 }
634
635 /**
636  * Set Tx queue parameters from device configuration.
637  *
638  * @param txq_ctrl
639  *   Pointer to Tx queue control structure.
640  */
641 static void
642 txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
643 {
644         struct priv *priv = txq_ctrl->priv;
645         struct mlx5_dev_config *config = &priv->config;
646         const unsigned int max_tso_inline =
647                 ((MLX5_MAX_TSO_HEADER + (RTE_CACHE_LINE_SIZE - 1)) /
648                  RTE_CACHE_LINE_SIZE);
649         unsigned int txq_inline;
650         unsigned int txqs_inline;
651         unsigned int inline_max_packet_sz;
652         eth_tx_burst_t tx_pkt_burst =
653                 mlx5_select_tx_function(ETH_DEV(priv));
654         int is_empw_func = is_empw_burst_func(tx_pkt_burst);
655         int tso = !!(txq_ctrl->txq.offloads & (DEV_TX_OFFLOAD_TCP_TSO |
656                                                DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
657                                                DEV_TX_OFFLOAD_GRE_TNL_TSO |
658                                                DEV_TX_OFFLOAD_IP_TNL_TSO |
659                                                DEV_TX_OFFLOAD_UDP_TNL_TSO));
660
661         txq_inline = (config->txq_inline == MLX5_ARG_UNSET) ?
662                 0 : config->txq_inline;
663         txqs_inline = (config->txqs_inline == MLX5_ARG_UNSET) ?
664                 0 : config->txqs_inline;
665         inline_max_packet_sz =
666                 (config->inline_max_packet_sz == MLX5_ARG_UNSET) ?
667                 0 : config->inline_max_packet_sz;
668         if (is_empw_func) {
669                 if (config->txq_inline == MLX5_ARG_UNSET)
670                         txq_inline = MLX5_WQE_SIZE_MAX - MLX5_WQE_SIZE;
671                 if (config->txqs_inline == MLX5_ARG_UNSET)
672                         txqs_inline = MLX5_EMPW_MIN_TXQS;
673                 if (config->inline_max_packet_sz == MLX5_ARG_UNSET)
674                         inline_max_packet_sz = MLX5_EMPW_MAX_INLINE_LEN;
675                 txq_ctrl->txq.mpw_hdr_dseg = config->mpw_hdr_dseg;
676                 txq_ctrl->txq.inline_max_packet_sz = inline_max_packet_sz;
677         }
678         if (txq_inline && priv->txqs_n >= txqs_inline) {
679                 unsigned int ds_cnt;
680
681                 txq_ctrl->txq.max_inline =
682                         ((txq_inline + (RTE_CACHE_LINE_SIZE - 1)) /
683                          RTE_CACHE_LINE_SIZE);
684                 if (is_empw_func) {
685                         /* To minimize the size of data set, avoid requesting
686                          * too large WQ.
687                          */
688                         txq_ctrl->max_inline_data =
689                                 ((RTE_MIN(txq_inline,
690                                           inline_max_packet_sz) +
691                                   (RTE_CACHE_LINE_SIZE - 1)) /
692                                  RTE_CACHE_LINE_SIZE) * RTE_CACHE_LINE_SIZE;
693                 } else {
694                         txq_ctrl->max_inline_data =
695                                 txq_ctrl->txq.max_inline * RTE_CACHE_LINE_SIZE;
696                 }
697                 /*
698                  * Check if the inline size is too large in a way which
699                  * can make the WQE DS to overflow.
700                  * Considering in calculation:
701                  *      WQE CTRL (1 DS)
702                  *      WQE ETH  (1 DS)
703                  *      Inline part (N DS)
704                  */
705                 ds_cnt = 2 + (txq_ctrl->txq.max_inline / MLX5_WQE_DWORD_SIZE);
706                 if (ds_cnt > MLX5_DSEG_MAX) {
707                         unsigned int max_inline = (MLX5_DSEG_MAX - 2) *
708                                                   MLX5_WQE_DWORD_SIZE;
709
710                         max_inline = max_inline - (max_inline %
711                                                    RTE_CACHE_LINE_SIZE);
712                         DRV_LOG(WARNING,
713                                 "port %u txq inline is too large (%d) setting"
714                                 " it to the maximum possible: %d\n",
715                                 PORT_ID(priv), txq_inline, max_inline);
716                         txq_ctrl->txq.max_inline = max_inline /
717                                                    RTE_CACHE_LINE_SIZE;
718                 }
719         }
720         if (tso) {
721                 txq_ctrl->max_tso_header = max_tso_inline * RTE_CACHE_LINE_SIZE;
722                 txq_ctrl->txq.max_inline = RTE_MAX(txq_ctrl->txq.max_inline,
723                                                    max_tso_inline);
724                 txq_ctrl->txq.tso_en = 1;
725         }
726         txq_ctrl->txq.tunnel_en = config->tunnel_en | config->swp;
727         txq_ctrl->txq.swp_en = ((DEV_TX_OFFLOAD_IP_TNL_TSO |
728                                  DEV_TX_OFFLOAD_UDP_TNL_TSO |
729                                  DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) &
730                                 txq_ctrl->txq.offloads) && config->swp;
731 }
732
733 /**
734  * Create a DPDK Tx queue.
735  *
736  * @param dev
737  *   Pointer to Ethernet device.
738  * @param idx
739  *   TX queue index.
740  * @param desc
741  *   Number of descriptors to configure in queue.
742  * @param socket
743  *   NUMA socket on which memory must be allocated.
744  * @param[in] conf
745  *  Thresholds parameters.
746  *
747  * @return
748  *   A DPDK queue object on success, NULL otherwise and rte_errno is set.
749  */
750 struct mlx5_txq_ctrl *
751 mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
752              unsigned int socket, const struct rte_eth_txconf *conf)
753 {
754         struct priv *priv = dev->data->dev_private;
755         struct mlx5_txq_ctrl *tmpl;
756
757         tmpl = rte_calloc_socket("TXQ", 1,
758                                  sizeof(*tmpl) +
759                                  desc * sizeof(struct rte_mbuf *),
760                                  0, socket);
761         if (!tmpl) {
762                 rte_errno = ENOMEM;
763                 return NULL;
764         }
765         if (mlx5_mr_btree_init(&tmpl->txq.mr_ctrl.cache_bh,
766                                MLX5_MR_BTREE_CACHE_N, socket)) {
767                 /* rte_errno is already set. */
768                 goto error;
769         }
770         /* Save pointer of global generation number to check memory event. */
771         tmpl->txq.mr_ctrl.dev_gen_ptr = &priv->mr.dev_gen;
772         assert(desc > MLX5_TX_COMP_THRESH);
773         tmpl->txq.offloads = conf->offloads |
774                              dev->data->dev_conf.txmode.offloads;
775         tmpl->priv = priv;
776         tmpl->socket = socket;
777         tmpl->txq.elts_n = log2above(desc);
778         tmpl->idx = idx;
779         txq_set_params(tmpl);
780         DRV_LOG(DEBUG, "port %u priv->device_attr.max_qp_wr is %d",
781                 dev->data->port_id, priv->device_attr.orig_attr.max_qp_wr);
782         DRV_LOG(DEBUG, "port %u priv->device_attr.max_sge is %d",
783                 dev->data->port_id, priv->device_attr.orig_attr.max_sge);
784         tmpl->txq.elts =
785                 (struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
786         tmpl->txq.stats.idx = idx;
787         rte_atomic32_inc(&tmpl->refcnt);
788         LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
789         return tmpl;
790 error:
791         rte_free(tmpl);
792         return NULL;
793 }
794
795 /**
796  * Get a Tx queue.
797  *
798  * @param dev
799  *   Pointer to Ethernet device.
800  * @param idx
801  *   TX queue index.
802  *
803  * @return
804  *   A pointer to the queue if it exists.
805  */
806 struct mlx5_txq_ctrl *
807 mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
808 {
809         struct priv *priv = dev->data->dev_private;
810         struct mlx5_txq_ctrl *ctrl = NULL;
811
812         if ((*priv->txqs)[idx]) {
813                 ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
814                                     txq);
815                 mlx5_txq_ibv_get(dev, idx);
816                 rte_atomic32_inc(&ctrl->refcnt);
817         }
818         return ctrl;
819 }
820
821 /**
822  * Release a Tx queue.
823  *
824  * @param dev
825  *   Pointer to Ethernet device.
826  * @param idx
827  *   TX queue index.
828  *
829  * @return
830  *   1 while a reference on it exists, 0 when freed.
831  */
832 int
833 mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
834 {
835         struct priv *priv = dev->data->dev_private;
836         struct mlx5_txq_ctrl *txq;
837         size_t page_size = sysconf(_SC_PAGESIZE);
838
839         if (!(*priv->txqs)[idx])
840                 return 0;
841         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
842         if (txq->ibv && !mlx5_txq_ibv_release(txq->ibv))
843                 txq->ibv = NULL;
844         if (priv->uar_base)
845                 munmap((void *)RTE_ALIGN_FLOOR((uintptr_t)txq->txq.bf_reg,
846                        page_size), page_size);
847         if (rte_atomic32_dec_and_test(&txq->refcnt)) {
848                 txq_free_elts(txq);
849                 mlx5_mr_btree_free(&txq->txq.mr_ctrl.cache_bh);
850                 LIST_REMOVE(txq, next);
851                 rte_free(txq);
852                 (*priv->txqs)[idx] = NULL;
853                 return 0;
854         }
855         return 1;
856 }
857
858 /**
859  * Verify if the queue can be released.
860  *
861  * @param dev
862  *   Pointer to Ethernet device.
863  * @param idx
864  *   TX queue index.
865  *
866  * @return
867  *   1 if the queue can be released.
868  */
869 int
870 mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
871 {
872         struct priv *priv = dev->data->dev_private;
873         struct mlx5_txq_ctrl *txq;
874
875         if (!(*priv->txqs)[idx])
876                 return -1;
877         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
878         return (rte_atomic32_read(&txq->refcnt) == 1);
879 }
880
881 /**
882  * Verify the Tx Queue list is empty
883  *
884  * @param dev
885  *   Pointer to Ethernet device.
886  *
887  * @return
888  *   The number of object not released.
889  */
890 int
891 mlx5_txq_verify(struct rte_eth_dev *dev)
892 {
893         struct priv *priv = dev->data->dev_private;
894         struct mlx5_txq_ctrl *txq;
895         int ret = 0;
896
897         LIST_FOREACH(txq, &priv->txqsctrl, next) {
898                 DRV_LOG(DEBUG, "port %u Tx queue %u still referenced",
899                         dev->data->port_id, txq->idx);
900                 ++ret;
901         }
902         return ret;
903 }