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