net/mlx5: separate Tx queue object modification
[dpdk.git] / drivers / net / mlx5 / mlx5_devx.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 <stdbool.h>
8 #include <string.h>
9 #include <stdint.h>
10 #include <sys/queue.h>
11
12 #include <rte_malloc.h>
13 #include <rte_common.h>
14 #include <rte_eal_paging.h>
15
16 #include <mlx5_glue.h>
17 #include <mlx5_devx_cmds.h>
18 #include <mlx5_malloc.h>
19
20 #include "mlx5.h"
21 #include "mlx5_common_os.h"
22 #include "mlx5_rxtx.h"
23 #include "mlx5_utils.h"
24 #include "mlx5_devx.h"
25 #include "mlx5_flow.h"
26
27
28 /**
29  * Modify RQ vlan stripping offload
30  *
31  * @param rxq_obj
32  *   Rx queue object.
33  *
34  * @return
35  *   0 on success, non-0 otherwise
36  */
37 static int
38 mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_obj *rxq_obj, int on)
39 {
40         struct mlx5_devx_modify_rq_attr rq_attr;
41
42         memset(&rq_attr, 0, sizeof(rq_attr));
43         rq_attr.rq_state = MLX5_RQC_STATE_RDY;
44         rq_attr.state = MLX5_RQC_STATE_RDY;
45         rq_attr.vsd = (on ? 0 : 1);
46         rq_attr.modify_bitmask = MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD;
47         return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);
48 }
49
50 /**
51  * Modify RQ using DevX API.
52  *
53  * @param rxq_obj
54  *   DevX Rx queue object.
55  *
56  * @return
57  *   0 on success, a negative errno value otherwise and rte_errno is set.
58  */
59 static int
60 mlx5_devx_modify_rq(struct mlx5_rxq_obj *rxq_obj, bool is_start)
61 {
62         struct mlx5_devx_modify_rq_attr rq_attr;
63
64         memset(&rq_attr, 0, sizeof(rq_attr));
65         if (is_start) {
66                 rq_attr.rq_state = MLX5_RQC_STATE_RST;
67                 rq_attr.state = MLX5_RQC_STATE_RDY;
68         } else {
69                 rq_attr.rq_state = MLX5_RQC_STATE_RDY;
70                 rq_attr.state = MLX5_RQC_STATE_RST;
71         }
72         return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);
73 }
74
75 /**
76  * Modify SQ using DevX API.
77  *
78  * @param txq_obj
79  *   DevX Tx queue object.
80  * @param type
81  *   Type of change queue state.
82  * @param dev_port
83  *   Unnecessary.
84  *
85  * @return
86  *   0 on success, a negative errno value otherwise and rte_errno is set.
87  */
88 static int
89 mlx5_devx_modify_sq(struct mlx5_txq_obj *obj, enum mlx5_txq_modify_type type,
90                     uint8_t dev_port)
91 {
92         struct mlx5_devx_modify_sq_attr msq_attr = { 0 };
93         int ret;
94
95         if (type != MLX5_TXQ_MOD_RST2RDY) {
96                 /* Change queue state to reset. */
97                 if (type == MLX5_TXQ_MOD_ERR2RDY)
98                         msq_attr.sq_state = MLX5_SQC_STATE_ERR;
99                 else
100                         msq_attr.sq_state = MLX5_SQC_STATE_RDY;
101                 msq_attr.state = MLX5_SQC_STATE_RST;
102                 ret = mlx5_devx_cmd_modify_sq(obj->sq_devx, &msq_attr);
103                 if (ret) {
104                         DRV_LOG(ERR, "Cannot change the Tx SQ state to RESET"
105                                 " %s", strerror(errno));
106                         rte_errno = errno;
107                         return ret;
108                 }
109         }
110         if (type != MLX5_TXQ_MOD_RDY2RST) {
111                 /* Change queue state to ready. */
112                 msq_attr.sq_state = MLX5_SQC_STATE_RST;
113                 msq_attr.state = MLX5_SQC_STATE_RDY;
114                 ret = mlx5_devx_cmd_modify_sq(obj->sq_devx, &msq_attr);
115                 if (ret) {
116                         DRV_LOG(ERR, "Cannot change the Tx SQ state to READY"
117                                 " %s", strerror(errno));
118                         rte_errno = errno;
119                         return ret;
120                 }
121         }
122         /*
123          * The dev_port variable is relevant only in Verbs API, and there is a
124          * pointer that points to this function and a parallel function in verbs
125          * intermittently, so they should have the same parameters.
126          */
127         (void)dev_port;
128         return 0;
129 }
130
131 /**
132  * Release the resources allocated for an RQ DevX object.
133  *
134  * @param rxq_ctrl
135  *   DevX Rx queue object.
136  */
137 static void
138 mlx5_rxq_release_devx_rq_resources(struct mlx5_rxq_ctrl *rxq_ctrl)
139 {
140         struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->rq_dbrec_page;
141
142         if (rxq_ctrl->rxq.wqes) {
143                 mlx5_free((void *)(uintptr_t)rxq_ctrl->rxq.wqes);
144                 rxq_ctrl->rxq.wqes = NULL;
145         }
146         if (rxq_ctrl->wq_umem) {
147                 mlx5_glue->devx_umem_dereg(rxq_ctrl->wq_umem);
148                 rxq_ctrl->wq_umem = NULL;
149         }
150         if (dbr_page) {
151                 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs,
152                                             mlx5_os_get_umem_id(dbr_page->umem),
153                                             rxq_ctrl->rq_dbr_offset));
154                 rxq_ctrl->rq_dbrec_page = NULL;
155         }
156 }
157
158 /**
159  * Release the resources allocated for the Rx CQ DevX object.
160  *
161  * @param rxq_ctrl
162  *   DevX Rx queue object.
163  */
164 static void
165 mlx5_rxq_release_devx_cq_resources(struct mlx5_rxq_ctrl *rxq_ctrl)
166 {
167         struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->cq_dbrec_page;
168
169         if (rxq_ctrl->rxq.cqes) {
170                 rte_free((void *)(uintptr_t)rxq_ctrl->rxq.cqes);
171                 rxq_ctrl->rxq.cqes = NULL;
172         }
173         if (rxq_ctrl->cq_umem) {
174                 mlx5_glue->devx_umem_dereg(rxq_ctrl->cq_umem);
175                 rxq_ctrl->cq_umem = NULL;
176         }
177         if (dbr_page) {
178                 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs,
179                                             mlx5_os_get_umem_id(dbr_page->umem),
180                                             rxq_ctrl->cq_dbr_offset));
181                 rxq_ctrl->cq_dbrec_page = NULL;
182         }
183 }
184
185 /**
186  * Release an Rx DevX queue object.
187  *
188  * @param rxq_obj
189  *   DevX Rx queue object.
190  */
191 static void
192 mlx5_rxq_devx_obj_release(struct mlx5_rxq_obj *rxq_obj)
193 {
194         MLX5_ASSERT(rxq_obj);
195         MLX5_ASSERT(rxq_obj->rq);
196         if (rxq_obj->type == MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN) {
197                 mlx5_devx_modify_rq(rxq_obj, false);
198                 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));
199         } else {
200                 MLX5_ASSERT(rxq_obj->devx_cq);
201                 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));
202                 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->devx_cq));
203                 if (rxq_obj->devx_channel)
204                         mlx5_glue->devx_destroy_event_channel
205                                                         (rxq_obj->devx_channel);
206                 mlx5_rxq_release_devx_rq_resources(rxq_obj->rxq_ctrl);
207                 mlx5_rxq_release_devx_cq_resources(rxq_obj->rxq_ctrl);
208         }
209 }
210
211 /**
212  * Get event for an Rx DevX queue object.
213  *
214  * @param rxq_obj
215  *   DevX Rx queue object.
216  *
217  * @return
218  *   0 on success, a negative errno value otherwise and rte_errno is set.
219  */
220 static int
221 mlx5_rx_devx_get_event(struct mlx5_rxq_obj *rxq_obj)
222 {
223 #ifdef HAVE_IBV_DEVX_EVENT
224         union {
225                 struct mlx5dv_devx_async_event_hdr event_resp;
226                 uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
227         } out;
228         int ret = mlx5_glue->devx_get_event(rxq_obj->devx_channel,
229                                             &out.event_resp,
230                                             sizeof(out.buf));
231
232         if (ret < 0) {
233                 rte_errno = errno;
234                 return -rte_errno;
235         }
236         if (out.event_resp.cookie != (uint64_t)(uintptr_t)rxq_obj->devx_cq) {
237                 rte_errno = EINVAL;
238                 return -rte_errno;
239         }
240         return 0;
241 #else
242         (void)rxq_obj;
243         rte_errno = ENOTSUP;
244         return -rte_errno;
245 #endif /* HAVE_IBV_DEVX_EVENT */
246 }
247
248 /**
249  * Fill common fields of create RQ attributes structure.
250  *
251  * @param rxq_data
252  *   Pointer to Rx queue data.
253  * @param cqn
254  *   CQ number to use with this RQ.
255  * @param rq_attr
256  *   RQ attributes structure to fill..
257  */
258 static void
259 mlx5_devx_create_rq_attr_fill(struct mlx5_rxq_data *rxq_data, uint32_t cqn,
260                               struct mlx5_devx_create_rq_attr *rq_attr)
261 {
262         rq_attr->state = MLX5_RQC_STATE_RST;
263         rq_attr->vsd = (rxq_data->vlan_strip) ? 0 : 1;
264         rq_attr->cqn = cqn;
265         rq_attr->scatter_fcs = (rxq_data->crc_present) ? 1 : 0;
266 }
267
268 /**
269  * Fill common fields of DevX WQ attributes structure.
270  *
271  * @param priv
272  *   Pointer to device private data.
273  * @param rxq_ctrl
274  *   Pointer to Rx queue control structure.
275  * @param wq_attr
276  *   WQ attributes structure to fill..
277  */
278 static void
279 mlx5_devx_wq_attr_fill(struct mlx5_priv *priv, struct mlx5_rxq_ctrl *rxq_ctrl,
280                        struct mlx5_devx_wq_attr *wq_attr)
281 {
282         wq_attr->end_padding_mode = priv->config.cqe_pad ?
283                                         MLX5_WQ_END_PAD_MODE_ALIGN :
284                                         MLX5_WQ_END_PAD_MODE_NONE;
285         wq_attr->pd = priv->sh->pdn;
286         wq_attr->dbr_addr = rxq_ctrl->rq_dbr_offset;
287         wq_attr->dbr_umem_id =
288                         mlx5_os_get_umem_id(rxq_ctrl->rq_dbrec_page->umem);
289         wq_attr->dbr_umem_valid = 1;
290         wq_attr->wq_umem_id = mlx5_os_get_umem_id(rxq_ctrl->wq_umem);
291         wq_attr->wq_umem_valid = 1;
292 }
293
294 /**
295  * Create a RQ object using DevX.
296  *
297  * @param dev
298  *   Pointer to Ethernet device.
299  * @param idx
300  *   Queue index in DPDK Rx queue array.
301  *
302  * @return
303  *   The DevX RQ object initialized, NULL otherwise and rte_errno is set.
304  */
305 static struct mlx5_devx_obj *
306 mlx5_rxq_create_devx_rq_resources(struct rte_eth_dev *dev, uint16_t idx)
307 {
308         struct mlx5_priv *priv = dev->data->dev_private;
309         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
310         struct mlx5_rxq_ctrl *rxq_ctrl =
311                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
312         struct mlx5_devx_create_rq_attr rq_attr = { 0 };
313         uint32_t wqe_n = 1 << (rxq_data->elts_n - rxq_data->sges_n);
314         uint32_t cqn = rxq_ctrl->obj->devx_cq->id;
315         struct mlx5_devx_dbr_page *dbr_page;
316         int64_t dbr_offset;
317         uint32_t wq_size = 0;
318         uint32_t wqe_size = 0;
319         uint32_t log_wqe_size = 0;
320         void *buf = NULL;
321         struct mlx5_devx_obj *rq;
322
323         /* Fill RQ attributes. */
324         rq_attr.mem_rq_type = MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE;
325         rq_attr.flush_in_error_en = 1;
326         mlx5_devx_create_rq_attr_fill(rxq_data, cqn, &rq_attr);
327         /* Fill WQ attributes for this RQ. */
328         if (mlx5_rxq_mprq_enabled(rxq_data)) {
329                 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ;
330                 /*
331                  * Number of strides in each WQE:
332                  * 512*2^single_wqe_log_num_of_strides.
333                  */
334                 rq_attr.wq_attr.single_wqe_log_num_of_strides =
335                                 rxq_data->strd_num_n -
336                                 MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES;
337                 /* Stride size = (2^single_stride_log_num_of_bytes)*64B. */
338                 rq_attr.wq_attr.single_stride_log_num_of_bytes =
339                                 rxq_data->strd_sz_n -
340                                 MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES;
341                 wqe_size = sizeof(struct mlx5_wqe_mprq);
342         } else {
343                 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
344                 wqe_size = sizeof(struct mlx5_wqe_data_seg);
345         }
346         log_wqe_size = log2above(wqe_size) + rxq_data->sges_n;
347         rq_attr.wq_attr.log_wq_stride = log_wqe_size;
348         rq_attr.wq_attr.log_wq_sz = rxq_data->elts_n - rxq_data->sges_n;
349         /* Calculate and allocate WQ memory space. */
350         wqe_size = 1 << log_wqe_size; /* round up power of two.*/
351         wq_size = wqe_n * wqe_size;
352         size_t alignment = MLX5_WQE_BUF_ALIGNMENT;
353         if (alignment == (size_t)-1) {
354                 DRV_LOG(ERR, "Failed to get mem page size");
355                 rte_errno = ENOMEM;
356                 return NULL;
357         }
358         buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, wq_size,
359                           alignment, rxq_ctrl->socket);
360         if (!buf)
361                 return NULL;
362         rxq_data->wqes = buf;
363         rxq_ctrl->wq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx,
364                                                      buf, wq_size, 0);
365         if (!rxq_ctrl->wq_umem)
366                 goto error;
367         /* Allocate RQ door-bell. */
368         dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page);
369         if (dbr_offset < 0) {
370                 DRV_LOG(ERR, "Failed to allocate RQ door-bell.");
371                 goto error;
372         }
373         rxq_ctrl->rq_dbr_offset = dbr_offset;
374         rxq_ctrl->rq_dbrec_page = dbr_page;
375         rxq_data->rq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs +
376                           (uintptr_t)rxq_ctrl->rq_dbr_offset);
377         /* Create RQ using DevX API. */
378         mlx5_devx_wq_attr_fill(priv, rxq_ctrl, &rq_attr.wq_attr);
379         rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &rq_attr, rxq_ctrl->socket);
380         if (!rq)
381                 goto error;
382         return rq;
383 error:
384         mlx5_rxq_release_devx_rq_resources(rxq_ctrl);
385         return NULL;
386 }
387
388 /**
389  * Create a DevX CQ object for an Rx queue.
390  *
391  * @param dev
392  *   Pointer to Ethernet device.
393  * @param idx
394  *   Queue index in DPDK Rx queue array.
395  *
396  * @return
397  *   The DevX CQ object initialized, NULL otherwise and rte_errno is set.
398  */
399 static struct mlx5_devx_obj *
400 mlx5_rxq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx)
401 {
402         struct mlx5_devx_obj *cq_obj = 0;
403         struct mlx5_devx_cq_attr cq_attr = { 0 };
404         struct mlx5_priv *priv = dev->data->dev_private;
405         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
406         struct mlx5_rxq_ctrl *rxq_ctrl =
407                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
408         size_t page_size = rte_mem_page_size();
409         unsigned int cqe_n = mlx5_rxq_cqe_num(rxq_data);
410         struct mlx5_devx_dbr_page *dbr_page;
411         int64_t dbr_offset;
412         void *buf = NULL;
413         uint16_t event_nums[1] = {0};
414         uint32_t log_cqe_n;
415         uint32_t cq_size;
416         int ret = 0;
417
418         if (page_size == (size_t)-1) {
419                 DRV_LOG(ERR, "Failed to get page_size.");
420                 goto error;
421         }
422         if (priv->config.cqe_comp && !rxq_data->hw_timestamp &&
423             !rxq_data->lro) {
424                 cq_attr.cqe_comp_en = 1u;
425                 cq_attr.mini_cqe_res_format =
426                                 mlx5_rxq_mprq_enabled(rxq_data) ?
427                                         MLX5_CQE_RESP_FORMAT_CSUM_STRIDX :
428                                         MLX5_CQE_RESP_FORMAT_HASH;
429                 /*
430                  * For vectorized Rx, it must not be doubled in order to
431                  * make cq_ci and rq_ci aligned.
432                  */
433                 if (mlx5_rxq_check_vec_support(rxq_data) < 0)
434                         cqe_n *= 2;
435         } else if (priv->config.cqe_comp && rxq_data->hw_timestamp) {
436                 DRV_LOG(DEBUG,
437                         "Port %u Rx CQE compression is disabled for HW"
438                         " timestamp.",
439                         dev->data->port_id);
440         } else if (priv->config.cqe_comp && rxq_data->lro) {
441                 DRV_LOG(DEBUG,
442                         "Port %u Rx CQE compression is disabled for LRO.",
443                         dev->data->port_id);
444         }
445         if (priv->config.cqe_pad)
446                 cq_attr.cqe_size = MLX5_CQE_SIZE_128B;
447         log_cqe_n = log2above(cqe_n);
448         cq_size = sizeof(struct mlx5_cqe) * (1 << log_cqe_n);
449         buf = rte_calloc_socket(__func__, 1, cq_size, page_size,
450                                 rxq_ctrl->socket);
451         if (!buf) {
452                 DRV_LOG(ERR, "Failed to allocate memory for CQ.");
453                 goto error;
454         }
455         rxq_data->cqes = (volatile struct mlx5_cqe (*)[])(uintptr_t)buf;
456         rxq_ctrl->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx, buf,
457                                                      cq_size,
458                                                      IBV_ACCESS_LOCAL_WRITE);
459         if (!rxq_ctrl->cq_umem) {
460                 DRV_LOG(ERR, "Failed to register umem for CQ.");
461                 goto error;
462         }
463         /* Allocate CQ door-bell. */
464         dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page);
465         if (dbr_offset < 0) {
466                 DRV_LOG(ERR, "Failed to allocate CQ door-bell.");
467                 goto error;
468         }
469         rxq_ctrl->cq_dbr_offset = dbr_offset;
470         rxq_ctrl->cq_dbrec_page = dbr_page;
471         rxq_data->cq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs +
472                           (uintptr_t)rxq_ctrl->cq_dbr_offset);
473         rxq_data->cq_uar =
474                         mlx5_os_get_devx_uar_base_addr(priv->sh->devx_rx_uar);
475         /* Create CQ using DevX API. */
476         cq_attr.eqn = priv->sh->eqn;
477         cq_attr.uar_page_id =
478                         mlx5_os_get_devx_uar_page_id(priv->sh->devx_rx_uar);
479         cq_attr.q_umem_id = mlx5_os_get_umem_id(rxq_ctrl->cq_umem);
480         cq_attr.q_umem_valid = 1;
481         cq_attr.log_cq_size = log_cqe_n;
482         cq_attr.log_page_size = rte_log2_u32(page_size);
483         cq_attr.db_umem_offset = rxq_ctrl->cq_dbr_offset;
484         cq_attr.db_umem_id = mlx5_os_get_umem_id(dbr_page->umem);
485         cq_attr.db_umem_valid = 1;
486         cq_obj = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr);
487         if (!cq_obj)
488                 goto error;
489         rxq_data->cqe_n = log_cqe_n;
490         rxq_data->cqn = cq_obj->id;
491         if (rxq_ctrl->obj->devx_channel) {
492                 ret = mlx5_glue->devx_subscribe_devx_event
493                                                 (rxq_ctrl->obj->devx_channel,
494                                                  cq_obj->obj,
495                                                  sizeof(event_nums),
496                                                  event_nums,
497                                                  (uint64_t)(uintptr_t)cq_obj);
498                 if (ret) {
499                         DRV_LOG(ERR, "Fail to subscribe CQ to event channel.");
500                         rte_errno = errno;
501                         goto error;
502                 }
503         }
504         /* Initialise CQ to 1's to mark HW ownership for all CQEs. */
505         memset((void *)(uintptr_t)rxq_data->cqes, 0xFF, cq_size);
506         return cq_obj;
507 error:
508         if (cq_obj)
509                 mlx5_devx_cmd_destroy(cq_obj);
510         mlx5_rxq_release_devx_cq_resources(rxq_ctrl);
511         return NULL;
512 }
513
514 /**
515  * Create the Rx hairpin queue object.
516  *
517  * @param dev
518  *   Pointer to Ethernet device.
519  * @param idx
520  *   Queue index in DPDK Rx queue array.
521  *
522  * @return
523  *   0 on success, a negative errno value otherwise and rte_errno is set.
524  */
525 static int
526 mlx5_rxq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx)
527 {
528         struct mlx5_priv *priv = dev->data->dev_private;
529         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
530         struct mlx5_rxq_ctrl *rxq_ctrl =
531                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
532         struct mlx5_devx_create_rq_attr attr = { 0 };
533         struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
534         uint32_t max_wq_data;
535
536         MLX5_ASSERT(rxq_data);
537         MLX5_ASSERT(tmpl);
538         tmpl->type = MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN;
539         tmpl->rxq_ctrl = rxq_ctrl;
540         attr.hairpin = 1;
541         max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz;
542         /* Jumbo frames > 9KB should be supported, and more packets. */
543         if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
544                 if (priv->config.log_hp_size > max_wq_data) {
545                         DRV_LOG(ERR, "Total data size %u power of 2 is "
546                                 "too large for hairpin.",
547                                 priv->config.log_hp_size);
548                         rte_errno = ERANGE;
549                         return -rte_errno;
550                 }
551                 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
552         } else {
553                 attr.wq_attr.log_hairpin_data_sz =
554                                 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
555                                  max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
556         }
557         /* Set the packets number to the maximum value for performance. */
558         attr.wq_attr.log_hairpin_num_packets =
559                         attr.wq_attr.log_hairpin_data_sz -
560                         MLX5_HAIRPIN_QUEUE_STRIDE;
561         tmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &attr,
562                                            rxq_ctrl->socket);
563         if (!tmpl->rq) {
564                 DRV_LOG(ERR,
565                         "Port %u Rx hairpin queue %u can't create rq object.",
566                         dev->data->port_id, idx);
567                 rte_errno = errno;
568                 return -rte_errno;
569         }
570         dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_HAIRPIN;
571         return 0;
572 }
573
574 /**
575  * Create the Rx queue DevX object.
576  *
577  * @param dev
578  *   Pointer to Ethernet device.
579  * @param idx
580  *   Queue index in DPDK Rx queue array.
581  *
582  * @return
583  *   0 on success, a negative errno value otherwise and rte_errno is set.
584  */
585 static int
586 mlx5_rxq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx)
587 {
588         struct mlx5_priv *priv = dev->data->dev_private;
589         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
590         struct mlx5_rxq_ctrl *rxq_ctrl =
591                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
592         struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
593         int ret = 0;
594
595         MLX5_ASSERT(rxq_data);
596         MLX5_ASSERT(tmpl);
597         if (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN)
598                 return mlx5_rxq_obj_hairpin_new(dev, idx);
599         tmpl->type = MLX5_RXQ_OBJ_TYPE_DEVX_RQ;
600         tmpl->rxq_ctrl = rxq_ctrl;
601         if (rxq_ctrl->irq) {
602                 int devx_ev_flag =
603                           MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA;
604
605                 tmpl->devx_channel = mlx5_glue->devx_create_event_channel
606                                                                 (priv->sh->ctx,
607                                                                  devx_ev_flag);
608                 if (!tmpl->devx_channel) {
609                         rte_errno = errno;
610                         DRV_LOG(ERR, "Failed to create event channel %d.",
611                                 rte_errno);
612                         goto error;
613                 }
614                 tmpl->fd = mlx5_os_get_devx_channel_fd(tmpl->devx_channel);
615         }
616         /* Create CQ using DevX API. */
617         tmpl->devx_cq = mlx5_rxq_create_devx_cq_resources(dev, idx);
618         if (!tmpl->devx_cq) {
619                 DRV_LOG(ERR, "Failed to create CQ.");
620                 goto error;
621         }
622         /* Create RQ using DevX API. */
623         tmpl->rq = mlx5_rxq_create_devx_rq_resources(dev, idx);
624         if (!tmpl->rq) {
625                 DRV_LOG(ERR, "Port %u Rx queue %u RQ creation failure.",
626                         dev->data->port_id, idx);
627                 rte_errno = ENOMEM;
628                 goto error;
629         }
630         /* Change queue state to ready. */
631         ret = mlx5_devx_modify_rq(tmpl, true);
632         if (ret)
633                 goto error;
634         rxq_data->cq_arm_sn = 0;
635         mlx5_rxq_initialize(rxq_data);
636         rxq_data->cq_ci = 0;
637         dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
638         rxq_ctrl->wqn = tmpl->rq->id;
639         return 0;
640 error:
641         ret = rte_errno; /* Save rte_errno before cleanup. */
642         if (tmpl->rq)
643                 claim_zero(mlx5_devx_cmd_destroy(tmpl->rq));
644         if (tmpl->devx_cq)
645                 claim_zero(mlx5_devx_cmd_destroy(tmpl->devx_cq));
646         if (tmpl->devx_channel)
647                 mlx5_glue->devx_destroy_event_channel(tmpl->devx_channel);
648         mlx5_rxq_release_devx_rq_resources(rxq_ctrl);
649         mlx5_rxq_release_devx_cq_resources(rxq_ctrl);
650         rte_errno = ret; /* Restore rte_errno. */
651         return -rte_errno;
652 }
653
654 /**
655  * Create RQT using DevX API as a filed of indirection table.
656  *
657  * @param dev
658  *   Pointer to Ethernet device.
659  * @param log_n
660  *   Log of number of queues in the array.
661  * @param ind_tbl
662  *   DevX indirection table object.
663  *
664  * @return
665  *   0 on success, a negative errno value otherwise and rte_errno is set.
666  */
667 static int
668 mlx5_devx_ind_table_new(struct rte_eth_dev *dev, const unsigned int log_n,
669                         struct mlx5_ind_table_obj *ind_tbl)
670 {
671         struct mlx5_priv *priv = dev->data->dev_private;
672         struct mlx5_devx_rqt_attr *rqt_attr = NULL;
673         const unsigned int rqt_n = 1 << log_n;
674         unsigned int i, j;
675
676         MLX5_ASSERT(ind_tbl);
677         rqt_attr = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rqt_attr) +
678                               rqt_n * sizeof(uint32_t), 0, SOCKET_ID_ANY);
679         if (!rqt_attr) {
680                 DRV_LOG(ERR, "Port %u cannot allocate RQT resources.",
681                         dev->data->port_id);
682                 rte_errno = ENOMEM;
683                 return -rte_errno;
684         }
685         rqt_attr->rqt_max_size = priv->config.ind_table_max_size;
686         rqt_attr->rqt_actual_size = rqt_n;
687         for (i = 0; i != ind_tbl->queues_n; ++i) {
688                 struct mlx5_rxq_data *rxq = (*priv->rxqs)[ind_tbl->queues[i]];
689                 struct mlx5_rxq_ctrl *rxq_ctrl =
690                                 container_of(rxq, struct mlx5_rxq_ctrl, rxq);
691
692                 rqt_attr->rq_list[i] = rxq_ctrl->obj->rq->id;
693         }
694         MLX5_ASSERT(i > 0);
695         for (j = 0; i != rqt_n; ++j, ++i)
696                 rqt_attr->rq_list[i] = rqt_attr->rq_list[j];
697         ind_tbl->rqt = mlx5_devx_cmd_create_rqt(priv->sh->ctx, rqt_attr);
698         mlx5_free(rqt_attr);
699         if (!ind_tbl->rqt) {
700                 DRV_LOG(ERR, "Port %u cannot create DevX RQT.",
701                         dev->data->port_id);
702                 rte_errno = errno;
703                 return -rte_errno;
704         }
705         return 0;
706 }
707
708 /**
709  * Destroy the DevX RQT object.
710  *
711  * @param ind_table
712  *   Indirection table to release.
713  */
714 static void
715 mlx5_devx_ind_table_destroy(struct mlx5_ind_table_obj *ind_tbl)
716 {
717         claim_zero(mlx5_devx_cmd_destroy(ind_tbl->rqt));
718 }
719
720 /**
721  * Create an Rx Hash queue.
722  *
723  * @param dev
724  *   Pointer to Ethernet device.
725  * @param hrxq
726  *   Pointer to Rx Hash queue.
727  * @param tunnel
728  *   Tunnel type.
729  *
730  * @return
731  *   0 on success, a negative errno value otherwise and rte_errno is set.
732  */
733 static int
734 mlx5_devx_hrxq_new(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq,
735                    int tunnel __rte_unused)
736 {
737         struct mlx5_priv *priv = dev->data->dev_private;
738         struct mlx5_ind_table_obj *ind_tbl = hrxq->ind_table;
739         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[ind_tbl->queues[0]];
740         struct mlx5_rxq_ctrl *rxq_ctrl =
741                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
742         struct mlx5_devx_tir_attr tir_attr;
743         const uint8_t *rss_key = hrxq->rss_key;
744         uint64_t hash_fields = hrxq->hash_fields;
745         bool lro = true;
746         uint32_t i;
747         int err;
748
749         /* Enable TIR LRO only if all the queues were configured for. */
750         for (i = 0; i < ind_tbl->queues_n; ++i) {
751                 if (!(*priv->rxqs)[ind_tbl->queues[i]]->lro) {
752                         lro = false;
753                         break;
754                 }
755         }
756         memset(&tir_attr, 0, sizeof(tir_attr));
757         tir_attr.disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT;
758         tir_attr.rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ;
759         tir_attr.tunneled_offload_en = !!tunnel;
760         /* If needed, translate hash_fields bitmap to PRM format. */
761         if (hash_fields) {
762                 struct mlx5_rx_hash_field_select *rx_hash_field_select = NULL;
763 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
764                 rx_hash_field_select = hash_fields & IBV_RX_HASH_INNER ?
765                                        &tir_attr.rx_hash_field_selector_inner :
766                                        &tir_attr.rx_hash_field_selector_outer;
767 #else
768                 rx_hash_field_select = &tir_attr.rx_hash_field_selector_outer;
769 #endif
770                 /* 1 bit: 0: IPv4, 1: IPv6. */
771                 rx_hash_field_select->l3_prot_type =
772                                         !!(hash_fields & MLX5_IPV6_IBV_RX_HASH);
773                 /* 1 bit: 0: TCP, 1: UDP. */
774                 rx_hash_field_select->l4_prot_type =
775                                          !!(hash_fields & MLX5_UDP_IBV_RX_HASH);
776                 /* Bitmask which sets which fields to use in RX Hash. */
777                 rx_hash_field_select->selected_fields =
778                         ((!!(hash_fields & MLX5_L3_SRC_IBV_RX_HASH)) <<
779                          MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
780                         (!!(hash_fields & MLX5_L3_DST_IBV_RX_HASH)) <<
781                          MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP |
782                         (!!(hash_fields & MLX5_L4_SRC_IBV_RX_HASH)) <<
783                          MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT |
784                         (!!(hash_fields & MLX5_L4_DST_IBV_RX_HASH)) <<
785                          MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT;
786         }
787         if (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN)
788                 tir_attr.transport_domain = priv->sh->td->id;
789         else
790                 tir_attr.transport_domain = priv->sh->tdn;
791         memcpy(tir_attr.rx_hash_toeplitz_key, rss_key, MLX5_RSS_HASH_KEY_LEN);
792         tir_attr.indirect_table = ind_tbl->rqt->id;
793         if (dev->data->dev_conf.lpbk_mode)
794                 tir_attr.self_lb_block = MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
795         if (lro) {
796                 tir_attr.lro_timeout_period_usecs = priv->config.lro.timeout;
797                 tir_attr.lro_max_msg_sz = priv->max_lro_msg_size;
798                 tir_attr.lro_enable_mask = MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO |
799                                            MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO;
800         }
801         hrxq->tir = mlx5_devx_cmd_create_tir(priv->sh->ctx, &tir_attr);
802         if (!hrxq->tir) {
803                 DRV_LOG(ERR, "Port %u cannot create DevX TIR.",
804                         dev->data->port_id);
805                 rte_errno = errno;
806                 goto error;
807         }
808 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
809         hrxq->action = mlx5_glue->dv_create_flow_action_dest_devx_tir
810                                                                (hrxq->tir->obj);
811         if (!hrxq->action) {
812                 rte_errno = errno;
813                 goto error;
814         }
815 #endif
816         return 0;
817 error:
818         err = rte_errno; /* Save rte_errno before cleanup. */
819         if (hrxq->tir)
820                 claim_zero(mlx5_devx_cmd_destroy(hrxq->tir));
821         rte_errno = err; /* Restore rte_errno. */
822         return -rte_errno;
823 }
824
825 /**
826  * Destroy a DevX TIR object.
827  *
828  * @param hrxq
829  *   Hash Rx queue to release its tir.
830  */
831 static void
832 mlx5_devx_tir_destroy(struct mlx5_hrxq *hrxq)
833 {
834         claim_zero(mlx5_devx_cmd_destroy(hrxq->tir));
835 }
836
837 /**
838  * Create a DevX drop action for Rx Hash queue.
839  *
840  * @param dev
841  *   Pointer to Ethernet device.
842  *
843  * @return
844  *   0 on success, a negative errno value otherwise and rte_errno is set.
845  */
846 static int
847 mlx5_devx_drop_action_create(struct rte_eth_dev *dev)
848 {
849         (void)dev;
850         DRV_LOG(ERR, "DevX drop action is not supported yet.");
851         rte_errno = ENOTSUP;
852         return -rte_errno;
853 }
854
855 /**
856  * Release a drop hash Rx queue.
857  *
858  * @param dev
859  *   Pointer to Ethernet device.
860  */
861 static void
862 mlx5_devx_drop_action_destroy(struct rte_eth_dev *dev)
863 {
864         (void)dev;
865         DRV_LOG(ERR, "DevX drop action is not supported yet.");
866         rte_errno = ENOTSUP;
867 }
868
869 /**
870  * Create the Tx hairpin queue object.
871  *
872  * @param dev
873  *   Pointer to Ethernet device.
874  * @param idx
875  *   Queue index in DPDK Tx queue array.
876  *
877  * @return
878  *   0 on success, a negative errno value otherwise and rte_errno is set.
879  */
880 static int
881 mlx5_txq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx)
882 {
883         struct mlx5_priv *priv = dev->data->dev_private;
884         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
885         struct mlx5_txq_ctrl *txq_ctrl =
886                 container_of(txq_data, struct mlx5_txq_ctrl, txq);
887         struct mlx5_devx_create_sq_attr attr = { 0 };
888         struct mlx5_txq_obj *tmpl = txq_ctrl->obj;
889         uint32_t max_wq_data;
890
891         MLX5_ASSERT(txq_data);
892         MLX5_ASSERT(tmpl);
893         tmpl->type = MLX5_TXQ_OBJ_TYPE_DEVX_HAIRPIN;
894         tmpl->txq_ctrl = txq_ctrl;
895         attr.hairpin = 1;
896         attr.tis_lst_sz = 1;
897         max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz;
898         /* Jumbo frames > 9KB should be supported, and more packets. */
899         if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
900                 if (priv->config.log_hp_size > max_wq_data) {
901                         DRV_LOG(ERR, "Total data size %u power of 2 is "
902                                 "too large for hairpin.",
903                                 priv->config.log_hp_size);
904                         rte_errno = ERANGE;
905                         return -rte_errno;
906                 }
907                 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
908         } else {
909                 attr.wq_attr.log_hairpin_data_sz =
910                                 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
911                                  max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
912         }
913         /* Set the packets number to the maximum value for performance. */
914         attr.wq_attr.log_hairpin_num_packets =
915                         attr.wq_attr.log_hairpin_data_sz -
916                         MLX5_HAIRPIN_QUEUE_STRIDE;
917         attr.tis_num = priv->sh->tis->id;
918         tmpl->sq = mlx5_devx_cmd_create_sq(priv->sh->ctx, &attr);
919         if (!tmpl->sq) {
920                 DRV_LOG(ERR,
921                         "Port %u tx hairpin queue %u can't create SQ object.",
922                         dev->data->port_id, idx);
923                 rte_errno = errno;
924                 return -rte_errno;
925         }
926         return 0;
927 }
928
929 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET
930 /**
931  * Release DevX SQ resources.
932  *
933  * @param txq_obj
934  *   DevX Tx queue object.
935  */
936 static void
937 mlx5_txq_release_devx_sq_resources(struct mlx5_txq_obj *txq_obj)
938 {
939         if (txq_obj->sq_devx)
940                 claim_zero(mlx5_devx_cmd_destroy(txq_obj->sq_devx));
941         if (txq_obj->sq_umem)
942                 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->sq_umem));
943         if (txq_obj->sq_buf)
944                 mlx5_free(txq_obj->sq_buf);
945         if (txq_obj->sq_dbrec_page)
946                 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs,
947                                             mlx5_os_get_umem_id
948                                                  (txq_obj->sq_dbrec_page->umem),
949                                             txq_obj->sq_dbrec_offset));
950 }
951
952 /**
953  * Release DevX Tx CQ resources.
954  *
955  * @param txq_obj
956  *   DevX Tx queue object.
957  */
958 static void
959 mlx5_txq_release_devx_cq_resources(struct mlx5_txq_obj *txq_obj)
960 {
961         if (txq_obj->cq_devx)
962                 claim_zero(mlx5_devx_cmd_destroy(txq_obj->cq_devx));
963         if (txq_obj->cq_umem)
964                 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->cq_umem));
965         if (txq_obj->cq_buf)
966                 mlx5_free(txq_obj->cq_buf);
967         if (txq_obj->cq_dbrec_page)
968                 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs,
969                                             mlx5_os_get_umem_id
970                                                  (txq_obj->cq_dbrec_page->umem),
971                                             txq_obj->cq_dbrec_offset));
972 }
973
974 /**
975  * Destroy the Tx queue DevX object.
976  *
977  * @param txq_obj
978  *   Txq object to destroy.
979  */
980 static void
981 mlx5_txq_release_devx_resources(struct mlx5_txq_obj *txq_obj)
982 {
983         MLX5_ASSERT(txq_obj->type == MLX5_TXQ_OBJ_TYPE_DEVX_SQ);
984
985         mlx5_txq_release_devx_cq_resources(txq_obj);
986         mlx5_txq_release_devx_sq_resources(txq_obj);
987 }
988
989 /**
990  * Create a DevX CQ object and its resources for an Tx queue.
991  *
992  * @param dev
993  *   Pointer to Ethernet device.
994  * @param idx
995  *   Queue index in DPDK Tx queue array.
996  *
997  * @return
998  *   Number of CQEs in CQ, 0 otherwise and rte_errno is set.
999  */
1000 static uint32_t
1001 mlx5_txq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx)
1002 {
1003         struct mlx5_priv *priv = dev->data->dev_private;
1004         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1005         struct mlx5_txq_ctrl *txq_ctrl =
1006                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1007         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1008         struct mlx5_devx_cq_attr cq_attr = { 0 };
1009         struct mlx5_cqe *cqe;
1010         size_t page_size;
1011         size_t alignment;
1012         uint32_t cqe_n;
1013         uint32_t i;
1014         int ret;
1015
1016         MLX5_ASSERT(txq_data);
1017         MLX5_ASSERT(txq_obj);
1018         page_size = rte_mem_page_size();
1019         if (page_size == (size_t)-1) {
1020                 DRV_LOG(ERR, "Failed to get mem page size.");
1021                 rte_errno = ENOMEM;
1022                 return 0;
1023         }
1024         /* Allocate memory buffer for CQEs. */
1025         alignment = MLX5_CQE_BUF_ALIGNMENT;
1026         if (alignment == (size_t)-1) {
1027                 DRV_LOG(ERR, "Failed to get CQE buf alignment.");
1028                 rte_errno = ENOMEM;
1029                 return 0;
1030         }
1031         /* Create the Completion Queue. */
1032         cqe_n = (1UL << txq_data->elts_n) / MLX5_TX_COMP_THRESH +
1033                 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
1034         cqe_n = 1UL << log2above(cqe_n);
1035         if (cqe_n > UINT16_MAX) {
1036                 DRV_LOG(ERR,
1037                         "Port %u Tx queue %u requests to many CQEs %u.",
1038                         dev->data->port_id, txq_data->idx, cqe_n);
1039                 rte_errno = EINVAL;
1040                 return 0;
1041         }
1042         txq_obj->cq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
1043                                       cqe_n * sizeof(struct mlx5_cqe),
1044                                       alignment,
1045                                       priv->sh->numa_node);
1046         if (!txq_obj->cq_buf) {
1047                 DRV_LOG(ERR,
1048                         "Port %u Tx queue %u cannot allocate memory (CQ).",
1049                         dev->data->port_id, txq_data->idx);
1050                 rte_errno = ENOMEM;
1051                 return 0;
1052         }
1053         /* Register allocated buffer in user space with DevX. */
1054         txq_obj->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx,
1055                                                 (void *)txq_obj->cq_buf,
1056                                                 cqe_n * sizeof(struct mlx5_cqe),
1057                                                 IBV_ACCESS_LOCAL_WRITE);
1058         if (!txq_obj->cq_umem) {
1059                 rte_errno = errno;
1060                 DRV_LOG(ERR,
1061                         "Port %u Tx queue %u cannot register memory (CQ).",
1062                         dev->data->port_id, txq_data->idx);
1063                 goto error;
1064         }
1065         /* Allocate doorbell record for completion queue. */
1066         txq_obj->cq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx,
1067                                                 &priv->dbrpgs,
1068                                                 &txq_obj->cq_dbrec_page);
1069         if (txq_obj->cq_dbrec_offset < 0) {
1070                 rte_errno = errno;
1071                 DRV_LOG(ERR, "Failed to allocate CQ door-bell.");
1072                 goto error;
1073         }
1074         cq_attr.cqe_size = (sizeof(struct mlx5_cqe) == 128) ?
1075                             MLX5_CQE_SIZE_128B : MLX5_CQE_SIZE_64B;
1076         cq_attr.uar_page_id = mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar);
1077         cq_attr.eqn = priv->sh->eqn;
1078         cq_attr.q_umem_valid = 1;
1079         cq_attr.q_umem_offset = (uintptr_t)txq_obj->cq_buf % page_size;
1080         cq_attr.q_umem_id = mlx5_os_get_umem_id(txq_obj->cq_umem);
1081         cq_attr.db_umem_valid = 1;
1082         cq_attr.db_umem_offset = txq_obj->cq_dbrec_offset;
1083         cq_attr.db_umem_id = mlx5_os_get_umem_id(txq_obj->cq_dbrec_page->umem);
1084         cq_attr.log_cq_size = rte_log2_u32(cqe_n);
1085         cq_attr.log_page_size = rte_log2_u32(page_size);
1086         /* Create completion queue object with DevX. */
1087         txq_obj->cq_devx = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr);
1088         if (!txq_obj->cq_devx) {
1089                 rte_errno = errno;
1090                 DRV_LOG(ERR, "Port %u Tx queue %u CQ creation failure.",
1091                         dev->data->port_id, idx);
1092                 goto error;
1093         }
1094         /* Initial fill CQ buffer with invalid CQE opcode. */
1095         cqe = (struct mlx5_cqe *)txq_obj->cq_buf;
1096         for (i = 0; i < cqe_n; i++) {
1097                 cqe->op_own = (MLX5_CQE_INVALID << 4) | MLX5_CQE_OWNER_MASK;
1098                 ++cqe;
1099         }
1100         return cqe_n;
1101 error:
1102         ret = rte_errno;
1103         mlx5_txq_release_devx_cq_resources(txq_obj);
1104         rte_errno = ret;
1105         return 0;
1106 }
1107
1108 /**
1109  * Create a SQ object and its resources using DevX.
1110  *
1111  * @param dev
1112  *   Pointer to Ethernet device.
1113  * @param idx
1114  *   Queue index in DPDK Tx queue array.
1115  *
1116  * @return
1117  *   Number of WQEs in SQ, 0 otherwise and rte_errno is set.
1118  */
1119 static uint32_t
1120 mlx5_txq_create_devx_sq_resources(struct rte_eth_dev *dev, uint16_t idx)
1121 {
1122         struct mlx5_priv *priv = dev->data->dev_private;
1123         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1124         struct mlx5_txq_ctrl *txq_ctrl =
1125                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1126         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1127         struct mlx5_devx_create_sq_attr sq_attr = { 0 };
1128         size_t page_size;
1129         uint32_t wqe_n;
1130         int ret;
1131
1132         MLX5_ASSERT(txq_data);
1133         MLX5_ASSERT(txq_obj);
1134         page_size = rte_mem_page_size();
1135         if (page_size == (size_t)-1) {
1136                 DRV_LOG(ERR, "Failed to get mem page size.");
1137                 rte_errno = ENOMEM;
1138                 return 0;
1139         }
1140         wqe_n = RTE_MIN(1UL << txq_data->elts_n,
1141                         (uint32_t)priv->sh->device_attr.max_qp_wr);
1142         txq_obj->sq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
1143                                       wqe_n * sizeof(struct mlx5_wqe),
1144                                       page_size, priv->sh->numa_node);
1145         if (!txq_obj->sq_buf) {
1146                 DRV_LOG(ERR,
1147                         "Port %u Tx queue %u cannot allocate memory (SQ).",
1148                         dev->data->port_id, txq_data->idx);
1149                 rte_errno = ENOMEM;
1150                 goto error;
1151         }
1152         /* Register allocated buffer in user space with DevX. */
1153         txq_obj->sq_umem = mlx5_glue->devx_umem_reg
1154                                         (priv->sh->ctx,
1155                                          (void *)txq_obj->sq_buf,
1156                                          wqe_n * sizeof(struct mlx5_wqe),
1157                                          IBV_ACCESS_LOCAL_WRITE);
1158         if (!txq_obj->sq_umem) {
1159                 rte_errno = errno;
1160                 DRV_LOG(ERR,
1161                         "Port %u Tx queue %u cannot register memory (SQ).",
1162                         dev->data->port_id, txq_data->idx);
1163                 goto error;
1164         }
1165         /* Allocate doorbell record for send queue. */
1166         txq_obj->sq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx,
1167                                                 &priv->dbrpgs,
1168                                                 &txq_obj->sq_dbrec_page);
1169         if (txq_obj->sq_dbrec_offset < 0) {
1170                 rte_errno = errno;
1171                 DRV_LOG(ERR, "Failed to allocate SQ door-bell.");
1172                 goto error;
1173         }
1174         sq_attr.tis_lst_sz = 1;
1175         sq_attr.tis_num = priv->sh->tis->id;
1176         sq_attr.state = MLX5_SQC_STATE_RST;
1177         sq_attr.cqn = txq_obj->cq_devx->id;
1178         sq_attr.flush_in_error_en = 1;
1179         sq_attr.allow_multi_pkt_send_wqe = !!priv->config.mps;
1180         sq_attr.allow_swp = !!priv->config.swp;
1181         sq_attr.min_wqe_inline_mode = priv->config.hca_attr.vport_inline_mode;
1182         sq_attr.wq_attr.uar_page =
1183                                 mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar);
1184         sq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
1185         sq_attr.wq_attr.pd = priv->sh->pdn;
1186         sq_attr.wq_attr.log_wq_stride = rte_log2_u32(MLX5_WQE_SIZE);
1187         sq_attr.wq_attr.log_wq_sz = log2above(wqe_n);
1188         sq_attr.wq_attr.dbr_umem_valid = 1;
1189         sq_attr.wq_attr.dbr_addr = txq_obj->sq_dbrec_offset;
1190         sq_attr.wq_attr.dbr_umem_id =
1191                         mlx5_os_get_umem_id(txq_obj->sq_dbrec_page->umem);
1192         sq_attr.wq_attr.wq_umem_valid = 1;
1193         sq_attr.wq_attr.wq_umem_id = mlx5_os_get_umem_id(txq_obj->sq_umem);
1194         sq_attr.wq_attr.wq_umem_offset = (uintptr_t)txq_obj->sq_buf % page_size;
1195         /* Create Send Queue object with DevX. */
1196         txq_obj->sq_devx = mlx5_devx_cmd_create_sq(priv->sh->ctx, &sq_attr);
1197         if (!txq_obj->sq_devx) {
1198                 rte_errno = errno;
1199                 DRV_LOG(ERR, "Port %u Tx queue %u SQ creation failure.",
1200                         dev->data->port_id, idx);
1201                 goto error;
1202         }
1203         return wqe_n;
1204 error:
1205         ret = rte_errno;
1206         mlx5_txq_release_devx_sq_resources(txq_obj);
1207         rte_errno = ret;
1208         return 0;
1209 }
1210 #endif
1211
1212 /**
1213  * Create the Tx queue DevX object.
1214  *
1215  * @param dev
1216  *   Pointer to Ethernet device.
1217  * @param idx
1218  *   Queue index in DPDK Tx queue array.
1219  *
1220  * @return
1221  *   0 on success, a negative errno value otherwise and rte_errno is set.
1222  */
1223 int
1224 mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx)
1225 {
1226         struct mlx5_priv *priv = dev->data->dev_private;
1227         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1228         struct mlx5_txq_ctrl *txq_ctrl =
1229                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1230
1231         if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN)
1232                 return mlx5_txq_obj_hairpin_new(dev, idx);
1233 #ifndef HAVE_MLX5DV_DEVX_UAR_OFFSET
1234         DRV_LOG(ERR, "Port %u Tx queue %u cannot create with DevX, no UAR.",
1235                      dev->data->port_id, idx);
1236         rte_errno = ENOMEM;
1237         return -rte_errno;
1238 #else
1239         struct mlx5_dev_ctx_shared *sh = priv->sh;
1240         struct mlx5_devx_modify_sq_attr msq_attr = { 0 };
1241         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1242         void *reg_addr;
1243         uint32_t cqe_n;
1244         uint32_t wqe_n;
1245         int ret = 0;
1246
1247         MLX5_ASSERT(txq_data);
1248         MLX5_ASSERT(txq_obj);
1249         txq_obj->type = MLX5_TXQ_OBJ_TYPE_DEVX_SQ;
1250         txq_obj->txq_ctrl = txq_ctrl;
1251         txq_obj->dev = dev;
1252         cqe_n = mlx5_txq_create_devx_cq_resources(dev, idx);
1253         if (!cqe_n) {
1254                 rte_errno = errno;
1255                 goto error;
1256         }
1257         txq_data->cqe_n = log2above(cqe_n);
1258         txq_data->cqe_s = 1 << txq_data->cqe_n;
1259         txq_data->cqe_m = txq_data->cqe_s - 1;
1260         txq_data->cqes = (volatile struct mlx5_cqe *)txq_obj->cq_buf;
1261         txq_data->cq_ci = 0;
1262         txq_data->cq_pi = 0;
1263         txq_data->cq_db = (volatile uint32_t *)(txq_obj->cq_dbrec_page->dbrs +
1264                                                 txq_obj->cq_dbrec_offset);
1265         *txq_data->cq_db = 0;
1266         /* Create Send Queue object with DevX. */
1267         wqe_n = mlx5_txq_create_devx_sq_resources(dev, idx);
1268         if (!wqe_n) {
1269                 rte_errno = errno;
1270                 goto error;
1271         }
1272         /* Create the Work Queue. */
1273         txq_data->wqe_n = log2above(wqe_n);
1274         txq_data->wqe_s = 1 << txq_data->wqe_n;
1275         txq_data->wqe_m = txq_data->wqe_s - 1;
1276         txq_data->wqes = (struct mlx5_wqe *)txq_obj->sq_buf;
1277         txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s;
1278         txq_data->wqe_ci = 0;
1279         txq_data->wqe_pi = 0;
1280         txq_data->wqe_comp = 0;
1281         txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV;
1282         txq_data->qp_db = (volatile uint32_t *)
1283                                         (txq_obj->sq_dbrec_page->dbrs +
1284                                          txq_obj->sq_dbrec_offset +
1285                                          MLX5_SND_DBR * sizeof(uint32_t));
1286         *txq_data->qp_db = 0;
1287         txq_data->qp_num_8s = txq_obj->sq_devx->id << 8;
1288         /* Change Send Queue state to Ready-to-Send. */
1289         msq_attr.sq_state = MLX5_SQC_STATE_RST;
1290         msq_attr.state = MLX5_SQC_STATE_RDY;
1291         ret = mlx5_devx_cmd_modify_sq(txq_obj->sq_devx, &msq_attr);
1292         if (ret) {
1293                 rte_errno = errno;
1294                 DRV_LOG(ERR,
1295                         "Port %u Tx queue %u SP state to SQC_STATE_RDY failed.",
1296                         dev->data->port_id, idx);
1297                 goto error;
1298         }
1299 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
1300         /*
1301          * If using DevX need to query and store TIS transport domain value.
1302          * This is done once per port.
1303          * Will use this value on Rx, when creating matching TIR.
1304          */
1305         if (!priv->sh->tdn)
1306                 priv->sh->tdn = priv->sh->td->id;
1307 #endif
1308         MLX5_ASSERT(sh->tx_uar);
1309         reg_addr = mlx5_os_get_devx_uar_reg_addr(sh->tx_uar);
1310         MLX5_ASSERT(reg_addr);
1311         txq_ctrl->bf_reg = reg_addr;
1312         txq_ctrl->uar_mmap_offset =
1313                                 mlx5_os_get_devx_uar_mmap_offset(sh->tx_uar);
1314         txq_uar_init(txq_ctrl);
1315         return 0;
1316 error:
1317         ret = rte_errno; /* Save rte_errno before cleanup. */
1318         mlx5_txq_release_devx_resources(txq_obj);
1319         rte_errno = ret; /* Restore rte_errno. */
1320         return -rte_errno;
1321 #endif
1322 }
1323
1324 /**
1325  * Release an Tx DevX queue object.
1326  *
1327  * @param txq_obj
1328  *   DevX Tx queue object.
1329  */
1330 void
1331 mlx5_txq_devx_obj_release(struct mlx5_txq_obj *txq_obj)
1332 {
1333         MLX5_ASSERT(txq_obj);
1334         if (txq_obj->type == MLX5_TXQ_OBJ_TYPE_DEVX_HAIRPIN) {
1335                 if (txq_obj->tis)
1336                         claim_zero(mlx5_devx_cmd_destroy(txq_obj->tis));
1337 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET
1338         } else {
1339                 mlx5_txq_release_devx_resources(txq_obj);
1340 #endif
1341         }
1342 }
1343
1344 struct mlx5_obj_ops devx_obj_ops = {
1345         .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_rq_vlan_strip,
1346         .rxq_obj_new = mlx5_rxq_devx_obj_new,
1347         .rxq_event_get = mlx5_rx_devx_get_event,
1348         .rxq_obj_modify = mlx5_devx_modify_rq,
1349         .rxq_obj_release = mlx5_rxq_devx_obj_release,
1350         .ind_table_new = mlx5_devx_ind_table_new,
1351         .ind_table_destroy = mlx5_devx_ind_table_destroy,
1352         .hrxq_new = mlx5_devx_hrxq_new,
1353         .hrxq_destroy = mlx5_devx_tir_destroy,
1354         .drop_action_create = mlx5_devx_drop_action_create,
1355         .drop_action_destroy = mlx5_devx_drop_action_destroy,
1356         .txq_obj_new = mlx5_txq_devx_obj_new,
1357         .txq_obj_modify = mlx5_devx_modify_sq,
1358         .txq_obj_release = mlx5_txq_devx_obj_release,
1359 };