net/mlx5: drop useless support for several Verbs ports
[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
259         memset(pages, 0, priv->txqs_n * sizeof(uintptr_t));
260         /*
261          * As rdma-core, UARs are mapped in size of OS page size.
262          * Use aligned address to avoid duplicate mmap.
263          * Ref to libmlx5 function: mlx5_init_context()
264          */
265         for (i = 0; i != priv->txqs_n; ++i) {
266                 if (!(*priv->txqs)[i])
267                         continue;
268                 txq = (*priv->txqs)[i];
269                 txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
270                 assert(txq_ctrl->idx == (uint16_t)i);
271                 /* UAR addr form verbs used to find dup and offset in page. */
272                 uar_va = (uintptr_t)txq_ctrl->bf_reg_orig;
273                 off = uar_va & (page_size - 1); /* offset in page. */
274                 uar_va = RTE_ALIGN_FLOOR(uar_va, page_size); /* page addr. */
275                 already_mapped = 0;
276                 for (j = 0; j != pages_n; ++j) {
277                         if (pages[j] == uar_va) {
278                                 already_mapped = 1;
279                                 break;
280                         }
281                 }
282                 /* new address in reserved UAR address space. */
283                 addr = RTE_PTR_ADD(priv->uar_base,
284                                    uar_va & (MLX5_UAR_SIZE - 1));
285                 if (!already_mapped) {
286                         pages[pages_n++] = uar_va;
287                         /* fixed mmap to specified address in reserved
288                          * address space.
289                          */
290                         ret = mmap(addr, page_size,
291                                    PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
292                                    txq_ctrl->uar_mmap_offset);
293                         if (ret != addr) {
294                                 /* fixed mmap have to return same address */
295                                 DRV_LOG(ERR,
296                                         "port %u call to mmap failed on UAR"
297                                         " for txq %u",
298                                         dev->data->port_id, txq_ctrl->idx);
299                                 rte_errno = ENXIO;
300                                 return -rte_errno;
301                         }
302                 }
303                 if (rte_eal_process_type() == RTE_PROC_PRIMARY) /* save once */
304                         txq_ctrl->txq.bf_reg = RTE_PTR_ADD((void *)addr, off);
305                 else
306                         assert(txq_ctrl->txq.bf_reg ==
307                                RTE_PTR_ADD((void *)addr, off));
308         }
309         return 0;
310 }
311
312 /**
313  * Check if the burst function is using eMPW.
314  *
315  * @param tx_pkt_burst
316  *   Tx burst function pointer.
317  *
318  * @return
319  *   1 if the burst function is using eMPW, 0 otherwise.
320  */
321 static int
322 is_empw_burst_func(eth_tx_burst_t tx_pkt_burst)
323 {
324         if (tx_pkt_burst == mlx5_tx_burst_raw_vec ||
325             tx_pkt_burst == mlx5_tx_burst_vec ||
326             tx_pkt_burst == mlx5_tx_burst_empw)
327                 return 1;
328         return 0;
329 }
330
331 /**
332  * Create the Tx queue Verbs object.
333  *
334  * @param dev
335  *   Pointer to Ethernet device.
336  * @param idx
337  *   Queue index in DPDK Rx queue array
338  *
339  * @return
340  *   The Verbs object initialised, NULL otherwise and rte_errno is set.
341  */
342 struct mlx5_txq_ibv *
343 mlx5_txq_ibv_new(struct rte_eth_dev *dev, uint16_t idx)
344 {
345         struct priv *priv = dev->data->dev_private;
346         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
347         struct mlx5_txq_ctrl *txq_ctrl =
348                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
349         struct mlx5_txq_ibv tmpl;
350         struct mlx5_txq_ibv *txq_ibv;
351         union {
352                 struct ibv_qp_init_attr_ex init;
353                 struct ibv_cq_init_attr_ex cq;
354                 struct ibv_qp_attr mod;
355                 struct ibv_cq_ex cq_attr;
356         } attr;
357         unsigned int cqe_n;
358         struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
359         struct mlx5dv_cq cq_info;
360         struct mlx5dv_obj obj;
361         const int desc = 1 << txq_data->elts_n;
362         eth_tx_burst_t tx_pkt_burst = mlx5_select_tx_function(dev);
363         int ret = 0;
364
365         assert(txq_data);
366         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_TX_QUEUE;
367         priv->verbs_alloc_ctx.obj = txq_ctrl;
368         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
369                 DRV_LOG(ERR,
370                         "port %u MLX5_ENABLE_CQE_COMPRESSION must never be set",
371                         dev->data->port_id);
372                 rte_errno = EINVAL;
373                 return NULL;
374         }
375         memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
376         attr.cq = (struct ibv_cq_init_attr_ex){
377                 .comp_mask = 0,
378         };
379         cqe_n = ((desc / MLX5_TX_COMP_THRESH) - 1) ?
380                 ((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
381         if (is_empw_burst_func(tx_pkt_burst))
382                 cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
383         tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
384         if (tmpl.cq == NULL) {
385                 DRV_LOG(ERR, "port %u Tx queue %u CQ creation failure",
386                         dev->data->port_id, idx);
387                 rte_errno = errno;
388                 goto error;
389         }
390         attr.init = (struct ibv_qp_init_attr_ex){
391                 /* CQ to be associated with the send queue. */
392                 .send_cq = tmpl.cq,
393                 /* CQ to be associated with the receive queue. */
394                 .recv_cq = tmpl.cq,
395                 .cap = {
396                         /* Max number of outstanding WRs. */
397                         .max_send_wr =
398                                 ((priv->device_attr.orig_attr.max_qp_wr <
399                                   desc) ?
400                                  priv->device_attr.orig_attr.max_qp_wr :
401                                  desc),
402                         /*
403                          * Max number of scatter/gather elements in a WR,
404                          * must be 1 to prevent libmlx5 from trying to affect
405                          * too much memory. TX gather is not impacted by the
406                          * priv->device_attr.max_sge limit and will still work
407                          * properly.
408                          */
409                         .max_send_sge = 1,
410                 },
411                 .qp_type = IBV_QPT_RAW_PACKET,
412                 /*
413                  * Do *NOT* enable this, completions events are managed per
414                  * Tx burst.
415                  */
416                 .sq_sig_all = 0,
417                 .pd = priv->pd,
418                 .comp_mask = IBV_QP_INIT_ATTR_PD,
419         };
420         if (txq_data->max_inline)
421                 attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
422         if (txq_data->tso_en) {
423                 attr.init.max_tso_header = txq_ctrl->max_tso_header;
424                 attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
425         }
426         tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
427         if (tmpl.qp == NULL) {
428                 DRV_LOG(ERR, "port %u Tx queue %u QP creation failure",
429                         dev->data->port_id, idx);
430                 rte_errno = errno;
431                 goto error;
432         }
433         attr.mod = (struct ibv_qp_attr){
434                 /* Move the QP to this state. */
435                 .qp_state = IBV_QPS_INIT,
436                 /* Primary port number. */
437                 .port_num = 1,
438         };
439         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
440                                    (IBV_QP_STATE | IBV_QP_PORT));
441         if (ret) {
442                 DRV_LOG(ERR,
443                         "port %u Tx queue %u QP state to IBV_QPS_INIT failed",
444                         dev->data->port_id, idx);
445                 rte_errno = errno;
446                 goto error;
447         }
448         attr.mod = (struct ibv_qp_attr){
449                 .qp_state = IBV_QPS_RTR
450         };
451         ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
452         if (ret) {
453                 DRV_LOG(ERR,
454                         "port %u Tx queue %u QP state to IBV_QPS_RTR failed",
455                         dev->data->port_id, idx);
456                 rte_errno = errno;
457                 goto error;
458         }
459         attr.mod.qp_state = IBV_QPS_RTS;
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_RTS failed",
464                         dev->data->port_id, idx);
465                 rte_errno = errno;
466                 goto error;
467         }
468         txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
469                                     txq_ctrl->socket);
470         if (!txq_ibv) {
471                 DRV_LOG(ERR, "port %u Tx queue %u cannot allocate memory",
472                         dev->data->port_id, idx);
473                 rte_errno = ENOMEM;
474                 goto error;
475         }
476         obj.cq.in = tmpl.cq;
477         obj.cq.out = &cq_info;
478         obj.qp.in = tmpl.qp;
479         obj.qp.out = &qp;
480         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
481         if (ret != 0) {
482                 rte_errno = errno;
483                 goto error;
484         }
485         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
486                 DRV_LOG(ERR,
487                         "port %u wrong MLX5_CQE_SIZE environment variable"
488                         " value: it should be set to %u",
489                         dev->data->port_id, RTE_CACHE_LINE_SIZE);
490                 rte_errno = EINVAL;
491                 goto error;
492         }
493         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
494         txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
495         txq_data->wqes = qp.sq.buf;
496         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
497         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
498         txq_ctrl->bf_reg_orig = qp.bf.reg;
499         txq_data->cq_db = cq_info.dbrec;
500         txq_data->cqes =
501                 (volatile struct mlx5_cqe (*)[])
502                 (uintptr_t)cq_info.buf;
503         txq_data->cq_ci = 0;
504 #ifndef NDEBUG
505         txq_data->cq_pi = 0;
506 #endif
507         txq_data->wqe_ci = 0;
508         txq_data->wqe_pi = 0;
509         txq_ibv->qp = tmpl.qp;
510         txq_ibv->cq = tmpl.cq;
511         rte_atomic32_inc(&txq_ibv->refcnt);
512         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
513                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
514         } else {
515                 DRV_LOG(ERR,
516                         "port %u failed to retrieve UAR info, invalid"
517                         " libmlx5.so",
518                         dev->data->port_id);
519                 rte_errno = EINVAL;
520                 goto error;
521         }
522         LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
523         txq_ibv->txq_ctrl = txq_ctrl;
524         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
525         return txq_ibv;
526 error:
527         ret = rte_errno; /* Save rte_errno before cleanup. */
528         if (tmpl.cq)
529                 claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
530         if (tmpl.qp)
531                 claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
532         priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
533         rte_errno = ret; /* Restore rte_errno. */
534         return NULL;
535 }
536
537 /**
538  * Get an Tx queue Verbs object.
539  *
540  * @param dev
541  *   Pointer to Ethernet device.
542  * @param idx
543  *   Queue index in DPDK Rx queue array
544  *
545  * @return
546  *   The Verbs object if it exists.
547  */
548 struct mlx5_txq_ibv *
549 mlx5_txq_ibv_get(struct rte_eth_dev *dev, uint16_t idx)
550 {
551         struct priv *priv = dev->data->dev_private;
552         struct mlx5_txq_ctrl *txq_ctrl;
553
554         if (idx >= priv->txqs_n)
555                 return NULL;
556         if (!(*priv->txqs)[idx])
557                 return NULL;
558         txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
559         if (txq_ctrl->ibv)
560                 rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
561         return txq_ctrl->ibv;
562 }
563
564 /**
565  * Release an Tx verbs queue object.
566  *
567  * @param txq_ibv
568  *   Verbs Tx queue object.
569  *
570  * @return
571  *   1 while a reference on it exists, 0 when freed.
572  */
573 int
574 mlx5_txq_ibv_release(struct mlx5_txq_ibv *txq_ibv)
575 {
576         assert(txq_ibv);
577         if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
578                 claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
579                 claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
580                 LIST_REMOVE(txq_ibv, next);
581                 rte_free(txq_ibv);
582                 return 0;
583         }
584         return 1;
585 }
586
587 /**
588  * Return true if a single reference exists on the object.
589  *
590  * @param txq_ibv
591  *   Verbs Tx queue object.
592  */
593 int
594 mlx5_txq_ibv_releasable(struct mlx5_txq_ibv *txq_ibv)
595 {
596         assert(txq_ibv);
597         return (rte_atomic32_read(&txq_ibv->refcnt) == 1);
598 }
599
600 /**
601  * Verify the Verbs Tx queue list is empty
602  *
603  * @param dev
604  *   Pointer to Ethernet device.
605  *
606  * @return
607  *   The number of object not released.
608  */
609 int
610 mlx5_txq_ibv_verify(struct rte_eth_dev *dev)
611 {
612         struct priv *priv = dev->data->dev_private;
613         int ret = 0;
614         struct mlx5_txq_ibv *txq_ibv;
615
616         LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
617                 DRV_LOG(DEBUG, "port %u Verbs Tx queue %u still referenced",
618                         dev->data->port_id, txq_ibv->txq_ctrl->idx);
619                 ++ret;
620         }
621         return ret;
622 }
623
624 /**
625  * Set Tx queue parameters from device configuration.
626  *
627  * @param txq_ctrl
628  *   Pointer to Tx queue control structure.
629  */
630 static void
631 txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
632 {
633         struct priv *priv = txq_ctrl->priv;
634         struct mlx5_dev_config *config = &priv->config;
635         const unsigned int max_tso_inline =
636                 ((MLX5_MAX_TSO_HEADER + (RTE_CACHE_LINE_SIZE - 1)) /
637                  RTE_CACHE_LINE_SIZE);
638         unsigned int txq_inline;
639         unsigned int txqs_inline;
640         unsigned int inline_max_packet_sz;
641         eth_tx_burst_t tx_pkt_burst =
642                 mlx5_select_tx_function(ETH_DEV(priv));
643         int is_empw_func = is_empw_burst_func(tx_pkt_burst);
644         int tso = !!(txq_ctrl->txq.offloads & (DEV_TX_OFFLOAD_TCP_TSO |
645                                                DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
646                                                DEV_TX_OFFLOAD_GRE_TNL_TSO |
647                                                DEV_TX_OFFLOAD_IP_TNL_TSO |
648                                                DEV_TX_OFFLOAD_UDP_TNL_TSO));
649
650         txq_inline = (config->txq_inline == MLX5_ARG_UNSET) ?
651                 0 : config->txq_inline;
652         txqs_inline = (config->txqs_inline == MLX5_ARG_UNSET) ?
653                 0 : config->txqs_inline;
654         inline_max_packet_sz =
655                 (config->inline_max_packet_sz == MLX5_ARG_UNSET) ?
656                 0 : config->inline_max_packet_sz;
657         if (is_empw_func) {
658                 if (config->txq_inline == MLX5_ARG_UNSET)
659                         txq_inline = MLX5_WQE_SIZE_MAX - MLX5_WQE_SIZE;
660                 if (config->txqs_inline == MLX5_ARG_UNSET)
661                         txqs_inline = MLX5_EMPW_MIN_TXQS;
662                 if (config->inline_max_packet_sz == MLX5_ARG_UNSET)
663                         inline_max_packet_sz = MLX5_EMPW_MAX_INLINE_LEN;
664                 txq_ctrl->txq.mpw_hdr_dseg = config->mpw_hdr_dseg;
665                 txq_ctrl->txq.inline_max_packet_sz = inline_max_packet_sz;
666         }
667         if (txq_inline && priv->txqs_n >= txqs_inline) {
668                 unsigned int ds_cnt;
669
670                 txq_ctrl->txq.max_inline =
671                         ((txq_inline + (RTE_CACHE_LINE_SIZE - 1)) /
672                          RTE_CACHE_LINE_SIZE);
673                 if (is_empw_func) {
674                         /* To minimize the size of data set, avoid requesting
675                          * too large WQ.
676                          */
677                         txq_ctrl->max_inline_data =
678                                 ((RTE_MIN(txq_inline,
679                                           inline_max_packet_sz) +
680                                   (RTE_CACHE_LINE_SIZE - 1)) /
681                                  RTE_CACHE_LINE_SIZE) * RTE_CACHE_LINE_SIZE;
682                 } else {
683                         txq_ctrl->max_inline_data =
684                                 txq_ctrl->txq.max_inline * RTE_CACHE_LINE_SIZE;
685                 }
686                 /*
687                  * Check if the inline size is too large in a way which
688                  * can make the WQE DS to overflow.
689                  * Considering in calculation:
690                  *      WQE CTRL (1 DS)
691                  *      WQE ETH  (1 DS)
692                  *      Inline part (N DS)
693                  */
694                 ds_cnt = 2 + (txq_ctrl->txq.max_inline / MLX5_WQE_DWORD_SIZE);
695                 if (ds_cnt > MLX5_DSEG_MAX) {
696                         unsigned int max_inline = (MLX5_DSEG_MAX - 2) *
697                                                   MLX5_WQE_DWORD_SIZE;
698
699                         max_inline = max_inline - (max_inline %
700                                                    RTE_CACHE_LINE_SIZE);
701                         DRV_LOG(WARNING,
702                                 "port %u txq inline is too large (%d) setting"
703                                 " it to the maximum possible: %d\n",
704                                 PORT_ID(priv), txq_inline, max_inline);
705                         txq_ctrl->txq.max_inline = max_inline /
706                                                    RTE_CACHE_LINE_SIZE;
707                 }
708         }
709         if (tso) {
710                 txq_ctrl->max_tso_header = max_tso_inline * RTE_CACHE_LINE_SIZE;
711                 txq_ctrl->txq.max_inline = RTE_MAX(txq_ctrl->txq.max_inline,
712                                                    max_tso_inline);
713                 txq_ctrl->txq.tso_en = 1;
714         }
715         txq_ctrl->txq.tunnel_en = config->tunnel_en | config->swp;
716         txq_ctrl->txq.swp_en = ((DEV_TX_OFFLOAD_IP_TNL_TSO |
717                                  DEV_TX_OFFLOAD_UDP_TNL_TSO |
718                                  DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) &
719                                 txq_ctrl->txq.offloads) && config->swp;
720 }
721
722 /**
723  * Create a DPDK Tx queue.
724  *
725  * @param dev
726  *   Pointer to Ethernet device.
727  * @param idx
728  *   TX queue index.
729  * @param desc
730  *   Number of descriptors to configure in queue.
731  * @param socket
732  *   NUMA socket on which memory must be allocated.
733  * @param[in] conf
734  *  Thresholds parameters.
735  *
736  * @return
737  *   A DPDK queue object on success, NULL otherwise and rte_errno is set.
738  */
739 struct mlx5_txq_ctrl *
740 mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
741              unsigned int socket, const struct rte_eth_txconf *conf)
742 {
743         struct priv *priv = dev->data->dev_private;
744         struct mlx5_txq_ctrl *tmpl;
745
746         tmpl = rte_calloc_socket("TXQ", 1,
747                                  sizeof(*tmpl) +
748                                  desc * sizeof(struct rte_mbuf *),
749                                  0, socket);
750         if (!tmpl) {
751                 rte_errno = ENOMEM;
752                 return NULL;
753         }
754         if (mlx5_mr_btree_init(&tmpl->txq.mr_ctrl.cache_bh,
755                                MLX5_MR_BTREE_CACHE_N, socket)) {
756                 /* rte_errno is already set. */
757                 goto error;
758         }
759         /* Save pointer of global generation number to check memory event. */
760         tmpl->txq.mr_ctrl.dev_gen_ptr = &priv->mr.dev_gen;
761         assert(desc > MLX5_TX_COMP_THRESH);
762         tmpl->txq.offloads = conf->offloads |
763                              dev->data->dev_conf.txmode.offloads;
764         tmpl->priv = priv;
765         tmpl->socket = socket;
766         tmpl->txq.elts_n = log2above(desc);
767         tmpl->idx = idx;
768         txq_set_params(tmpl);
769         DRV_LOG(DEBUG, "port %u priv->device_attr.max_qp_wr is %d",
770                 dev->data->port_id, priv->device_attr.orig_attr.max_qp_wr);
771         DRV_LOG(DEBUG, "port %u priv->device_attr.max_sge is %d",
772                 dev->data->port_id, priv->device_attr.orig_attr.max_sge);
773         tmpl->txq.elts =
774                 (struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
775         tmpl->txq.stats.idx = idx;
776         rte_atomic32_inc(&tmpl->refcnt);
777         LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
778         return tmpl;
779 error:
780         rte_free(tmpl);
781         return NULL;
782 }
783
784 /**
785  * Get a Tx queue.
786  *
787  * @param dev
788  *   Pointer to Ethernet device.
789  * @param idx
790  *   TX queue index.
791  *
792  * @return
793  *   A pointer to the queue if it exists.
794  */
795 struct mlx5_txq_ctrl *
796 mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
797 {
798         struct priv *priv = dev->data->dev_private;
799         struct mlx5_txq_ctrl *ctrl = NULL;
800
801         if ((*priv->txqs)[idx]) {
802                 ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
803                                     txq);
804                 mlx5_txq_ibv_get(dev, idx);
805                 rte_atomic32_inc(&ctrl->refcnt);
806         }
807         return ctrl;
808 }
809
810 /**
811  * Release a Tx queue.
812  *
813  * @param dev
814  *   Pointer to Ethernet device.
815  * @param idx
816  *   TX queue index.
817  *
818  * @return
819  *   1 while a reference on it exists, 0 when freed.
820  */
821 int
822 mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
823 {
824         struct priv *priv = dev->data->dev_private;
825         struct mlx5_txq_ctrl *txq;
826         size_t page_size = sysconf(_SC_PAGESIZE);
827
828         if (!(*priv->txqs)[idx])
829                 return 0;
830         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
831         if (txq->ibv && !mlx5_txq_ibv_release(txq->ibv))
832                 txq->ibv = NULL;
833         if (priv->uar_base)
834                 munmap((void *)RTE_ALIGN_FLOOR((uintptr_t)txq->txq.bf_reg,
835                        page_size), page_size);
836         if (rte_atomic32_dec_and_test(&txq->refcnt)) {
837                 txq_free_elts(txq);
838                 mlx5_mr_btree_free(&txq->txq.mr_ctrl.cache_bh);
839                 LIST_REMOVE(txq, next);
840                 rte_free(txq);
841                 (*priv->txqs)[idx] = NULL;
842                 return 0;
843         }
844         return 1;
845 }
846
847 /**
848  * Verify if the queue can be released.
849  *
850  * @param dev
851  *   Pointer to Ethernet device.
852  * @param idx
853  *   TX queue index.
854  *
855  * @return
856  *   1 if the queue can be released.
857  */
858 int
859 mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
860 {
861         struct priv *priv = dev->data->dev_private;
862         struct mlx5_txq_ctrl *txq;
863
864         if (!(*priv->txqs)[idx])
865                 return -1;
866         txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
867         return (rte_atomic32_read(&txq->refcnt) == 1);
868 }
869
870 /**
871  * Verify the Tx Queue list is empty
872  *
873  * @param dev
874  *   Pointer to Ethernet device.
875  *
876  * @return
877  *   The number of object not released.
878  */
879 int
880 mlx5_txq_verify(struct rte_eth_dev *dev)
881 {
882         struct priv *priv = dev->data->dev_private;
883         struct mlx5_txq_ctrl *txq;
884         int ret = 0;
885
886         LIST_FOREACH(txq, &priv->txqsctrl, next) {
887                 DRV_LOG(DEBUG, "port %u Tx queue %u still referenced",
888                         dev->data->port_id, txq->idx);
889                 ++ret;
890         }
891         return ret;
892 }