net/mlx5: add Tx configuration and setup
[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  * Create the Tx queue Verbs object.
369  *
370  * @param dev
371  *   Pointer to Ethernet device.
372  * @param idx
373  *   Queue index in DPDK Tx queue array.
374  *
375  * @return
376  *   The Verbs object initialised, NULL otherwise and rte_errno is set.
377  */
378 struct mlx5_txq_ibv *
379 mlx5_txq_ibv_new(struct rte_eth_dev *dev, uint16_t idx)
380 {
381         struct mlx5_priv *priv = dev->data->dev_private;
382         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
383         struct mlx5_txq_ctrl *txq_ctrl =
384                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
385         struct mlx5_txq_ibv tmpl;
386         struct mlx5_txq_ibv *txq_ibv = NULL;
387         union {
388                 struct ibv_qp_init_attr_ex init;
389                 struct ibv_cq_init_attr_ex cq;
390                 struct ibv_qp_attr mod;
391                 struct ibv_cq_ex cq_attr;
392         } attr;
393         unsigned int cqe_n;
394         struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
395         struct mlx5dv_cq cq_info;
396         struct mlx5dv_obj obj;
397         const int desc = 1 << txq_data->elts_n;
398         int ret = 0;
399
400         assert(txq_data);
401         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_TX_QUEUE;
402         priv->verbs_alloc_ctx.obj = txq_ctrl;
403         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
404                 DRV_LOG(ERR,
405                         "port %u MLX5_ENABLE_CQE_COMPRESSION must never be set",
406                         dev->data->port_id);
407                 rte_errno = EINVAL;
408                 return NULL;
409         }
410         memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
411         attr.cq = (struct ibv_cq_init_attr_ex){
412                 .comp_mask = 0,
413         };
414         cqe_n = desc / MLX5_TX_COMP_THRESH +
415                 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
416         tmpl.cq = mlx5_glue->create_cq(priv->sh->ctx, cqe_n, NULL, NULL, 0);
417         if (tmpl.cq == NULL) {
418                 DRV_LOG(ERR, "port %u Tx queue %u CQ creation failure",
419                         dev->data->port_id, idx);
420                 rte_errno = errno;
421                 goto error;
422         }
423         attr.init = (struct ibv_qp_init_attr_ex){
424                 /* CQ to be associated with the send queue. */
425                 .send_cq = tmpl.cq,
426                 /* CQ to be associated with the receive queue. */
427                 .recv_cq = tmpl.cq,
428                 .cap = {
429                         /* Max number of outstanding WRs. */
430                         .max_send_wr =
431                                 ((priv->sh->device_attr.orig_attr.max_qp_wr <
432                                   desc) ?
433                                  priv->sh->device_attr.orig_attr.max_qp_wr :
434                                  desc),
435                         /*
436                          * Max number of scatter/gather elements in a WR,
437                          * must be 1 to prevent libmlx5 from trying to affect
438                          * too much memory. TX gather is not impacted by the
439                          * device_attr.max_sge limit and will still work
440                          * properly.
441                          */
442                         .max_send_sge = 1,
443                 },
444                 .qp_type = IBV_QPT_RAW_PACKET,
445                 /*
446                  * Do *NOT* enable this, completions events are managed per
447                  * Tx burst.
448                  */
449                 .sq_sig_all = 0,
450                 .pd = priv->sh->pd,
451                 .comp_mask = IBV_QP_INIT_ATTR_PD,
452         };
453         if (txq_data->inlen_send)
454                 attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
455         if (txq_data->tso_en) {
456                 attr.init.max_tso_header = txq_ctrl->max_tso_header;
457                 attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
458         }
459         tmpl.qp = mlx5_glue->create_qp_ex(priv->sh->ctx, &attr.init);
460         if (tmpl.qp == NULL) {
461                 DRV_LOG(ERR, "port %u Tx queue %u QP creation failure",
462                         dev->data->port_id, idx);
463                 rte_errno = errno;
464                 goto error;
465         }
466         attr.mod = (struct ibv_qp_attr){
467                 /* Move the QP to this state. */
468                 .qp_state = IBV_QPS_INIT,
469                 /* IB device port number. */
470                 .port_num = (uint8_t)priv->ibv_port,
471         };
472         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
473                                    (IBV_QP_STATE | IBV_QP_PORT));
474         if (ret) {
475                 DRV_LOG(ERR,
476                         "port %u Tx queue %u QP state to IBV_QPS_INIT failed",
477                         dev->data->port_id, idx);
478                 rte_errno = errno;
479                 goto error;
480         }
481         attr.mod = (struct ibv_qp_attr){
482                 .qp_state = IBV_QPS_RTR
483         };
484         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
485         if (ret) {
486                 DRV_LOG(ERR,
487                         "port %u Tx queue %u QP state to IBV_QPS_RTR failed",
488                         dev->data->port_id, idx);
489                 rte_errno = errno;
490                 goto error;
491         }
492         attr.mod.qp_state = IBV_QPS_RTS;
493         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
494         if (ret) {
495                 DRV_LOG(ERR,
496                         "port %u Tx queue %u QP state to IBV_QPS_RTS failed",
497                         dev->data->port_id, idx);
498                 rte_errno = errno;
499                 goto error;
500         }
501         txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
502                                     txq_ctrl->socket);
503         if (!txq_ibv) {
504                 DRV_LOG(ERR, "port %u Tx queue %u cannot allocate memory",
505                         dev->data->port_id, idx);
506                 rte_errno = ENOMEM;
507                 goto error;
508         }
509         obj.cq.in = tmpl.cq;
510         obj.cq.out = &cq_info;
511         obj.qp.in = tmpl.qp;
512         obj.qp.out = &qp;
513         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
514         if (ret != 0) {
515                 rte_errno = errno;
516                 goto error;
517         }
518         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
519                 DRV_LOG(ERR,
520                         "port %u wrong MLX5_CQE_SIZE environment variable"
521                         " value: it should be set to %u",
522                         dev->data->port_id, RTE_CACHE_LINE_SIZE);
523                 rte_errno = EINVAL;
524                 goto error;
525         }
526         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
527         txq_data->cqe_s = 1 << txq_data->cqe_n;
528         txq_data->cqe_m = txq_data->cqe_s - 1;
529         txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
530         txq_data->wqes = qp.sq.buf;
531         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
532         txq_data->wqe_s = 1 << txq_data->wqe_n;
533         txq_data->wqe_m = txq_data->wqe_s - 1;
534         txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s;
535         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
536         txq_data->cq_db = cq_info.dbrec;
537         txq_data->cqes = (volatile struct mlx5_cqe *)cq_info.buf;
538         txq_data->cq_ci = 0;
539 #ifndef NDEBUG
540         txq_data->cq_pi = 0;
541 #endif
542         txq_data->wqe_ci = 0;
543         txq_data->wqe_pi = 0;
544         txq_data->wqe_comp = 0;
545         txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV;
546         txq_ibv->qp = tmpl.qp;
547         txq_ibv->cq = tmpl.cq;
548         rte_atomic32_inc(&txq_ibv->refcnt);
549         txq_ctrl->bf_reg = qp.bf.reg;
550         txq_uar_init(txq_ctrl);
551         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
552                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
553                 DRV_LOG(DEBUG, "port %u: uar_mmap_offset 0x%"PRIx64,
554                         dev->data->port_id, txq_ctrl->uar_mmap_offset);
555         } else {
556                 DRV_LOG(ERR,
557                         "port %u failed to retrieve UAR info, invalid"
558                         " libmlx5.so",
559                         dev->data->port_id);
560                 rte_errno = EINVAL;
561                 goto error;
562         }
563         LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
564         txq_ibv->txq_ctrl = txq_ctrl;
565         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
566         return txq_ibv;
567 error:
568         ret = rte_errno; /* Save rte_errno before cleanup. */
569         if (tmpl.cq)
570                 claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
571         if (tmpl.qp)
572                 claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
573         if (txq_ibv)
574                 rte_free(txq_ibv);
575         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
576         rte_errno = ret; /* Restore rte_errno. */
577         return NULL;
578 }
579
580 /**
581  * Get an Tx queue Verbs object.
582  *
583  * @param dev
584  *   Pointer to Ethernet device.
585  * @param idx
586  *   Queue index in DPDK Tx queue array.
587  *
588  * @return
589  *   The Verbs object if it exists.
590  */
591 struct mlx5_txq_ibv *
592 mlx5_txq_ibv_get(struct rte_eth_dev *dev, uint16_t idx)
593 {
594         struct mlx5_priv *priv = dev->data->dev_private;
595         struct mlx5_txq_ctrl *txq_ctrl;
596
597         if (idx >= priv->txqs_n)
598                 return NULL;
599         if (!(*priv->txqs)[idx])
600                 return NULL;
601         txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
602         if (txq_ctrl->ibv)
603                 rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
604         return txq_ctrl->ibv;
605 }
606
607 /**
608  * Release an Tx verbs queue object.
609  *
610  * @param txq_ibv
611  *   Verbs Tx queue object.
612  *
613  * @return
614  *   1 while a reference on it exists, 0 when freed.
615  */
616 int
617 mlx5_txq_ibv_release(struct mlx5_txq_ibv *txq_ibv)
618 {
619         assert(txq_ibv);
620         if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
621                 claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
622                 claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
623                 LIST_REMOVE(txq_ibv, next);
624                 rte_free(txq_ibv);
625                 return 0;
626         }
627         return 1;
628 }
629
630 /**
631  * Verify the Verbs Tx queue list is empty
632  *
633  * @param dev
634  *   Pointer to Ethernet device.
635  *
636  * @return
637  *   The number of object not released.
638  */
639 int
640 mlx5_txq_ibv_verify(struct rte_eth_dev *dev)
641 {
642         struct mlx5_priv *priv = dev->data->dev_private;
643         int ret = 0;
644         struct mlx5_txq_ibv *txq_ibv;
645
646         LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
647                 DRV_LOG(DEBUG, "port %u Verbs Tx queue %u still referenced",
648                         dev->data->port_id, txq_ibv->txq_ctrl->txq.idx);
649                 ++ret;
650         }
651         return ret;
652 }
653
654 /**
655  * Calculate the total number of WQEBB for Tx queue.
656  *
657  * Simplified version of calc_sq_size() in rdma-core.
658  *
659  * @param txq_ctrl
660  *   Pointer to Tx queue control structure.
661  *
662  * @return
663  *   The number of WQEBB.
664  */
665 static int
666 txq_calc_wqebb_cnt(struct mlx5_txq_ctrl *txq_ctrl)
667 {
668         unsigned int wqe_size;
669         const unsigned int desc = 1 << txq_ctrl->txq.elts_n;
670
671         wqe_size = MLX5_WQE_CSEG_SIZE +
672                    MLX5_WQE_ESEG_SIZE +
673                    MLX5_WSEG_SIZE -
674                    MLX5_ESEG_MIN_INLINE_SIZE +
675                    txq_ctrl->max_inline_data;
676         return rte_align32pow2(wqe_size * desc) / MLX5_WQE_SIZE;
677 }
678
679 /**
680  * Set Tx queue parameters from device configuration.
681  *
682  * @param txq_ctrl
683  *   Pointer to Tx queue control structure.
684  */
685 static void
686 txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
687 {
688         struct mlx5_priv *priv = txq_ctrl->priv;
689         struct mlx5_dev_config *config = &priv->config;
690         unsigned int inlen_send; /* Inline data for ordinary SEND.*/
691         unsigned int inlen_empw; /* Inline data for enhanced MPW. */
692         unsigned int inlen_mode; /* Minimal required Inline data. */
693         unsigned int txqs_inline; /* Min Tx queues to enable inline. */
694         uint64_t dev_txoff = priv->dev_data->dev_conf.txmode.offloads;
695         bool tso = txq_ctrl->txq.offloads & (DEV_TX_OFFLOAD_TCP_TSO |
696                                             DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
697                                             DEV_TX_OFFLOAD_GRE_TNL_TSO |
698                                             DEV_TX_OFFLOAD_IP_TNL_TSO |
699                                             DEV_TX_OFFLOAD_UDP_TNL_TSO);
700         bool vlan_inline;
701         unsigned int temp;
702
703         if (config->txqs_inline == MLX5_ARG_UNSET)
704                 txqs_inline =
705 #if defined(RTE_ARCH_ARM64)
706                 (priv->sh->pci_dev->id.device_id ==
707                         PCI_DEVICE_ID_MELLANOX_CONNECTX5BF) ?
708                         MLX5_INLINE_MAX_TXQS_BLUEFIELD :
709 #endif
710                         MLX5_INLINE_MAX_TXQS;
711         else
712                 txqs_inline = (unsigned int)config->txqs_inline;
713         inlen_send = (config->txq_inline_max == MLX5_ARG_UNSET) ?
714                      MLX5_SEND_DEF_INLINE_LEN :
715                      (unsigned int)config->txq_inline_max;
716         inlen_empw = (config->txq_inline_mpw == MLX5_ARG_UNSET) ?
717                      MLX5_EMPW_DEF_INLINE_LEN :
718                      (unsigned int)config->txq_inline_mpw;
719         inlen_mode = (config->txq_inline_min == MLX5_ARG_UNSET) ?
720                      0 : (unsigned int)config->txq_inline_min;
721         if (config->mps != MLX5_MPW_ENHANCED)
722                 inlen_empw = 0;
723         /*
724          * If there is requested minimal amount of data to inline
725          * we MUST enable inlining. This is a case for ConnectX-4
726          * which usually requires L2 inlined for correct operating
727          * and ConnectX-4LX which requires L2-L4 inlined to
728          * support E-Switch Flows.
729          */
730         if (inlen_mode) {
731                 if (inlen_mode <= MLX5_ESEG_MIN_INLINE_SIZE) {
732                         /*
733                          * Optimize minimal inlining for single
734                          * segment packets to fill one WQEBB
735                          * without gaps.
736                          */
737                         temp = MLX5_ESEG_MIN_INLINE_SIZE;
738                 } else {
739                         temp = inlen_mode - MLX5_ESEG_MIN_INLINE_SIZE;
740                         temp = RTE_ALIGN(temp, MLX5_WSEG_SIZE) +
741                                MLX5_ESEG_MIN_INLINE_SIZE;
742                         temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
743                 }
744                 if (temp != inlen_mode) {
745                         DRV_LOG(INFO,
746                                 "port %u minimal required inline setting"
747                                 " aligned from %u to %u",
748                                 PORT_ID(priv), inlen_mode, temp);
749                         inlen_mode = temp;
750                 }
751         }
752         /*
753          * If port is configured to support VLAN insertion and device
754          * does not support this feature by HW (for NICs before ConnectX-5
755          * or in case of wqe_vlan_insert flag is not set) we must enable
756          * data inline on all queues because it is supported by single
757          * tx_burst routine.
758          */
759         txq_ctrl->txq.vlan_en = config->hw_vlan_insert;
760         vlan_inline = (dev_txoff & DEV_TX_OFFLOAD_VLAN_INSERT) &&
761                       !config->hw_vlan_insert;
762         if (vlan_inline)
763                 inlen_send = RTE_MAX(inlen_send, MLX5_ESEG_MIN_INLINE_SIZE);
764         /*
765          * If there are few Tx queues it is prioritized
766          * to save CPU cycles and disable data inlining at all.
767          */
768         if ((inlen_send && priv->txqs_n >= txqs_inline) || vlan_inline) {
769                 /*
770                  * The data sent with ordinal MLX5_OPCODE_SEND
771                  * may be inlined in Ethernet Segment, align the
772                  * length accordingly to fit entire WQEBBs.
773                  */
774                 temp = (inlen_send / MLX5_WQE_SIZE) * MLX5_WQE_SIZE +
775                         MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE;
776                 temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
777                                      MLX5_ESEG_MIN_INLINE_SIZE -
778                                      MLX5_WQE_CSEG_SIZE -
779                                      MLX5_WQE_ESEG_SIZE -
780                                      MLX5_WQE_DSEG_SIZE * 2);
781                 temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
782                 temp = RTE_MAX(temp, inlen_mode);
783                 if (temp != inlen_send) {
784                         DRV_LOG(INFO,
785                                 "port %u ordinary send inline setting"
786                                 " aligned from %u to %u",
787                                 PORT_ID(priv), inlen_send, temp);
788                         inlen_send = temp;
789                 }
790                 /*
791                  * Not aligned to cache lines, but to WQEs.
792                  * First bytes of data (initial alignment)
793                  * is going to be copied explicitly at the
794                  * beginning of inlining buffer in Ethernet
795                  * Segment.
796                  */
797                 assert(inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE);
798                 assert(inlen_send <= MLX5_WQE_SIZE_MAX +
799                                      MLX5_ESEG_MIN_INLINE_SIZE -
800                                      MLX5_WQE_CSEG_SIZE -
801                                      MLX5_WQE_ESEG_SIZE -
802                                      MLX5_WQE_DSEG_SIZE * 2);
803                 txq_ctrl->txq.inlen_send = inlen_send;
804                 txq_ctrl->txq.inlen_mode = inlen_mode;
805                 txq_ctrl->txq.inlen_empw = 0;
806         } else {
807                 /*
808                  * If minimal inlining is requested we must
809                  * enable inlining in general, despite the
810                  * number of configured queues.
811                  */
812                 inlen_send = inlen_mode;
813                 if (inlen_mode) {
814                         /*
815                          * Extend space for inline data to allow
816                          * optional alignment of data buffer
817                          * start address, it may improve PCIe
818                          * performance.
819                          */
820                         inlen_send = RTE_MIN(inlen_send + MLX5_WQE_SIZE,
821                                              MLX5_SEND_MAX_INLINE_LEN);
822                 }
823                 txq_ctrl->txq.inlen_send = inlen_send;
824                 txq_ctrl->txq.inlen_mode = inlen_mode;
825                 txq_ctrl->txq.inlen_empw = 0;
826                 inlen_send = 0;
827                 inlen_empw = 0;
828         }
829         if (inlen_send && inlen_empw && priv->txqs_n >= txqs_inline) {
830                 /*
831                  * The data sent with MLX5_OPCODE_ENHANCED_MPSW
832                  * may be inlined in Data Segment, align the
833                  * length accordingly to fit entire WQEBBs.
834                  */
835                 temp = (inlen_empw + MLX5_WQE_SIZE - 1) / MLX5_WQE_SIZE;
836                 temp = temp * MLX5_WQE_SIZE +
837                        MLX5_DSEG_MIN_INLINE_SIZE - MLX5_WQE_DSEG_SIZE;
838                 temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
839                                      MLX5_DSEG_MIN_INLINE_SIZE -
840                                      MLX5_WQE_CSEG_SIZE -
841                                      MLX5_WQE_ESEG_SIZE -
842                                      MLX5_WQE_DSEG_SIZE);
843                 temp = RTE_MIN(temp, MLX5_EMPW_MAX_INLINE_LEN);
844                 if (temp != inlen_empw) {
845                         DRV_LOG(INFO,
846                                 "port %u enhanced empw inline setting"
847                                 " aligned from %u to %u",
848                                 PORT_ID(priv), inlen_empw, temp);
849                         inlen_empw = temp;
850                 }
851                 assert(inlen_empw >= MLX5_ESEG_MIN_INLINE_SIZE);
852                 assert(inlen_empw <= MLX5_WQE_SIZE_MAX +
853                                      MLX5_DSEG_MIN_INLINE_SIZE -
854                                      MLX5_WQE_CSEG_SIZE -
855                                      MLX5_WQE_ESEG_SIZE -
856                                      MLX5_WQE_DSEG_SIZE);
857                 txq_ctrl->txq.inlen_empw = inlen_empw;
858         }
859         txq_ctrl->max_inline_data = RTE_MAX(inlen_send, inlen_empw);
860         if (tso) {
861                 txq_ctrl->max_tso_header = MLX5_MAX_TSO_HEADER;
862                 txq_ctrl->max_inline_data = RTE_MAX(txq_ctrl->max_inline_data,
863                                                     MLX5_MAX_TSO_HEADER);
864                 txq_ctrl->txq.tso_en = 1;
865         }
866         txq_ctrl->txq.tunnel_en = config->tunnel_en | config->swp;
867         txq_ctrl->txq.swp_en = ((DEV_TX_OFFLOAD_IP_TNL_TSO |
868                                  DEV_TX_OFFLOAD_UDP_TNL_TSO |
869                                  DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) &
870                                 txq_ctrl->txq.offloads) && config->swp;
871 }
872
873 /**
874  * Create a DPDK Tx queue.
875  *
876  * @param dev
877  *   Pointer to Ethernet device.
878  * @param idx
879  *   TX queue index.
880  * @param desc
881  *   Number of descriptors to configure in queue.
882  * @param socket
883  *   NUMA socket on which memory must be allocated.
884  * @param[in] conf
885  *  Thresholds parameters.
886  *
887  * @return
888  *   A DPDK queue object on success, NULL otherwise and rte_errno is set.
889  */
890 struct mlx5_txq_ctrl *
891 mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
892              unsigned int socket, const struct rte_eth_txconf *conf)
893 {
894         struct mlx5_priv *priv = dev->data->dev_private;
895         struct mlx5_txq_ctrl *tmpl;
896
897         tmpl = rte_calloc_socket("TXQ", 1,
898                                  sizeof(*tmpl) +
899                                  desc * sizeof(struct rte_mbuf *),
900                                  0, socket);
901         if (!tmpl) {
902                 rte_errno = ENOMEM;
903                 return NULL;
904         }
905         if (mlx5_mr_btree_init(&tmpl->txq.mr_ctrl.cache_bh,
906                                MLX5_MR_BTREE_CACHE_N, socket)) {
907                 /* rte_errno is already set. */
908                 goto error;
909         }
910         /* Save pointer of global generation number to check memory event. */
911         tmpl->txq.mr_ctrl.dev_gen_ptr = &priv->sh->mr.dev_gen;
912         assert(desc > MLX5_TX_COMP_THRESH);
913         tmpl->txq.offloads = conf->offloads |
914                              dev->data->dev_conf.txmode.offloads;
915         tmpl->priv = priv;
916         tmpl->socket = socket;
917         tmpl->txq.elts_n = log2above(desc);
918         tmpl->txq.elts_s = desc;
919         tmpl->txq.elts_m = desc - 1;
920         tmpl->txq.port_id = dev->data->port_id;
921         tmpl->txq.idx = idx;
922         txq_set_params(tmpl);
923         if (txq_calc_wqebb_cnt(tmpl) >
924             priv->sh->device_attr.orig_attr.max_qp_wr) {
925                 DRV_LOG(ERR,
926                         "port %u Tx WQEBB count (%d) exceeds the limit (%d),"
927                         " try smaller queue size",
928                         dev->data->port_id, txq_calc_wqebb_cnt(tmpl),
929                         priv->sh->device_attr.orig_attr.max_qp_wr);
930                 rte_errno = ENOMEM;
931                 goto error;
932         }
933         rte_atomic32_inc(&tmpl->refcnt);
934         LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
935         return tmpl;
936 error:
937         rte_free(tmpl);
938         return NULL;
939 }
940
941 /**
942  * Get a Tx queue.
943  *
944  * @param dev
945  *   Pointer to Ethernet device.
946  * @param idx
947  *   TX queue index.
948  *
949  * @return
950  *   A pointer to the queue if it exists.
951  */
952 struct mlx5_txq_ctrl *
953 mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
954 {
955         struct mlx5_priv *priv = dev->data->dev_private;
956         struct mlx5_txq_ctrl *ctrl = NULL;
957
958         if ((*priv->txqs)[idx]) {
959                 ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
960                                     txq);
961                 mlx5_txq_ibv_get(dev, idx);
962                 rte_atomic32_inc(&ctrl->refcnt);
963         }
964         return ctrl;
965 }
966
967 /**
968  * Release a Tx queue.
969  *
970  * @param dev
971  *   Pointer to Ethernet device.
972  * @param idx
973  *   TX queue index.
974  *
975  * @return
976  *   1 while a reference on it exists, 0 when freed.
977  */
978 int
979 mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
980 {
981         struct mlx5_priv *priv = dev->data->dev_private;
982         struct mlx5_txq_ctrl *txq;
983
984         if (!(*priv->txqs)[idx])
985                 return 0;
986         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
987         if (txq->ibv && !mlx5_txq_ibv_release(txq->ibv))
988                 txq->ibv = NULL;
989         if (rte_atomic32_dec_and_test(&txq->refcnt)) {
990                 txq_free_elts(txq);
991                 mlx5_mr_btree_free(&txq->txq.mr_ctrl.cache_bh);
992                 LIST_REMOVE(txq, next);
993                 rte_free(txq);
994                 (*priv->txqs)[idx] = NULL;
995                 return 0;
996         }
997         return 1;
998 }
999
1000 /**
1001  * Verify if the queue can be released.
1002  *
1003  * @param dev
1004  *   Pointer to Ethernet device.
1005  * @param idx
1006  *   TX queue index.
1007  *
1008  * @return
1009  *   1 if the queue can be released.
1010  */
1011 int
1012 mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
1013 {
1014         struct mlx5_priv *priv = dev->data->dev_private;
1015         struct mlx5_txq_ctrl *txq;
1016
1017         if (!(*priv->txqs)[idx])
1018                 return -1;
1019         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
1020         return (rte_atomic32_read(&txq->refcnt) == 1);
1021 }
1022
1023 /**
1024  * Verify the Tx Queue list is empty
1025  *
1026  * @param dev
1027  *   Pointer to Ethernet device.
1028  *
1029  * @return
1030  *   The number of object not released.
1031  */
1032 int
1033 mlx5_txq_verify(struct rte_eth_dev *dev)
1034 {
1035         struct mlx5_priv *priv = dev->data->dev_private;
1036         struct mlx5_txq_ctrl *txq_ctrl;
1037         int ret = 0;
1038
1039         LIST_FOREACH(txq_ctrl, &priv->txqsctrl, next) {
1040                 DRV_LOG(DEBUG, "port %u Tx queue %u still referenced",
1041                         dev->data->port_id, txq_ctrl->txq.idx);
1042                 ++ret;
1043         }
1044         return ret;
1045 }