net/mlx5: add VLAN push/pop DR commands to glue
[dpdk.git] / drivers / net / mlx4 / mlx4_txq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 6WIND S.A.
3  * Copyright 2017 Mellanox Technologies, Ltd
4  */
5
6 /**
7  * @file
8  * Tx queues configuration for mlx4 driver.
9  */
10
11 #include <assert.h>
12 #include <errno.h>
13 #include <stddef.h>
14 #include <stdint.h>
15 #include <string.h>
16 #include <sys/mman.h>
17 #include <inttypes.h>
18 #include <unistd.h>
19
20 /* Verbs headers do not support -pedantic. */
21 #ifdef PEDANTIC
22 #pragma GCC diagnostic ignored "-Wpedantic"
23 #endif
24 #include <infiniband/verbs.h>
25 #ifdef PEDANTIC
26 #pragma GCC diagnostic error "-Wpedantic"
27 #endif
28
29 #include <rte_common.h>
30 #include <rte_errno.h>
31 #include <rte_ethdev_driver.h>
32 #include <rte_malloc.h>
33 #include <rte_mbuf.h>
34 #include <rte_mempool.h>
35
36 #include "mlx4.h"
37 #include "mlx4_glue.h"
38 #include "mlx4_prm.h"
39 #include "mlx4_rxtx.h"
40 #include "mlx4_utils.h"
41
42 /**
43  * Initialize Tx UAR registers for primary process.
44  *
45  * @param txq
46  *   Pointer to Tx queue structure.
47  */
48 static void
49 txq_uar_init(struct txq *txq)
50 {
51         struct mlx4_priv *priv = txq->priv;
52         struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(priv));
53
54         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
55         assert(ppriv);
56         ppriv->uar_table[txq->stats.idx] = txq->msq.db;
57 }
58
59 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
60 /**
61  * Remap UAR register of a Tx queue for secondary process.
62  *
63  * Remapped address is stored at the table in the process private structure of
64  * the device, indexed by queue index.
65  *
66  * @param txq
67  *   Pointer to Tx queue structure.
68  * @param fd
69  *   Verbs file descriptor to map UAR pages.
70  *
71  * @return
72  *   0 on success, a negative errno value otherwise and rte_errno is set.
73  */
74 static int
75 txq_uar_init_secondary(struct txq *txq, int fd)
76 {
77         struct mlx4_priv *priv = txq->priv;
78         struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(priv));
79         void *addr;
80         uintptr_t uar_va;
81         uintptr_t offset;
82         const size_t page_size = sysconf(_SC_PAGESIZE);
83
84         assert(ppriv);
85         /*
86          * As rdma-core, UARs are mapped in size of OS page
87          * size. Ref to libmlx4 function: mlx4_init_context()
88          */
89         uar_va = (uintptr_t)txq->msq.db;
90         offset = uar_va & (page_size - 1); /* Offset in page. */
91         addr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd,
92                         txq->msq.uar_mmap_offset);
93         if (addr == MAP_FAILED) {
94                 ERROR("port %u mmap failed for BF reg of txq %u",
95                       txq->port_id, txq->stats.idx);
96                 rte_errno = ENXIO;
97                 return -rte_errno;
98         }
99         addr = RTE_PTR_ADD(addr, offset);
100         ppriv->uar_table[txq->stats.idx] = addr;
101         return 0;
102 }
103
104 /**
105  * Unmap UAR register of a Tx queue for secondary process.
106  *
107  * @param txq
108  *   Pointer to Tx queue structure.
109  */
110 static void
111 txq_uar_uninit_secondary(struct txq *txq)
112 {
113         struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(txq->priv));
114         const size_t page_size = sysconf(_SC_PAGESIZE);
115         void *addr;
116
117         addr = ppriv->uar_table[txq->stats.idx];
118         munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
119 }
120
121 /**
122  * Initialize Tx UAR registers for secondary process.
123  *
124  * @param dev
125  *   Pointer to Ethernet device.
126  * @param fd
127  *   Verbs file descriptor to map UAR pages.
128  *
129  * @return
130  *   0 on success, a negative errno value otherwise and rte_errno is set.
131  */
132 int
133 mlx4_tx_uar_init_secondary(struct rte_eth_dev *dev, int fd)
134 {
135         const unsigned int txqs_n = dev->data->nb_tx_queues;
136         struct txq *txq;
137         unsigned int i;
138         int ret;
139
140         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
141         for (i = 0; i != txqs_n; ++i) {
142                 txq = dev->data->tx_queues[i];
143                 if (!txq)
144                         continue;
145                 assert(txq->stats.idx == (uint16_t)i);
146                 ret = txq_uar_init_secondary(txq, fd);
147                 if (ret)
148                         goto error;
149         }
150         return 0;
151 error:
152         /* Rollback. */
153         do {
154                 txq = dev->data->tx_queues[i];
155                 if (!txq)
156                         continue;
157                 txq_uar_uninit_secondary(txq);
158         } while (i--);
159         return -rte_errno;
160 }
161 #else
162 int
163 mlx4_tx_uar_init_secondary(struct rte_eth_dev *dev __rte_unused,
164                            int fd __rte_unused)
165 {
166         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
167         ERROR("UAR remap is not supported");
168         rte_errno = ENOTSUP;
169         return -rte_errno;
170 }
171 #endif
172
173 /**
174  * Free Tx queue elements.
175  *
176  * @param txq
177  *   Pointer to Tx queue structure.
178  */
179 static void
180 mlx4_txq_free_elts(struct txq *txq)
181 {
182         unsigned int elts_head = txq->elts_head;
183         unsigned int elts_tail = txq->elts_tail;
184         struct txq_elt (*elts)[txq->elts_n] = txq->elts;
185         unsigned int elts_m = txq->elts_n - 1;
186
187         DEBUG("%p: freeing WRs", (void *)txq);
188         while (elts_tail != elts_head) {
189                 struct txq_elt *elt = &(*elts)[elts_tail++ & elts_m];
190
191                 assert(elt->buf != NULL);
192                 rte_pktmbuf_free(elt->buf);
193                 elt->buf = NULL;
194                 elt->wqe = NULL;
195         }
196         txq->elts_tail = txq->elts_head;
197 }
198
199 /**
200  * Retrieves information needed in order to directly access the Tx queue.
201  *
202  * @param txq
203  *   Pointer to Tx queue structure.
204  * @param mlxdv
205  *   Pointer to device information for this Tx queue.
206  */
207 static void
208 mlx4_txq_fill_dv_obj_info(struct txq *txq, struct mlx4dv_obj *mlxdv)
209 {
210         struct mlx4_sq *sq = &txq->msq;
211         struct mlx4_cq *cq = &txq->mcq;
212         struct mlx4dv_qp *dqp = mlxdv->qp.out;
213         struct mlx4dv_cq *dcq = mlxdv->cq.out;
214
215         /* Total length, including headroom and spare WQEs. */
216         sq->size = (uint32_t)dqp->rq.offset - (uint32_t)dqp->sq.offset;
217         sq->buf = (uint8_t *)dqp->buf.buf + dqp->sq.offset;
218         sq->eob = sq->buf + sq->size;
219         uint32_t headroom_size = 2048 + (1 << dqp->sq.wqe_shift);
220         /* Continuous headroom size bytes must always stay freed. */
221         sq->remain_size = sq->size - headroom_size;
222         sq->owner_opcode = MLX4_OPCODE_SEND | (0u << MLX4_SQ_OWNER_BIT);
223         sq->stamp = rte_cpu_to_be_32(MLX4_SQ_STAMP_VAL |
224                                      (0u << MLX4_SQ_OWNER_BIT));
225 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
226         sq->uar_mmap_offset = dqp->uar_mmap_offset;
227 #else
228         sq->uar_mmap_offset = -1; /* Make mmap() fail. */
229 #endif
230         sq->db = dqp->sdb;
231         sq->doorbell_qpn = dqp->doorbell_qpn;
232         cq->buf = dcq->buf.buf;
233         cq->cqe_cnt = dcq->cqe_cnt;
234         cq->set_ci_db = dcq->set_ci_db;
235         cq->cqe_64 = (dcq->cqe_size & 64) ? 1 : 0;
236 }
237
238 /**
239  * Returns the per-port supported offloads.
240  *
241  * @param priv
242  *   Pointer to private structure.
243  *
244  * @return
245  *   Supported Tx offloads.
246  */
247 uint64_t
248 mlx4_get_tx_port_offloads(struct mlx4_priv *priv)
249 {
250         uint64_t offloads = DEV_TX_OFFLOAD_MULTI_SEGS;
251
252         if (priv->hw_csum) {
253                 offloads |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
254                              DEV_TX_OFFLOAD_UDP_CKSUM |
255                              DEV_TX_OFFLOAD_TCP_CKSUM);
256         }
257         if (priv->tso)
258                 offloads |= DEV_TX_OFFLOAD_TCP_TSO;
259         if (priv->hw_csum_l2tun) {
260                 offloads |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
261                 if (priv->tso)
262                         offloads |= (DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
263                                      DEV_TX_OFFLOAD_GRE_TNL_TSO);
264         }
265         return offloads;
266 }
267
268 /**
269  * DPDK callback to configure a Tx queue.
270  *
271  * @param dev
272  *   Pointer to Ethernet device structure.
273  * @param idx
274  *   Tx queue index.
275  * @param desc
276  *   Number of descriptors to configure in queue.
277  * @param socket
278  *   NUMA socket on which memory must be allocated.
279  * @param[in] conf
280  *   Thresholds parameters.
281  *
282  * @return
283  *   0 on success, negative errno value otherwise and rte_errno is set.
284  */
285 int
286 mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
287                     unsigned int socket, const struct rte_eth_txconf *conf)
288 {
289         struct mlx4_priv *priv = dev->data->dev_private;
290         struct mlx4dv_obj mlxdv;
291         struct mlx4dv_qp dv_qp;
292         struct mlx4dv_cq dv_cq;
293         struct txq_elt (*elts)[rte_align32pow2(desc)];
294         struct ibv_qp_init_attr qp_init_attr;
295         struct txq *txq;
296         uint8_t *bounce_buf;
297         struct mlx4_malloc_vec vec[] = {
298                 {
299                         .align = RTE_CACHE_LINE_SIZE,
300                         .size = sizeof(*txq),
301                         .addr = (void **)&txq,
302                 },
303                 {
304                         .align = RTE_CACHE_LINE_SIZE,
305                         .size = sizeof(*elts),
306                         .addr = (void **)&elts,
307                 },
308                 {
309                         .align = RTE_CACHE_LINE_SIZE,
310                         .size = MLX4_MAX_WQE_SIZE,
311                         .addr = (void **)&bounce_buf,
312                 },
313         };
314         int ret;
315         uint64_t offloads;
316
317         offloads = conf->offloads | dev->data->dev_conf.txmode.offloads;
318         DEBUG("%p: configuring queue %u for %u descriptors",
319               (void *)dev, idx, desc);
320         if (idx >= dev->data->nb_tx_queues) {
321                 rte_errno = EOVERFLOW;
322                 ERROR("%p: queue index out of range (%u >= %u)",
323                       (void *)dev, idx, dev->data->nb_tx_queues);
324                 return -rte_errno;
325         }
326         txq = dev->data->tx_queues[idx];
327         if (txq) {
328                 rte_errno = EEXIST;
329                 DEBUG("%p: Tx queue %u already configured, release it first",
330                       (void *)dev, idx);
331                 return -rte_errno;
332         }
333         if (!desc) {
334                 rte_errno = EINVAL;
335                 ERROR("%p: invalid number of Tx descriptors", (void *)dev);
336                 return -rte_errno;
337         }
338         if (desc != RTE_DIM(*elts)) {
339                 desc = RTE_DIM(*elts);
340                 WARN("%p: increased number of descriptors in Tx queue %u"
341                      " to the next power of two (%u)",
342                      (void *)dev, idx, desc);
343         }
344         /* Allocate and initialize Tx queue. */
345         mlx4_zmallocv_socket("TXQ", vec, RTE_DIM(vec), socket);
346         if (!txq) {
347                 ERROR("%p: unable to allocate queue index %u",
348                       (void *)dev, idx);
349                 return -rte_errno;
350         }
351         *txq = (struct txq){
352                 .priv = priv,
353                 .port_id = dev->data->port_id,
354                 .stats = {
355                         .idx = idx,
356                 },
357                 .socket = socket,
358                 .elts_n = desc,
359                 .elts = elts,
360                 .elts_head = 0,
361                 .elts_tail = 0,
362                 /*
363                  * Request send completion every MLX4_PMD_TX_PER_COMP_REQ
364                  * packets or at least 4 times per ring.
365                  */
366                 .elts_comp_cd =
367                         RTE_MIN(MLX4_PMD_TX_PER_COMP_REQ, desc / 4),
368                 .elts_comp_cd_init =
369                         RTE_MIN(MLX4_PMD_TX_PER_COMP_REQ, desc / 4),
370                 .csum = priv->hw_csum &&
371                         (offloads & (DEV_TX_OFFLOAD_IPV4_CKSUM |
372                                            DEV_TX_OFFLOAD_UDP_CKSUM |
373                                            DEV_TX_OFFLOAD_TCP_CKSUM)),
374                 .csum_l2tun = priv->hw_csum_l2tun &&
375                               (offloads &
376                                DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM),
377                 /* Enable Tx loopback for VF devices. */
378                 .lb = !!priv->vf,
379                 .bounce_buf = bounce_buf,
380         };
381         priv->verbs_alloc_ctx.type = MLX4_VERBS_ALLOC_TYPE_TX_QUEUE;
382         priv->verbs_alloc_ctx.obj = txq;
383         txq->cq = mlx4_glue->create_cq(priv->ctx, desc, NULL, NULL, 0);
384         if (!txq->cq) {
385                 rte_errno = ENOMEM;
386                 ERROR("%p: CQ creation failure: %s",
387                       (void *)dev, strerror(rte_errno));
388                 goto error;
389         }
390         qp_init_attr = (struct ibv_qp_init_attr){
391                 .send_cq = txq->cq,
392                 .recv_cq = txq->cq,
393                 .cap = {
394                         .max_send_wr =
395                                 RTE_MIN(priv->device_attr.max_qp_wr, desc),
396                         .max_send_sge = 1,
397                         .max_inline_data = MLX4_PMD_MAX_INLINE,
398                 },
399                 .qp_type = IBV_QPT_RAW_PACKET,
400                 /* No completion events must occur by default. */
401                 .sq_sig_all = 0,
402         };
403         txq->qp = mlx4_glue->create_qp(priv->pd, &qp_init_attr);
404         if (!txq->qp) {
405                 rte_errno = errno ? errno : EINVAL;
406                 ERROR("%p: QP creation failure: %s",
407                       (void *)dev, strerror(rte_errno));
408                 goto error;
409         }
410         txq->max_inline = qp_init_attr.cap.max_inline_data;
411         ret = mlx4_glue->modify_qp
412                 (txq->qp,
413                  &(struct ibv_qp_attr){
414                         .qp_state = IBV_QPS_INIT,
415                         .port_num = priv->port,
416                  },
417                  IBV_QP_STATE | IBV_QP_PORT);
418         if (ret) {
419                 rte_errno = ret;
420                 ERROR("%p: QP state to IBV_QPS_INIT failed: %s",
421                       (void *)dev, strerror(rte_errno));
422                 goto error;
423         }
424         ret = mlx4_glue->modify_qp
425                 (txq->qp,
426                  &(struct ibv_qp_attr){
427                         .qp_state = IBV_QPS_RTR,
428                  },
429                  IBV_QP_STATE);
430         if (ret) {
431                 rte_errno = ret;
432                 ERROR("%p: QP state to IBV_QPS_RTR failed: %s",
433                       (void *)dev, strerror(rte_errno));
434                 goto error;
435         }
436         ret = mlx4_glue->modify_qp
437                 (txq->qp,
438                  &(struct ibv_qp_attr){
439                         .qp_state = IBV_QPS_RTS,
440                  },
441                  IBV_QP_STATE);
442         if (ret) {
443                 rte_errno = ret;
444                 ERROR("%p: QP state to IBV_QPS_RTS failed: %s",
445                       (void *)dev, strerror(rte_errno));
446                 goto error;
447         }
448         /* Retrieve device queue information. */
449 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
450         dv_qp = (struct mlx4dv_qp){
451                 .comp_mask = MLX4DV_QP_MASK_UAR_MMAP_OFFSET,
452         };
453 #endif
454         mlxdv.cq.in = txq->cq;
455         mlxdv.cq.out = &dv_cq;
456         mlxdv.qp.in = txq->qp;
457         mlxdv.qp.out = &dv_qp;
458         ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
459         if (ret) {
460                 rte_errno = EINVAL;
461                 ERROR("%p: failed to obtain information needed for"
462                       " accessing the device queues", (void *)dev);
463                 goto error;
464         }
465 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
466         if (!(dv_qp.comp_mask & MLX4DV_QP_MASK_UAR_MMAP_OFFSET)) {
467                 WARN("%p: failed to obtain UAR mmap offset", (void *)dev);
468                 dv_qp.uar_mmap_offset = -1; /* Make mmap() fail. */
469         }
470 #endif
471         mlx4_txq_fill_dv_obj_info(txq, &mlxdv);
472         txq_uar_init(txq);
473         /* Save first wqe pointer in the first element. */
474         (&(*txq->elts)[0])->wqe =
475                 (volatile struct mlx4_wqe_ctrl_seg *)txq->msq.buf;
476         if (mlx4_mr_btree_init(&txq->mr_ctrl.cache_bh,
477                                MLX4_MR_BTREE_CACHE_N, socket)) {
478                 /* rte_errno is already set. */
479                 goto error;
480         }
481         /* Save pointer of global generation number to check memory event. */
482         txq->mr_ctrl.dev_gen_ptr = &priv->mr.dev_gen;
483         DEBUG("%p: adding Tx queue %p to list", (void *)dev, (void *)txq);
484         dev->data->tx_queues[idx] = txq;
485         priv->verbs_alloc_ctx.type = MLX4_VERBS_ALLOC_TYPE_NONE;
486         return 0;
487 error:
488         dev->data->tx_queues[idx] = NULL;
489         ret = rte_errno;
490         mlx4_tx_queue_release(txq);
491         rte_errno = ret;
492         assert(rte_errno > 0);
493         priv->verbs_alloc_ctx.type = MLX4_VERBS_ALLOC_TYPE_NONE;
494         return -rte_errno;
495 }
496
497 /**
498  * DPDK callback to release a Tx queue.
499  *
500  * @param dpdk_txq
501  *   Generic Tx queue pointer.
502  */
503 void
504 mlx4_tx_queue_release(void *dpdk_txq)
505 {
506         struct txq *txq = (struct txq *)dpdk_txq;
507         struct mlx4_priv *priv;
508         unsigned int i;
509
510         if (txq == NULL)
511                 return;
512         priv = txq->priv;
513         for (i = 0; i != ETH_DEV(priv)->data->nb_tx_queues; ++i)
514                 if (ETH_DEV(priv)->data->tx_queues[i] == txq) {
515                         DEBUG("%p: removing Tx queue %p from list",
516                               (void *)ETH_DEV(priv), (void *)txq);
517                         ETH_DEV(priv)->data->tx_queues[i] = NULL;
518                         break;
519                 }
520         mlx4_txq_free_elts(txq);
521         if (txq->qp)
522                 claim_zero(mlx4_glue->destroy_qp(txq->qp));
523         if (txq->cq)
524                 claim_zero(mlx4_glue->destroy_cq(txq->cq));
525         mlx4_mr_btree_free(&txq->mr_ctrl.cache_bh);
526         rte_free(txq);
527 }