net/mlx5: remove duplicated reference of Tx doorbell
[dpdk.git] / drivers / net / mlx5 / linux / mlx5_verbs.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  */
4
5 #include <stddef.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <unistd.h>
10 #include <inttypes.h>
11 #include <sys/queue.h>
12
13 #include "mlx5_autoconf.h"
14
15 #include <rte_mbuf.h>
16 #include <rte_malloc.h>
17 #include <ethdev_driver.h>
18 #include <rte_common.h>
19
20 #include <mlx5_glue.h>
21 #include <mlx5_common.h>
22 #include <mlx5_common_mr.h>
23 #include <mlx5_verbs.h>
24 #include <mlx5_rx.h>
25 #include <mlx5_tx.h>
26 #include <mlx5_utils.h>
27 #include <mlx5_malloc.h>
28
29 /**
30  * Modify Rx WQ vlan stripping offload
31  *
32  * @param rxq
33  *   Rx queue.
34  *
35  * @return 0 on success, non-0 otherwise
36  */
37 static int
38 mlx5_rxq_obj_modify_wq_vlan_strip(struct mlx5_rxq_priv *rxq, int on)
39 {
40         uint16_t vlan_offloads =
41                 (on ? IBV_WQ_FLAGS_CVLAN_STRIPPING : 0) |
42                 0;
43         struct ibv_wq_attr mod;
44         mod = (struct ibv_wq_attr){
45                 .attr_mask = IBV_WQ_ATTR_FLAGS,
46                 .flags_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING,
47                 .flags = vlan_offloads,
48         };
49
50         return mlx5_glue->modify_wq(rxq->ctrl->obj->wq, &mod);
51 }
52
53 /**
54  * Modifies the attributes for the specified WQ.
55  *
56  * @param rxq
57  *   Verbs Rx queue.
58  * @param type
59  *   Type of change queue state.
60  *
61  * @return
62  *   0 on success, a negative errno value otherwise and rte_errno is set.
63  */
64 static int
65 mlx5_ibv_modify_wq(struct mlx5_rxq_priv *rxq, uint8_t type)
66 {
67         struct ibv_wq_attr mod = {
68                 .attr_mask = IBV_WQ_ATTR_STATE,
69                 .wq_state = (enum ibv_wq_state)type,
70         };
71
72         return mlx5_glue->modify_wq(rxq->ctrl->obj->wq, &mod);
73 }
74
75 /**
76  * Modify QP using Verbs API.
77  *
78  * @param txq_obj
79  *   Verbs Tx queue object.
80  * @param type
81  *   Type of change queue state.
82  * @param dev_port
83  *   IB device port number.
84  *
85  * @return
86  *   0 on success, a negative errno value otherwise and rte_errno is set.
87  */
88 static int
89 mlx5_ibv_modify_qp(struct mlx5_txq_obj *obj, enum mlx5_txq_modify_type type,
90                    uint8_t dev_port)
91 {
92         struct ibv_qp_attr mod = {
93                 .qp_state = IBV_QPS_RESET,
94                 .port_num = dev_port,
95         };
96         int attr_mask = (IBV_QP_STATE | IBV_QP_PORT);
97         int ret;
98
99         if (type != MLX5_TXQ_MOD_RST2RDY) {
100                 ret = mlx5_glue->modify_qp(obj->qp, &mod, IBV_QP_STATE);
101                 if (ret) {
102                         DRV_LOG(ERR, "Cannot change Tx QP state to RESET %s",
103                                 strerror(errno));
104                         rte_errno = errno;
105                         return ret;
106                 }
107                 if (type == MLX5_TXQ_MOD_RDY2RST)
108                         return 0;
109         }
110         if (type == MLX5_TXQ_MOD_ERR2RDY)
111                 attr_mask = IBV_QP_STATE;
112         mod.qp_state = IBV_QPS_INIT;
113         ret = mlx5_glue->modify_qp(obj->qp, &mod, attr_mask);
114         if (ret) {
115                 DRV_LOG(ERR, "Cannot change Tx QP state to INIT %s",
116                         strerror(errno));
117                 rte_errno = errno;
118                 return ret;
119         }
120         mod.qp_state = IBV_QPS_RTR;
121         ret = mlx5_glue->modify_qp(obj->qp, &mod, IBV_QP_STATE);
122         if (ret) {
123                 DRV_LOG(ERR, "Cannot change Tx QP state to RTR %s",
124                         strerror(errno));
125                 rte_errno = errno;
126                 return ret;
127         }
128         mod.qp_state = IBV_QPS_RTS;
129         ret = mlx5_glue->modify_qp(obj->qp, &mod, IBV_QP_STATE);
130         if (ret) {
131                 DRV_LOG(ERR, "Cannot change Tx QP state to RTS %s",
132                         strerror(errno));
133                 rte_errno = errno;
134                 return ret;
135         }
136         return 0;
137 }
138
139 /**
140  * Create a CQ Verbs object.
141  *
142  * @param rxq
143  *   Pointer to Rx queue.
144  *
145  * @return
146  *   The Verbs CQ object initialized, NULL otherwise and rte_errno is set.
147  */
148 static struct ibv_cq *
149 mlx5_rxq_ibv_cq_create(struct mlx5_rxq_priv *rxq)
150 {
151         struct mlx5_priv *priv = rxq->priv;
152         struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
153         struct mlx5_rxq_data *rxq_data = &rxq_ctrl->rxq;
154         struct mlx5_rxq_obj *rxq_obj = rxq_ctrl->obj;
155         unsigned int cqe_n = mlx5_rxq_cqe_num(rxq_data);
156         struct {
157                 struct ibv_cq_init_attr_ex ibv;
158                 struct mlx5dv_cq_init_attr mlx5;
159         } cq_attr;
160
161         cq_attr.ibv = (struct ibv_cq_init_attr_ex){
162                 .cqe = cqe_n,
163                 .channel = rxq_obj->ibv_channel,
164                 .comp_mask = 0,
165         };
166         cq_attr.mlx5 = (struct mlx5dv_cq_init_attr){
167                 .comp_mask = 0,
168         };
169         if (priv->config.cqe_comp && !rxq_data->hw_timestamp) {
170                 cq_attr.mlx5.comp_mask |=
171                                 MLX5DV_CQ_INIT_ATTR_MASK_COMPRESSED_CQE;
172                 rxq_data->byte_mask = UINT32_MAX;
173 #ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
174                 if (mlx5_rxq_mprq_enabled(rxq_data)) {
175                         cq_attr.mlx5.cqe_comp_res_format =
176                                         MLX5DV_CQE_RES_FORMAT_CSUM_STRIDX;
177                         rxq_data->mcqe_format =
178                                         MLX5_CQE_RESP_FORMAT_CSUM_STRIDX;
179                 } else {
180                         cq_attr.mlx5.cqe_comp_res_format =
181                                         MLX5DV_CQE_RES_FORMAT_HASH;
182                         rxq_data->mcqe_format =
183                                         MLX5_CQE_RESP_FORMAT_HASH;
184                 }
185 #else
186                 cq_attr.mlx5.cqe_comp_res_format = MLX5DV_CQE_RES_FORMAT_HASH;
187                 rxq_data->mcqe_format = MLX5_CQE_RESP_FORMAT_HASH;
188 #endif
189                 /*
190                  * For vectorized Rx, it must not be doubled in order to
191                  * make cq_ci and rq_ci aligned.
192                  */
193                 if (mlx5_rxq_check_vec_support(rxq_data) < 0)
194                         cq_attr.ibv.cqe *= 2;
195         } else if (priv->config.cqe_comp && rxq_data->hw_timestamp) {
196                 DRV_LOG(DEBUG,
197                         "Port %u Rx CQE compression is disabled for HW"
198                         " timestamp.",
199                         priv->dev_data->port_id);
200         }
201 #ifdef HAVE_IBV_MLX5_MOD_CQE_128B_PAD
202         if (RTE_CACHE_LINE_SIZE == 128) {
203                 cq_attr.mlx5.comp_mask |= MLX5DV_CQ_INIT_ATTR_MASK_FLAGS;
204                 cq_attr.mlx5.flags |= MLX5DV_CQ_INIT_ATTR_FLAGS_CQE_PAD;
205         }
206 #endif
207         return mlx5_glue->cq_ex_to_cq(mlx5_glue->dv_create_cq
208                                                            (priv->sh->cdev->ctx,
209                                                             &cq_attr.ibv,
210                                                             &cq_attr.mlx5));
211 }
212
213 /**
214  * Create a WQ Verbs object.
215  *
216  * @param rxq
217  *   Pointer to Rx queue.
218  *
219  * @return
220  *   The Verbs WQ object initialized, NULL otherwise and rte_errno is set.
221  */
222 static struct ibv_wq *
223 mlx5_rxq_ibv_wq_create(struct mlx5_rxq_priv *rxq)
224 {
225         struct mlx5_priv *priv = rxq->priv;
226         struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
227         struct mlx5_rxq_data *rxq_data = &rxq_ctrl->rxq;
228         struct mlx5_rxq_obj *rxq_obj = rxq_ctrl->obj;
229         unsigned int wqe_n = 1 << rxq_data->elts_n;
230         struct {
231                 struct ibv_wq_init_attr ibv;
232 #ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
233                 struct mlx5dv_wq_init_attr mlx5;
234 #endif
235         } wq_attr;
236
237         wq_attr.ibv = (struct ibv_wq_init_attr){
238                 .wq_context = NULL, /* Could be useful in the future. */
239                 .wq_type = IBV_WQT_RQ,
240                 /* Max number of outstanding WRs. */
241                 .max_wr = wqe_n >> rxq_data->sges_n,
242                 /* Max number of scatter/gather elements in a WR. */
243                 .max_sge = 1 << rxq_data->sges_n,
244                 .pd = priv->sh->cdev->pd,
245                 .cq = rxq_obj->ibv_cq,
246                 .comp_mask = IBV_WQ_FLAGS_CVLAN_STRIPPING | 0,
247                 .create_flags = (rxq_data->vlan_strip ?
248                                  IBV_WQ_FLAGS_CVLAN_STRIPPING : 0),
249         };
250         /* By default, FCS (CRC) is stripped by hardware. */
251         if (rxq_data->crc_present) {
252                 wq_attr.ibv.create_flags |= IBV_WQ_FLAGS_SCATTER_FCS;
253                 wq_attr.ibv.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
254         }
255         if (priv->config.hw_padding) {
256 #if defined(HAVE_IBV_WQ_FLAG_RX_END_PADDING)
257                 wq_attr.ibv.create_flags |= IBV_WQ_FLAG_RX_END_PADDING;
258                 wq_attr.ibv.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
259 #elif defined(HAVE_IBV_WQ_FLAGS_PCI_WRITE_END_PADDING)
260                 wq_attr.ibv.create_flags |= IBV_WQ_FLAGS_PCI_WRITE_END_PADDING;
261                 wq_attr.ibv.comp_mask |= IBV_WQ_INIT_ATTR_FLAGS;
262 #endif
263         }
264 #ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
265         wq_attr.mlx5 = (struct mlx5dv_wq_init_attr){
266                 .comp_mask = 0,
267         };
268         if (mlx5_rxq_mprq_enabled(rxq_data)) {
269                 struct mlx5dv_striding_rq_init_attr *mprq_attr =
270                                                 &wq_attr.mlx5.striding_rq_attrs;
271
272                 wq_attr.mlx5.comp_mask |= MLX5DV_WQ_INIT_ATTR_MASK_STRIDING_RQ;
273                 *mprq_attr = (struct mlx5dv_striding_rq_init_attr){
274                         .single_stride_log_num_of_bytes = rxq_data->strd_sz_n,
275                         .single_wqe_log_num_of_strides = rxq_data->strd_num_n,
276                         .two_byte_shift_en = MLX5_MPRQ_TWO_BYTE_SHIFT,
277                 };
278         }
279         rxq_obj->wq = mlx5_glue->dv_create_wq(priv->sh->cdev->ctx, &wq_attr.ibv,
280                                               &wq_attr.mlx5);
281 #else
282         rxq_obj->wq = mlx5_glue->create_wq(priv->sh->cdev->ctx, &wq_attr.ibv);
283 #endif
284         if (rxq_obj->wq) {
285                 /*
286                  * Make sure number of WRs*SGEs match expectations since a queue
287                  * cannot allocate more than "desc" buffers.
288                  */
289                 if (wq_attr.ibv.max_wr != (wqe_n >> rxq_data->sges_n) ||
290                     wq_attr.ibv.max_sge != (1u << rxq_data->sges_n)) {
291                         DRV_LOG(ERR,
292                                 "Port %u Rx queue %u requested %u*%u but got"
293                                 " %u*%u WRs*SGEs.",
294                                 priv->dev_data->port_id, rxq->idx,
295                                 wqe_n >> rxq_data->sges_n,
296                                 (1 << rxq_data->sges_n),
297                                 wq_attr.ibv.max_wr, wq_attr.ibv.max_sge);
298                         claim_zero(mlx5_glue->destroy_wq(rxq_obj->wq));
299                         rxq_obj->wq = NULL;
300                         rte_errno = EINVAL;
301                 }
302         }
303         return rxq_obj->wq;
304 }
305
306 /**
307  * Create the Rx queue Verbs object.
308  *
309  * @param rxq
310  *   Pointer to Rx queue.
311  *
312  * @return
313  *   0 on success, a negative errno value otherwise and rte_errno is set.
314  */
315 static int
316 mlx5_rxq_ibv_obj_new(struct mlx5_rxq_priv *rxq)
317 {
318         uint16_t idx = rxq->idx;
319         struct mlx5_priv *priv = rxq->priv;
320         uint16_t port_id = priv->dev_data->port_id;
321         struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
322         struct mlx5_rxq_data *rxq_data = &rxq_ctrl->rxq;
323         struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
324         struct mlx5dv_cq cq_info;
325         struct mlx5dv_rwq rwq;
326         int ret = 0;
327         struct mlx5dv_obj obj;
328
329         MLX5_ASSERT(rxq_data);
330         MLX5_ASSERT(tmpl);
331         tmpl->rxq_ctrl = rxq_ctrl;
332         if (rxq_ctrl->irq) {
333                 tmpl->ibv_channel =
334                         mlx5_glue->create_comp_channel(priv->sh->cdev->ctx);
335                 if (!tmpl->ibv_channel) {
336                         DRV_LOG(ERR, "Port %u: comp channel creation failure.",
337                                 port_id);
338                         rte_errno = ENOMEM;
339                         goto error;
340                 }
341                 tmpl->fd = ((struct ibv_comp_channel *)(tmpl->ibv_channel))->fd;
342         }
343         /* Create CQ using Verbs API. */
344         tmpl->ibv_cq = mlx5_rxq_ibv_cq_create(rxq);
345         if (!tmpl->ibv_cq) {
346                 DRV_LOG(ERR, "Port %u Rx queue %u CQ creation failure.",
347                         port_id, idx);
348                 rte_errno = ENOMEM;
349                 goto error;
350         }
351         obj.cq.in = tmpl->ibv_cq;
352         obj.cq.out = &cq_info;
353         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ);
354         if (ret) {
355                 rte_errno = ret;
356                 goto error;
357         }
358         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
359                 DRV_LOG(ERR,
360                         "Port %u wrong MLX5_CQE_SIZE environment "
361                         "variable value: it should be set to %u.",
362                         port_id, RTE_CACHE_LINE_SIZE);
363                 rte_errno = EINVAL;
364                 goto error;
365         }
366         /* Fill the rings. */
367         rxq_data->cqe_n = log2above(cq_info.cqe_cnt);
368         rxq_data->cq_db = cq_info.dbrec;
369         rxq_data->cqes = (volatile struct mlx5_cqe (*)[])(uintptr_t)cq_info.buf;
370         rxq_data->cq_uar = cq_info.cq_uar;
371         rxq_data->cqn = cq_info.cqn;
372         /* Create WQ (RQ) using Verbs API. */
373         tmpl->wq = mlx5_rxq_ibv_wq_create(rxq);
374         if (!tmpl->wq) {
375                 DRV_LOG(ERR, "Port %u Rx queue %u WQ creation failure.",
376                         port_id, idx);
377                 rte_errno = ENOMEM;
378                 goto error;
379         }
380         /* Change queue state to ready. */
381         ret = mlx5_ibv_modify_wq(rxq, IBV_WQS_RDY);
382         if (ret) {
383                 DRV_LOG(ERR,
384                         "Port %u Rx queue %u WQ state to IBV_WQS_RDY failed.",
385                         port_id, idx);
386                 rte_errno = ret;
387                 goto error;
388         }
389         obj.rwq.in = tmpl->wq;
390         obj.rwq.out = &rwq;
391         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_RWQ);
392         if (ret) {
393                 rte_errno = ret;
394                 goto error;
395         }
396         rxq_data->wqes = rwq.buf;
397         rxq_data->rq_db = rwq.dbrec;
398         rxq_data->cq_arm_sn = 0;
399         mlx5_rxq_initialize(rxq_data);
400         rxq_data->cq_ci = 0;
401         priv->dev_data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
402         rxq_ctrl->wqn = ((struct ibv_wq *)(tmpl->wq))->wq_num;
403         return 0;
404 error:
405         ret = rte_errno; /* Save rte_errno before cleanup. */
406         if (tmpl->wq)
407                 claim_zero(mlx5_glue->destroy_wq(tmpl->wq));
408         if (tmpl->ibv_cq)
409                 claim_zero(mlx5_glue->destroy_cq(tmpl->ibv_cq));
410         if (tmpl->ibv_channel)
411                 claim_zero(mlx5_glue->destroy_comp_channel(tmpl->ibv_channel));
412         rte_errno = ret; /* Restore rte_errno. */
413         return -rte_errno;
414 }
415
416 /**
417  * Release an Rx verbs queue object.
418  *
419  * @param rxq
420  *   Pointer to Rx queue.
421  */
422 static void
423 mlx5_rxq_ibv_obj_release(struct mlx5_rxq_priv *rxq)
424 {
425         struct mlx5_rxq_obj *rxq_obj = rxq->ctrl->obj;
426
427         if (rxq_obj == NULL || rxq_obj->wq == NULL)
428                 return;
429         claim_zero(mlx5_glue->destroy_wq(rxq_obj->wq));
430         rxq_obj->wq = NULL;
431         MLX5_ASSERT(rxq_obj->ibv_cq);
432         claim_zero(mlx5_glue->destroy_cq(rxq_obj->ibv_cq));
433         if (rxq_obj->ibv_channel)
434                 claim_zero(mlx5_glue->destroy_comp_channel
435                                                         (rxq_obj->ibv_channel));
436         rxq->ctrl->started = false;
437 }
438
439 /**
440  * Get event for an Rx verbs queue object.
441  *
442  * @param rxq_obj
443  *   Verbs Rx queue object.
444  *
445  * @return
446  *   0 on success, a negative errno value otherwise and rte_errno is set.
447  */
448 static int
449 mlx5_rx_ibv_get_event(struct mlx5_rxq_obj *rxq_obj)
450 {
451         struct ibv_cq *ev_cq;
452         void *ev_ctx;
453         int ret = mlx5_glue->get_cq_event(rxq_obj->ibv_channel,
454                                           &ev_cq, &ev_ctx);
455
456         if (ret < 0 || ev_cq != rxq_obj->ibv_cq)
457                 goto exit;
458         mlx5_glue->ack_cq_events(rxq_obj->ibv_cq, 1);
459         return 0;
460 exit:
461         if (ret < 0)
462                 rte_errno = errno;
463         else
464                 rte_errno = EINVAL;
465         return -rte_errno;
466 }
467
468 /**
469  * Creates a receive work queue as a filed of indirection table.
470  *
471  * @param dev
472  *   Pointer to Ethernet device.
473  * @param log_n
474  *   Log of number of queues in the array.
475  * @param ind_tbl
476  *   Verbs indirection table object.
477  *
478  * @return
479  *   0 on success, a negative errno value otherwise and rte_errno is set.
480  */
481 static int
482 mlx5_ibv_ind_table_new(struct rte_eth_dev *dev, const unsigned int log_n,
483                        struct mlx5_ind_table_obj *ind_tbl)
484 {
485         struct mlx5_priv *priv = dev->data->dev_private;
486         struct ibv_wq *wq[1 << log_n];
487         unsigned int i, j;
488
489         MLX5_ASSERT(ind_tbl);
490         for (i = 0; i != ind_tbl->queues_n; ++i) {
491                 struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev,
492                                                          ind_tbl->queues[i]);
493
494                 wq[i] = rxq->ctrl->obj->wq;
495         }
496         MLX5_ASSERT(i > 0);
497         /* Finalise indirection table. */
498         for (j = 0; i != (unsigned int)(1 << log_n); ++j, ++i)
499                 wq[i] = wq[j];
500         ind_tbl->ind_table = mlx5_glue->create_rwq_ind_table
501                                         (priv->sh->cdev->ctx,
502                                          &(struct ibv_rwq_ind_table_init_attr){
503                                                  .log_ind_tbl_size = log_n,
504                                                  .ind_tbl = wq,
505                                                  .comp_mask = 0,
506                                          });
507         if (!ind_tbl->ind_table) {
508                 rte_errno = errno;
509                 return -rte_errno;
510         }
511         return 0;
512 }
513
514 /**
515  * Destroys the specified Indirection Table.
516  *
517  * @param ind_table
518  *   Indirection table to release.
519  */
520 static void
521 mlx5_ibv_ind_table_destroy(struct mlx5_ind_table_obj *ind_tbl)
522 {
523         claim_zero(mlx5_glue->destroy_rwq_ind_table(ind_tbl->ind_table));
524 }
525
526 /**
527  * Create an Rx Hash queue.
528  *
529  * @param dev
530  *   Pointer to Ethernet device.
531  * @param hrxq
532  *   Pointer to Rx Hash queue.
533  * @param tunnel
534  *   Tunnel type.
535  *
536  * @return
537  *   0 on success, a negative errno value otherwise and rte_errno is set.
538  */
539 static int
540 mlx5_ibv_hrxq_new(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq,
541                   int tunnel __rte_unused)
542 {
543         struct mlx5_priv *priv = dev->data->dev_private;
544         struct ibv_qp *qp = NULL;
545         struct mlx5_ind_table_obj *ind_tbl = hrxq->ind_table;
546         const uint8_t *rss_key = hrxq->rss_key;
547         uint64_t hash_fields = hrxq->hash_fields;
548         int err;
549 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
550         struct mlx5dv_qp_init_attr qp_init_attr;
551
552         memset(&qp_init_attr, 0, sizeof(qp_init_attr));
553         if (tunnel) {
554                 qp_init_attr.comp_mask =
555                                        MLX5DV_QP_INIT_ATTR_MASK_QP_CREATE_FLAGS;
556                 qp_init_attr.create_flags = MLX5DV_QP_CREATE_TUNNEL_OFFLOADS;
557         }
558 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
559         if (dev->data->dev_conf.lpbk_mode) {
560                 /* Allow packet sent from NIC loop back w/o source MAC check. */
561                 qp_init_attr.comp_mask |=
562                                 MLX5DV_QP_INIT_ATTR_MASK_QP_CREATE_FLAGS;
563                 qp_init_attr.create_flags |=
564                                 MLX5DV_QP_CREATE_TIR_ALLOW_SELF_LOOPBACK_UC;
565         }
566 #endif
567         qp = mlx5_glue->dv_create_qp
568                         (priv->sh->cdev->ctx,
569                          &(struct ibv_qp_init_attr_ex){
570                                 .qp_type = IBV_QPT_RAW_PACKET,
571                                 .comp_mask =
572                                         IBV_QP_INIT_ATTR_PD |
573                                         IBV_QP_INIT_ATTR_IND_TABLE |
574                                         IBV_QP_INIT_ATTR_RX_HASH,
575                                 .rx_hash_conf = (struct ibv_rx_hash_conf){
576                                         .rx_hash_function =
577                                                 IBV_RX_HASH_FUNC_TOEPLITZ,
578                                         .rx_hash_key_len = hrxq->rss_key_len,
579                                         .rx_hash_key =
580                                                 (void *)(uintptr_t)rss_key,
581                                         .rx_hash_fields_mask = hash_fields,
582                                 },
583                                 .rwq_ind_tbl = ind_tbl->ind_table,
584                                 .pd = priv->sh->cdev->pd,
585                           },
586                           &qp_init_attr);
587 #else
588         qp = mlx5_glue->create_qp_ex
589                         (priv->sh->cdev->ctx,
590                          &(struct ibv_qp_init_attr_ex){
591                                 .qp_type = IBV_QPT_RAW_PACKET,
592                                 .comp_mask =
593                                         IBV_QP_INIT_ATTR_PD |
594                                         IBV_QP_INIT_ATTR_IND_TABLE |
595                                         IBV_QP_INIT_ATTR_RX_HASH,
596                                 .rx_hash_conf = (struct ibv_rx_hash_conf){
597                                         .rx_hash_function =
598                                                 IBV_RX_HASH_FUNC_TOEPLITZ,
599                                         .rx_hash_key_len = hrxq->rss_key_len,
600                                         .rx_hash_key =
601                                                 (void *)(uintptr_t)rss_key,
602                                         .rx_hash_fields_mask = hash_fields,
603                                 },
604                                 .rwq_ind_tbl = ind_tbl->ind_table,
605                                 .pd = priv->sh->cdev->pd,
606                          });
607 #endif
608         if (!qp) {
609                 rte_errno = errno;
610                 goto error;
611         }
612         hrxq->qp = qp;
613 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
614         hrxq->action = mlx5_glue->dv_create_flow_action_dest_ibv_qp(hrxq->qp);
615         if (!hrxq->action) {
616                 rte_errno = errno;
617                 goto error;
618         }
619 #endif
620         return 0;
621 error:
622         err = rte_errno; /* Save rte_errno before cleanup. */
623         if (qp)
624                 claim_zero(mlx5_glue->destroy_qp(qp));
625         rte_errno = err; /* Restore rte_errno. */
626         return -rte_errno;
627 }
628
629 /**
630  * Destroy a Verbs queue pair.
631  *
632  * @param hrxq
633  *   Hash Rx queue to release its qp.
634  */
635 static void
636 mlx5_ibv_qp_destroy(struct mlx5_hrxq *hrxq)
637 {
638         claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
639 }
640
641 /**
642  * Release a drop Rx queue Verbs object.
643  *
644  * @param dev
645  *   Pointer to Ethernet device.
646  */
647 static void
648 mlx5_rxq_ibv_obj_drop_release(struct rte_eth_dev *dev)
649 {
650         struct mlx5_priv *priv = dev->data->dev_private;
651         struct mlx5_rxq_priv *rxq = priv->drop_queue.rxq;
652         struct mlx5_rxq_obj *rxq_obj;
653
654         if (rxq == NULL)
655                 return;
656         if (rxq->ctrl == NULL)
657                 goto free_priv;
658         rxq_obj = rxq->ctrl->obj;
659         if (rxq_obj == NULL)
660                 goto free_ctrl;
661         if (rxq_obj->wq)
662                 claim_zero(mlx5_glue->destroy_wq(rxq_obj->wq));
663         if (rxq_obj->ibv_cq)
664                 claim_zero(mlx5_glue->destroy_cq(rxq_obj->ibv_cq));
665         mlx5_free(rxq_obj);
666 free_ctrl:
667         mlx5_free(rxq->ctrl);
668 free_priv:
669         mlx5_free(rxq);
670         priv->drop_queue.rxq = NULL;
671 }
672
673 /**
674  * Create a drop Rx queue Verbs object.
675  *
676  * @param dev
677  *   Pointer to Ethernet device.
678  *
679  * @return
680  *   0 on success, a negative errno value otherwise and rte_errno is set.
681  */
682 static int
683 mlx5_rxq_ibv_obj_drop_create(struct rte_eth_dev *dev)
684 {
685         struct mlx5_priv *priv = dev->data->dev_private;
686         struct ibv_context *ctx = priv->sh->cdev->ctx;
687         struct mlx5_rxq_priv *rxq = priv->drop_queue.rxq;
688         struct mlx5_rxq_ctrl *rxq_ctrl = NULL;
689         struct mlx5_rxq_obj *rxq_obj = NULL;
690
691         if (rxq != NULL)
692                 return 0;
693         rxq = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq), 0, SOCKET_ID_ANY);
694         if (rxq == NULL) {
695                 DRV_LOG(DEBUG, "Port %u cannot allocate drop Rx queue memory.",
696                       dev->data->port_id);
697                 rte_errno = ENOMEM;
698                 return -rte_errno;
699         }
700         priv->drop_queue.rxq = rxq;
701         rxq_ctrl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq_ctrl), 0,
702                                SOCKET_ID_ANY);
703         if (rxq_ctrl == NULL) {
704                 DRV_LOG(DEBUG, "Port %u cannot allocate drop Rx queue control memory.",
705                       dev->data->port_id);
706                 rte_errno = ENOMEM;
707                 goto error;
708         }
709         rxq->ctrl = rxq_ctrl;
710         rxq_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq_obj), 0,
711                               SOCKET_ID_ANY);
712         if (rxq_obj == NULL) {
713                 DRV_LOG(DEBUG, "Port %u cannot allocate drop Rx queue memory.",
714                       dev->data->port_id);
715                 rte_errno = ENOMEM;
716                 goto error;
717         }
718         rxq_ctrl->obj = rxq_obj;
719         rxq_obj->ibv_cq = mlx5_glue->create_cq(ctx, 1, NULL, NULL, 0);
720         if (!rxq_obj->ibv_cq) {
721                 DRV_LOG(DEBUG, "Port %u cannot allocate CQ for drop queue.",
722                       dev->data->port_id);
723                 rte_errno = errno;
724                 goto error;
725         }
726         rxq_obj->wq = mlx5_glue->create_wq(ctx, &(struct ibv_wq_init_attr){
727                                                     .wq_type = IBV_WQT_RQ,
728                                                     .max_wr = 1,
729                                                     .max_sge = 1,
730                                                     .pd = priv->sh->cdev->pd,
731                                                     .cq = rxq_obj->ibv_cq,
732                                               });
733         if (!rxq_obj->wq) {
734                 DRV_LOG(DEBUG, "Port %u cannot allocate WQ for drop queue.",
735                       dev->data->port_id);
736                 rte_errno = errno;
737                 goto error;
738         }
739         return 0;
740 error:
741         mlx5_rxq_ibv_obj_drop_release(dev);
742         return -rte_errno;
743 }
744
745 /**
746  * Create a Verbs drop action for Rx Hash queue.
747  *
748  * @param dev
749  *   Pointer to Ethernet device.
750  *
751  * @return
752  *   0 on success, a negative errno value otherwise and rte_errno is set.
753  */
754 static int
755 mlx5_ibv_drop_action_create(struct rte_eth_dev *dev)
756 {
757         struct mlx5_priv *priv = dev->data->dev_private;
758         struct mlx5_hrxq *hrxq = priv->drop_queue.hrxq;
759         struct ibv_rwq_ind_table *ind_tbl = NULL;
760         struct mlx5_rxq_obj *rxq;
761         int ret;
762
763         MLX5_ASSERT(hrxq && hrxq->ind_table);
764         ret = mlx5_rxq_ibv_obj_drop_create(dev);
765         if (ret < 0)
766                 goto error;
767         rxq = priv->drop_queue.rxq->ctrl->obj;
768         ind_tbl = mlx5_glue->create_rwq_ind_table
769                                 (priv->sh->cdev->ctx,
770                                  &(struct ibv_rwq_ind_table_init_attr){
771                                         .log_ind_tbl_size = 0,
772                                         .ind_tbl = (struct ibv_wq **)&rxq->wq,
773                                         .comp_mask = 0,
774                                  });
775         if (!ind_tbl) {
776                 DRV_LOG(DEBUG, "Port %u"
777                         " cannot allocate indirection table for drop queue.",
778                         dev->data->port_id);
779                 rte_errno = errno;
780                 goto error;
781         }
782         hrxq->qp = mlx5_glue->create_qp_ex(priv->sh->cdev->ctx,
783                  &(struct ibv_qp_init_attr_ex){
784                         .qp_type = IBV_QPT_RAW_PACKET,
785                         .comp_mask = IBV_QP_INIT_ATTR_PD |
786                                      IBV_QP_INIT_ATTR_IND_TABLE |
787                                      IBV_QP_INIT_ATTR_RX_HASH,
788                         .rx_hash_conf = (struct ibv_rx_hash_conf){
789                                 .rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ,
790                                 .rx_hash_key_len = MLX5_RSS_HASH_KEY_LEN,
791                                 .rx_hash_key = rss_hash_default_key,
792                                 .rx_hash_fields_mask = 0,
793                                 },
794                         .rwq_ind_tbl = ind_tbl,
795                         .pd = priv->sh->cdev->pd
796                  });
797         if (!hrxq->qp) {
798                 DRV_LOG(DEBUG, "Port %u cannot allocate QP for drop queue.",
799                       dev->data->port_id);
800                 rte_errno = errno;
801                 goto error;
802         }
803 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
804         hrxq->action = mlx5_glue->dv_create_flow_action_dest_ibv_qp(hrxq->qp);
805         if (!hrxq->action) {
806                 rte_errno = errno;
807                 goto error;
808         }
809 #endif
810         hrxq->ind_table->ind_table = ind_tbl;
811         return 0;
812 error:
813         if (hrxq->qp)
814                 claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
815         if (ind_tbl)
816                 claim_zero(mlx5_glue->destroy_rwq_ind_table(ind_tbl));
817         if (priv->drop_queue.rxq)
818                 mlx5_rxq_ibv_obj_drop_release(dev);
819         return -rte_errno;
820 }
821
822 /**
823  * Release a drop hash Rx queue.
824  *
825  * @param dev
826  *   Pointer to Ethernet device.
827  */
828 static void
829 mlx5_ibv_drop_action_destroy(struct rte_eth_dev *dev)
830 {
831         struct mlx5_priv *priv = dev->data->dev_private;
832         struct mlx5_hrxq *hrxq = priv->drop_queue.hrxq;
833         struct ibv_rwq_ind_table *ind_tbl = hrxq->ind_table->ind_table;
834
835 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
836         claim_zero(mlx5_glue->destroy_flow_action(hrxq->action));
837 #endif
838         claim_zero(mlx5_glue->destroy_qp(hrxq->qp));
839         claim_zero(mlx5_glue->destroy_rwq_ind_table(ind_tbl));
840         mlx5_rxq_ibv_obj_drop_release(dev);
841 }
842
843 /**
844  * Create a QP Verbs object.
845  *
846  * @param dev
847  *   Pointer to Ethernet device.
848  * @param idx
849  *   Queue index in DPDK Tx queue array.
850  *
851  * @return
852  *   The QP Verbs object, NULL otherwise and rte_errno is set.
853  */
854 static struct ibv_qp *
855 mlx5_txq_ibv_qp_create(struct rte_eth_dev *dev, uint16_t idx)
856 {
857         struct mlx5_priv *priv = dev->data->dev_private;
858         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
859         struct mlx5_txq_ctrl *txq_ctrl =
860                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
861         struct ibv_qp *qp_obj = NULL;
862         struct ibv_qp_init_attr_ex qp_attr = { 0 };
863         const int desc = 1 << txq_data->elts_n;
864
865         MLX5_ASSERT(txq_ctrl->obj->cq);
866         /* CQ to be associated with the send queue. */
867         qp_attr.send_cq = txq_ctrl->obj->cq;
868         /* CQ to be associated with the receive queue. */
869         qp_attr.recv_cq = txq_ctrl->obj->cq;
870         /* Max number of outstanding WRs. */
871         qp_attr.cap.max_send_wr = ((priv->sh->device_attr.max_qp_wr < desc) ?
872                                    priv->sh->device_attr.max_qp_wr : desc);
873         /*
874          * Max number of scatter/gather elements in a WR, must be 1 to prevent
875          * libmlx5 from trying to affect must be 1 to prevent libmlx5 from
876          * trying to affect too much memory. TX gather is not impacted by the
877          * device_attr.max_sge limit and will still work properly.
878          */
879         qp_attr.cap.max_send_sge = 1;
880         qp_attr.qp_type = IBV_QPT_RAW_PACKET,
881         /* Do *NOT* enable this, completions events are managed per Tx burst. */
882         qp_attr.sq_sig_all = 0;
883         qp_attr.pd = priv->sh->cdev->pd;
884         qp_attr.comp_mask = IBV_QP_INIT_ATTR_PD;
885         if (txq_data->inlen_send)
886                 qp_attr.cap.max_inline_data = txq_ctrl->max_inline_data;
887         if (txq_data->tso_en) {
888                 qp_attr.max_tso_header = txq_ctrl->max_tso_header;
889                 qp_attr.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
890         }
891         qp_obj = mlx5_glue->create_qp_ex(priv->sh->cdev->ctx, &qp_attr);
892         if (qp_obj == NULL) {
893                 DRV_LOG(ERR, "Port %u Tx queue %u QP creation failure.",
894                         dev->data->port_id, idx);
895                 rte_errno = errno;
896         }
897         return qp_obj;
898 }
899
900 /**
901  * Create the Tx queue Verbs object.
902  *
903  * @param dev
904  *   Pointer to Ethernet device.
905  * @param idx
906  *   Queue index in DPDK Tx queue array.
907  *
908  * @return
909  *   0 on success, a negative errno value otherwise and rte_errno is set.
910  */
911 int
912 mlx5_txq_ibv_obj_new(struct rte_eth_dev *dev, uint16_t idx)
913 {
914         struct mlx5_priv *priv = dev->data->dev_private;
915         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
916         struct mlx5_txq_ctrl *txq_ctrl =
917                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
918         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
919         unsigned int cqe_n;
920         struct mlx5dv_qp qp;
921         struct mlx5dv_cq cq_info;
922         struct mlx5dv_obj obj;
923         const int desc = 1 << txq_data->elts_n;
924         int ret = 0;
925
926         MLX5_ASSERT(txq_data);
927         MLX5_ASSERT(txq_obj);
928         txq_obj->txq_ctrl = txq_ctrl;
929         if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
930                 DRV_LOG(ERR, "Port %u MLX5_ENABLE_CQE_COMPRESSION "
931                         "must never be set.", dev->data->port_id);
932                 rte_errno = EINVAL;
933                 return -rte_errno;
934         }
935         cqe_n = desc / MLX5_TX_COMP_THRESH +
936                 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
937         txq_obj->cq = mlx5_glue->create_cq(priv->sh->cdev->ctx, cqe_n,
938                                            NULL, NULL, 0);
939         if (txq_obj->cq == NULL) {
940                 DRV_LOG(ERR, "Port %u Tx queue %u CQ creation failure.",
941                         dev->data->port_id, idx);
942                 rte_errno = errno;
943                 goto error;
944         }
945         txq_obj->qp = mlx5_txq_ibv_qp_create(dev, idx);
946         if (txq_obj->qp == NULL) {
947                 rte_errno = errno;
948                 goto error;
949         }
950         ret = mlx5_ibv_modify_qp(txq_obj, MLX5_TXQ_MOD_RST2RDY,
951                                  (uint8_t)priv->dev_port);
952         if (ret) {
953                 DRV_LOG(ERR, "Port %u Tx queue %u QP state modifying failed.",
954                         dev->data->port_id, idx);
955                 rte_errno = errno;
956                 goto error;
957         }
958         qp.comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET;
959 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
960         /* If using DevX, need additional mask to read tisn value. */
961         if (priv->sh->devx && !priv->sh->tdn)
962                 qp.comp_mask |= MLX5DV_QP_MASK_RAW_QP_HANDLES;
963 #endif
964         obj.cq.in = txq_obj->cq;
965         obj.cq.out = &cq_info;
966         obj.qp.in = txq_obj->qp;
967         obj.qp.out = &qp;
968         ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
969         if (ret != 0) {
970                 rte_errno = errno;
971                 goto error;
972         }
973         if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
974                 DRV_LOG(ERR,
975                         "Port %u wrong MLX5_CQE_SIZE environment variable"
976                         " value: it should be set to %u.",
977                         dev->data->port_id, RTE_CACHE_LINE_SIZE);
978                 rte_errno = EINVAL;
979                 goto error;
980         }
981         txq_data->cqe_n = log2above(cq_info.cqe_cnt);
982         txq_data->cqe_s = 1 << txq_data->cqe_n;
983         txq_data->cqe_m = txq_data->cqe_s - 1;
984         txq_data->qp_num_8s = ((struct ibv_qp *)txq_obj->qp)->qp_num << 8;
985         txq_data->wqes = qp.sq.buf;
986         txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
987         txq_data->wqe_s = 1 << txq_data->wqe_n;
988         txq_data->wqe_m = txq_data->wqe_s - 1;
989         txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s;
990         txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
991         txq_data->cq_db = cq_info.dbrec;
992         txq_data->cqes = (volatile struct mlx5_cqe *)cq_info.buf;
993         txq_data->cq_ci = 0;
994         txq_data->cq_pi = 0;
995         txq_data->wqe_ci = 0;
996         txq_data->wqe_pi = 0;
997         txq_data->wqe_comp = 0;
998         txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV;
999 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
1000         /*
1001          * If using DevX need to query and store TIS transport domain value.
1002          * This is done once per port.
1003          * Will use this value on Rx, when creating matching TIR.
1004          */
1005         if (priv->sh->devx && !priv->sh->tdn) {
1006                 ret = mlx5_devx_cmd_qp_query_tis_td(txq_obj->qp, qp.tisn,
1007                                                     &priv->sh->tdn);
1008                 if (ret) {
1009                         DRV_LOG(ERR, "Fail to query port %u Tx queue %u QP TIS "
1010                                 "transport domain.", dev->data->port_id, idx);
1011                         rte_errno = EINVAL;
1012                         goto error;
1013                 } else {
1014                         DRV_LOG(DEBUG, "Port %u Tx queue %u TIS number %d "
1015                                 "transport domain %d.", dev->data->port_id,
1016                                 idx, qp.tisn, priv->sh->tdn);
1017                 }
1018         }
1019 #endif
1020         if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
1021                 txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
1022                 DRV_LOG(DEBUG, "Port %u: uar_mmap_offset 0x%" PRIx64 ".",
1023                         dev->data->port_id, txq_ctrl->uar_mmap_offset);
1024         } else {
1025                 DRV_LOG(ERR,
1026                         "Port %u failed to retrieve UAR info, invalid libmlx5.so",
1027                         dev->data->port_id);
1028                 rte_errno = EINVAL;
1029                 goto error;
1030         }
1031         txq_uar_init(txq_ctrl, qp.bf.reg);
1032         dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
1033         return 0;
1034 error:
1035         ret = rte_errno; /* Save rte_errno before cleanup. */
1036         if (txq_obj->cq)
1037                 claim_zero(mlx5_glue->destroy_cq(txq_obj->cq));
1038         if (txq_obj->qp)
1039                 claim_zero(mlx5_glue->destroy_qp(txq_obj->qp));
1040         rte_errno = ret; /* Restore rte_errno. */
1041         return -rte_errno;
1042 }
1043
1044 /*
1045  * Create the dummy QP with minimal resources for loopback.
1046  *
1047  * @param dev
1048  *   Pointer to Ethernet device.
1049  *
1050  * @return
1051  *   0 on success, a negative errno value otherwise and rte_errno is set.
1052  */
1053 int
1054 mlx5_rxq_ibv_obj_dummy_lb_create(struct rte_eth_dev *dev)
1055 {
1056 #if defined(HAVE_IBV_DEVICE_TUNNEL_SUPPORT) && defined(HAVE_IBV_FLOW_DV_SUPPORT)
1057         struct mlx5_priv *priv = dev->data->dev_private;
1058         struct mlx5_dev_ctx_shared *sh = priv->sh;
1059         struct ibv_context *ctx = sh->cdev->ctx;
1060         struct mlx5dv_qp_init_attr qp_init_attr = {0};
1061         struct {
1062                 struct ibv_cq_init_attr_ex ibv;
1063                 struct mlx5dv_cq_init_attr mlx5;
1064         } cq_attr = {{0}};
1065
1066         if (dev->data->dev_conf.lpbk_mode) {
1067                 /* Allow packet sent from NIC loop back w/o source MAC check. */
1068                 qp_init_attr.comp_mask |=
1069                                 MLX5DV_QP_INIT_ATTR_MASK_QP_CREATE_FLAGS;
1070                 qp_init_attr.create_flags |=
1071                                 MLX5DV_QP_CREATE_TIR_ALLOW_SELF_LOOPBACK_UC;
1072         } else {
1073                 return 0;
1074         }
1075         /* Only need to check refcnt, 0 after "sh" is allocated. */
1076         if (!!(__atomic_fetch_add(&sh->self_lb.refcnt, 1, __ATOMIC_RELAXED))) {
1077                 MLX5_ASSERT(sh->self_lb.ibv_cq && sh->self_lb.qp);
1078                 priv->lb_used = 1;
1079                 return 0;
1080         }
1081         cq_attr.ibv = (struct ibv_cq_init_attr_ex){
1082                 .cqe = 1,
1083                 .channel = NULL,
1084                 .comp_mask = 0,
1085         };
1086         cq_attr.mlx5 = (struct mlx5dv_cq_init_attr){
1087                 .comp_mask = 0,
1088         };
1089         /* Only CQ is needed, no WQ(RQ) is required in this case. */
1090         sh->self_lb.ibv_cq = mlx5_glue->cq_ex_to_cq(mlx5_glue->dv_create_cq(ctx,
1091                                                         &cq_attr.ibv,
1092                                                         &cq_attr.mlx5));
1093         if (!sh->self_lb.ibv_cq) {
1094                 DRV_LOG(ERR, "Port %u cannot allocate CQ for loopback.",
1095                         dev->data->port_id);
1096                 rte_errno = errno;
1097                 goto error;
1098         }
1099         sh->self_lb.qp = mlx5_glue->dv_create_qp(ctx,
1100                                 &(struct ibv_qp_init_attr_ex){
1101                                         .qp_type = IBV_QPT_RAW_PACKET,
1102                                         .comp_mask = IBV_QP_INIT_ATTR_PD,
1103                                         .pd = sh->cdev->pd,
1104                                         .send_cq = sh->self_lb.ibv_cq,
1105                                         .recv_cq = sh->self_lb.ibv_cq,
1106                                         .cap.max_recv_wr = 1,
1107                                 },
1108                                 &qp_init_attr);
1109         if (!sh->self_lb.qp) {
1110                 DRV_LOG(DEBUG, "Port %u cannot allocate QP for loopback.",
1111                         dev->data->port_id);
1112                 rte_errno = errno;
1113                 goto error;
1114         }
1115         priv->lb_used = 1;
1116         return 0;
1117 error:
1118         if (sh->self_lb.ibv_cq) {
1119                 claim_zero(mlx5_glue->destroy_cq(sh->self_lb.ibv_cq));
1120                 sh->self_lb.ibv_cq = NULL;
1121         }
1122         (void)__atomic_sub_fetch(&sh->self_lb.refcnt, 1, __ATOMIC_RELAXED);
1123         return -rte_errno;
1124 #else
1125         RTE_SET_USED(dev);
1126         return 0;
1127 #endif
1128 }
1129
1130 /*
1131  * Release the dummy queue resources for loopback.
1132  *
1133  * @param dev
1134  *   Pointer to Ethernet device.
1135  */
1136 void
1137 mlx5_rxq_ibv_obj_dummy_lb_release(struct rte_eth_dev *dev)
1138 {
1139 #if defined(HAVE_IBV_DEVICE_TUNNEL_SUPPORT) && defined(HAVE_IBV_FLOW_DV_SUPPORT)
1140         struct mlx5_priv *priv = dev->data->dev_private;
1141         struct mlx5_dev_ctx_shared *sh = priv->sh;
1142
1143         if (!priv->lb_used)
1144                 return;
1145         MLX5_ASSERT(__atomic_load_n(&sh->self_lb.refcnt, __ATOMIC_RELAXED));
1146         if (!(__atomic_sub_fetch(&sh->self_lb.refcnt, 1, __ATOMIC_RELAXED))) {
1147                 if (sh->self_lb.qp) {
1148                         claim_zero(mlx5_glue->destroy_qp(sh->self_lb.qp));
1149                         sh->self_lb.qp = NULL;
1150                 }
1151                 if (sh->self_lb.ibv_cq) {
1152                         claim_zero(mlx5_glue->destroy_cq(sh->self_lb.ibv_cq));
1153                         sh->self_lb.ibv_cq = NULL;
1154                 }
1155         }
1156         priv->lb_used = 0;
1157 #else
1158         RTE_SET_USED(dev);
1159         return;
1160 #endif
1161 }
1162
1163 /**
1164  * Release an Tx verbs queue object.
1165  *
1166  * @param txq_obj
1167  *   Verbs Tx queue object..
1168  */
1169 void
1170 mlx5_txq_ibv_obj_release(struct mlx5_txq_obj *txq_obj)
1171 {
1172         MLX5_ASSERT(txq_obj);
1173         claim_zero(mlx5_glue->destroy_qp(txq_obj->qp));
1174         claim_zero(mlx5_glue->destroy_cq(txq_obj->cq));
1175 }
1176
1177 struct mlx5_obj_ops ibv_obj_ops = {
1178         .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_wq_vlan_strip,
1179         .rxq_obj_new = mlx5_rxq_ibv_obj_new,
1180         .rxq_event_get = mlx5_rx_ibv_get_event,
1181         .rxq_obj_modify = mlx5_ibv_modify_wq,
1182         .rxq_obj_release = mlx5_rxq_ibv_obj_release,
1183         .ind_table_new = mlx5_ibv_ind_table_new,
1184         .ind_table_destroy = mlx5_ibv_ind_table_destroy,
1185         .hrxq_new = mlx5_ibv_hrxq_new,
1186         .hrxq_destroy = mlx5_ibv_qp_destroy,
1187         .drop_action_create = mlx5_ibv_drop_action_create,
1188         .drop_action_destroy = mlx5_ibv_drop_action_destroy,
1189         .txq_obj_new = mlx5_txq_ibv_obj_new,
1190         .txq_obj_modify = mlx5_ibv_modify_qp,
1191         .txq_obj_release = mlx5_txq_ibv_obj_release,
1192         .lb_dummy_queue_create = NULL,
1193         .lb_dummy_queue_release = NULL,
1194 };