net/mlx5: remove Tx queue object type field
[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->txq_ctrl = txq_ctrl;
894         attr.hairpin = 1;
895         attr.tis_lst_sz = 1;
896         max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz;
897         /* Jumbo frames > 9KB should be supported, and more packets. */
898         if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
899                 if (priv->config.log_hp_size > max_wq_data) {
900                         DRV_LOG(ERR, "Total data size %u power of 2 is "
901                                 "too large for hairpin.",
902                                 priv->config.log_hp_size);
903                         rte_errno = ERANGE;
904                         return -rte_errno;
905                 }
906                 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
907         } else {
908                 attr.wq_attr.log_hairpin_data_sz =
909                                 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
910                                  max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
911         }
912         /* Set the packets number to the maximum value for performance. */
913         attr.wq_attr.log_hairpin_num_packets =
914                         attr.wq_attr.log_hairpin_data_sz -
915                         MLX5_HAIRPIN_QUEUE_STRIDE;
916         attr.tis_num = priv->sh->tis->id;
917         tmpl->sq = mlx5_devx_cmd_create_sq(priv->sh->ctx, &attr);
918         if (!tmpl->sq) {
919                 DRV_LOG(ERR,
920                         "Port %u tx hairpin queue %u can't create SQ object.",
921                         dev->data->port_id, idx);
922                 rte_errno = errno;
923                 return -rte_errno;
924         }
925         return 0;
926 }
927
928 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET
929 /**
930  * Release DevX SQ resources.
931  *
932  * @param txq_obj
933  *   DevX Tx queue object.
934  */
935 static void
936 mlx5_txq_release_devx_sq_resources(struct mlx5_txq_obj *txq_obj)
937 {
938         if (txq_obj->sq_devx)
939                 claim_zero(mlx5_devx_cmd_destroy(txq_obj->sq_devx));
940         if (txq_obj->sq_umem)
941                 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->sq_umem));
942         if (txq_obj->sq_buf)
943                 mlx5_free(txq_obj->sq_buf);
944         if (txq_obj->sq_dbrec_page)
945                 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs,
946                                             mlx5_os_get_umem_id
947                                                  (txq_obj->sq_dbrec_page->umem),
948                                             txq_obj->sq_dbrec_offset));
949 }
950
951 /**
952  * Release DevX Tx CQ resources.
953  *
954  * @param txq_obj
955  *   DevX Tx queue object.
956  */
957 static void
958 mlx5_txq_release_devx_cq_resources(struct mlx5_txq_obj *txq_obj)
959 {
960         if (txq_obj->cq_devx)
961                 claim_zero(mlx5_devx_cmd_destroy(txq_obj->cq_devx));
962         if (txq_obj->cq_umem)
963                 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->cq_umem));
964         if (txq_obj->cq_buf)
965                 mlx5_free(txq_obj->cq_buf);
966         if (txq_obj->cq_dbrec_page)
967                 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs,
968                                             mlx5_os_get_umem_id
969                                                  (txq_obj->cq_dbrec_page->umem),
970                                             txq_obj->cq_dbrec_offset));
971 }
972
973 /**
974  * Destroy the Tx queue DevX object.
975  *
976  * @param txq_obj
977  *   Txq object to destroy.
978  */
979 static void
980 mlx5_txq_release_devx_resources(struct mlx5_txq_obj *txq_obj)
981 {
982         mlx5_txq_release_devx_cq_resources(txq_obj);
983         mlx5_txq_release_devx_sq_resources(txq_obj);
984 }
985
986 /**
987  * Create a DevX CQ object and its resources for an Tx queue.
988  *
989  * @param dev
990  *   Pointer to Ethernet device.
991  * @param idx
992  *   Queue index in DPDK Tx queue array.
993  *
994  * @return
995  *   Number of CQEs in CQ, 0 otherwise and rte_errno is set.
996  */
997 static uint32_t
998 mlx5_txq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx)
999 {
1000         struct mlx5_priv *priv = dev->data->dev_private;
1001         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1002         struct mlx5_txq_ctrl *txq_ctrl =
1003                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1004         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1005         struct mlx5_devx_cq_attr cq_attr = { 0 };
1006         struct mlx5_cqe *cqe;
1007         size_t page_size;
1008         size_t alignment;
1009         uint32_t cqe_n;
1010         uint32_t i;
1011         int ret;
1012
1013         MLX5_ASSERT(txq_data);
1014         MLX5_ASSERT(txq_obj);
1015         page_size = rte_mem_page_size();
1016         if (page_size == (size_t)-1) {
1017                 DRV_LOG(ERR, "Failed to get mem page size.");
1018                 rte_errno = ENOMEM;
1019                 return 0;
1020         }
1021         /* Allocate memory buffer for CQEs. */
1022         alignment = MLX5_CQE_BUF_ALIGNMENT;
1023         if (alignment == (size_t)-1) {
1024                 DRV_LOG(ERR, "Failed to get CQE buf alignment.");
1025                 rte_errno = ENOMEM;
1026                 return 0;
1027         }
1028         /* Create the Completion Queue. */
1029         cqe_n = (1UL << txq_data->elts_n) / MLX5_TX_COMP_THRESH +
1030                 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
1031         cqe_n = 1UL << log2above(cqe_n);
1032         if (cqe_n > UINT16_MAX) {
1033                 DRV_LOG(ERR,
1034                         "Port %u Tx queue %u requests to many CQEs %u.",
1035                         dev->data->port_id, txq_data->idx, cqe_n);
1036                 rte_errno = EINVAL;
1037                 return 0;
1038         }
1039         txq_obj->cq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
1040                                       cqe_n * sizeof(struct mlx5_cqe),
1041                                       alignment,
1042                                       priv->sh->numa_node);
1043         if (!txq_obj->cq_buf) {
1044                 DRV_LOG(ERR,
1045                         "Port %u Tx queue %u cannot allocate memory (CQ).",
1046                         dev->data->port_id, txq_data->idx);
1047                 rte_errno = ENOMEM;
1048                 return 0;
1049         }
1050         /* Register allocated buffer in user space with DevX. */
1051         txq_obj->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx,
1052                                                 (void *)txq_obj->cq_buf,
1053                                                 cqe_n * sizeof(struct mlx5_cqe),
1054                                                 IBV_ACCESS_LOCAL_WRITE);
1055         if (!txq_obj->cq_umem) {
1056                 rte_errno = errno;
1057                 DRV_LOG(ERR,
1058                         "Port %u Tx queue %u cannot register memory (CQ).",
1059                         dev->data->port_id, txq_data->idx);
1060                 goto error;
1061         }
1062         /* Allocate doorbell record for completion queue. */
1063         txq_obj->cq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx,
1064                                                 &priv->dbrpgs,
1065                                                 &txq_obj->cq_dbrec_page);
1066         if (txq_obj->cq_dbrec_offset < 0) {
1067                 rte_errno = errno;
1068                 DRV_LOG(ERR, "Failed to allocate CQ door-bell.");
1069                 goto error;
1070         }
1071         cq_attr.cqe_size = (sizeof(struct mlx5_cqe) == 128) ?
1072                             MLX5_CQE_SIZE_128B : MLX5_CQE_SIZE_64B;
1073         cq_attr.uar_page_id = mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar);
1074         cq_attr.eqn = priv->sh->eqn;
1075         cq_attr.q_umem_valid = 1;
1076         cq_attr.q_umem_offset = (uintptr_t)txq_obj->cq_buf % page_size;
1077         cq_attr.q_umem_id = mlx5_os_get_umem_id(txq_obj->cq_umem);
1078         cq_attr.db_umem_valid = 1;
1079         cq_attr.db_umem_offset = txq_obj->cq_dbrec_offset;
1080         cq_attr.db_umem_id = mlx5_os_get_umem_id(txq_obj->cq_dbrec_page->umem);
1081         cq_attr.log_cq_size = rte_log2_u32(cqe_n);
1082         cq_attr.log_page_size = rte_log2_u32(page_size);
1083         /* Create completion queue object with DevX. */
1084         txq_obj->cq_devx = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr);
1085         if (!txq_obj->cq_devx) {
1086                 rte_errno = errno;
1087                 DRV_LOG(ERR, "Port %u Tx queue %u CQ creation failure.",
1088                         dev->data->port_id, idx);
1089                 goto error;
1090         }
1091         /* Initial fill CQ buffer with invalid CQE opcode. */
1092         cqe = (struct mlx5_cqe *)txq_obj->cq_buf;
1093         for (i = 0; i < cqe_n; i++) {
1094                 cqe->op_own = (MLX5_CQE_INVALID << 4) | MLX5_CQE_OWNER_MASK;
1095                 ++cqe;
1096         }
1097         return cqe_n;
1098 error:
1099         ret = rte_errno;
1100         mlx5_txq_release_devx_cq_resources(txq_obj);
1101         rte_errno = ret;
1102         return 0;
1103 }
1104
1105 /**
1106  * Create a SQ object and its resources using DevX.
1107  *
1108  * @param dev
1109  *   Pointer to Ethernet device.
1110  * @param idx
1111  *   Queue index in DPDK Tx queue array.
1112  *
1113  * @return
1114  *   Number of WQEs in SQ, 0 otherwise and rte_errno is set.
1115  */
1116 static uint32_t
1117 mlx5_txq_create_devx_sq_resources(struct rte_eth_dev *dev, uint16_t idx)
1118 {
1119         struct mlx5_priv *priv = dev->data->dev_private;
1120         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1121         struct mlx5_txq_ctrl *txq_ctrl =
1122                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1123         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1124         struct mlx5_devx_create_sq_attr sq_attr = { 0 };
1125         size_t page_size;
1126         uint32_t wqe_n;
1127         int ret;
1128
1129         MLX5_ASSERT(txq_data);
1130         MLX5_ASSERT(txq_obj);
1131         page_size = rte_mem_page_size();
1132         if (page_size == (size_t)-1) {
1133                 DRV_LOG(ERR, "Failed to get mem page size.");
1134                 rte_errno = ENOMEM;
1135                 return 0;
1136         }
1137         wqe_n = RTE_MIN(1UL << txq_data->elts_n,
1138                         (uint32_t)priv->sh->device_attr.max_qp_wr);
1139         txq_obj->sq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
1140                                       wqe_n * sizeof(struct mlx5_wqe),
1141                                       page_size, priv->sh->numa_node);
1142         if (!txq_obj->sq_buf) {
1143                 DRV_LOG(ERR,
1144                         "Port %u Tx queue %u cannot allocate memory (SQ).",
1145                         dev->data->port_id, txq_data->idx);
1146                 rte_errno = ENOMEM;
1147                 goto error;
1148         }
1149         /* Register allocated buffer in user space with DevX. */
1150         txq_obj->sq_umem = mlx5_glue->devx_umem_reg
1151                                         (priv->sh->ctx,
1152                                          (void *)txq_obj->sq_buf,
1153                                          wqe_n * sizeof(struct mlx5_wqe),
1154                                          IBV_ACCESS_LOCAL_WRITE);
1155         if (!txq_obj->sq_umem) {
1156                 rte_errno = errno;
1157                 DRV_LOG(ERR,
1158                         "Port %u Tx queue %u cannot register memory (SQ).",
1159                         dev->data->port_id, txq_data->idx);
1160                 goto error;
1161         }
1162         /* Allocate doorbell record for send queue. */
1163         txq_obj->sq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx,
1164                                                 &priv->dbrpgs,
1165                                                 &txq_obj->sq_dbrec_page);
1166         if (txq_obj->sq_dbrec_offset < 0) {
1167                 rte_errno = errno;
1168                 DRV_LOG(ERR, "Failed to allocate SQ door-bell.");
1169                 goto error;
1170         }
1171         sq_attr.tis_lst_sz = 1;
1172         sq_attr.tis_num = priv->sh->tis->id;
1173         sq_attr.state = MLX5_SQC_STATE_RST;
1174         sq_attr.cqn = txq_obj->cq_devx->id;
1175         sq_attr.flush_in_error_en = 1;
1176         sq_attr.allow_multi_pkt_send_wqe = !!priv->config.mps;
1177         sq_attr.allow_swp = !!priv->config.swp;
1178         sq_attr.min_wqe_inline_mode = priv->config.hca_attr.vport_inline_mode;
1179         sq_attr.wq_attr.uar_page =
1180                                 mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar);
1181         sq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
1182         sq_attr.wq_attr.pd = priv->sh->pdn;
1183         sq_attr.wq_attr.log_wq_stride = rte_log2_u32(MLX5_WQE_SIZE);
1184         sq_attr.wq_attr.log_wq_sz = log2above(wqe_n);
1185         sq_attr.wq_attr.dbr_umem_valid = 1;
1186         sq_attr.wq_attr.dbr_addr = txq_obj->sq_dbrec_offset;
1187         sq_attr.wq_attr.dbr_umem_id =
1188                         mlx5_os_get_umem_id(txq_obj->sq_dbrec_page->umem);
1189         sq_attr.wq_attr.wq_umem_valid = 1;
1190         sq_attr.wq_attr.wq_umem_id = mlx5_os_get_umem_id(txq_obj->sq_umem);
1191         sq_attr.wq_attr.wq_umem_offset = (uintptr_t)txq_obj->sq_buf % page_size;
1192         /* Create Send Queue object with DevX. */
1193         txq_obj->sq_devx = mlx5_devx_cmd_create_sq(priv->sh->ctx, &sq_attr);
1194         if (!txq_obj->sq_devx) {
1195                 rte_errno = errno;
1196                 DRV_LOG(ERR, "Port %u Tx queue %u SQ creation failure.",
1197                         dev->data->port_id, idx);
1198                 goto error;
1199         }
1200         return wqe_n;
1201 error:
1202         ret = rte_errno;
1203         mlx5_txq_release_devx_sq_resources(txq_obj);
1204         rte_errno = ret;
1205         return 0;
1206 }
1207 #endif
1208
1209 /**
1210  * Create the Tx queue DevX object.
1211  *
1212  * @param dev
1213  *   Pointer to Ethernet device.
1214  * @param idx
1215  *   Queue index in DPDK Tx queue array.
1216  *
1217  * @return
1218  *   0 on success, a negative errno value otherwise and rte_errno is set.
1219  */
1220 int
1221 mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx)
1222 {
1223         struct mlx5_priv *priv = dev->data->dev_private;
1224         struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1225         struct mlx5_txq_ctrl *txq_ctrl =
1226                         container_of(txq_data, struct mlx5_txq_ctrl, txq);
1227
1228         if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN)
1229                 return mlx5_txq_obj_hairpin_new(dev, idx);
1230 #ifndef HAVE_MLX5DV_DEVX_UAR_OFFSET
1231         DRV_LOG(ERR, "Port %u Tx queue %u cannot create with DevX, no UAR.",
1232                      dev->data->port_id, idx);
1233         rte_errno = ENOMEM;
1234         return -rte_errno;
1235 #else
1236         struct mlx5_dev_ctx_shared *sh = priv->sh;
1237         struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1238         void *reg_addr;
1239         uint32_t cqe_n;
1240         uint32_t wqe_n;
1241         int ret = 0;
1242
1243         MLX5_ASSERT(txq_data);
1244         MLX5_ASSERT(txq_obj);
1245         txq_obj->txq_ctrl = txq_ctrl;
1246         txq_obj->dev = dev;
1247         cqe_n = mlx5_txq_create_devx_cq_resources(dev, idx);
1248         if (!cqe_n) {
1249                 rte_errno = errno;
1250                 goto error;
1251         }
1252         txq_data->cqe_n = log2above(cqe_n);
1253         txq_data->cqe_s = 1 << txq_data->cqe_n;
1254         txq_data->cqe_m = txq_data->cqe_s - 1;
1255         txq_data->cqes = (volatile struct mlx5_cqe *)txq_obj->cq_buf;
1256         txq_data->cq_ci = 0;
1257         txq_data->cq_pi = 0;
1258         txq_data->cq_db = (volatile uint32_t *)(txq_obj->cq_dbrec_page->dbrs +
1259                                                 txq_obj->cq_dbrec_offset);
1260         *txq_data->cq_db = 0;
1261         /* Create Send Queue object with DevX. */
1262         wqe_n = mlx5_txq_create_devx_sq_resources(dev, idx);
1263         if (!wqe_n) {
1264                 rte_errno = errno;
1265                 goto error;
1266         }
1267         /* Create the Work Queue. */
1268         txq_data->wqe_n = log2above(wqe_n);
1269         txq_data->wqe_s = 1 << txq_data->wqe_n;
1270         txq_data->wqe_m = txq_data->wqe_s - 1;
1271         txq_data->wqes = (struct mlx5_wqe *)txq_obj->sq_buf;
1272         txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s;
1273         txq_data->wqe_ci = 0;
1274         txq_data->wqe_pi = 0;
1275         txq_data->wqe_comp = 0;
1276         txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV;
1277         txq_data->qp_db = (volatile uint32_t *)
1278                                         (txq_obj->sq_dbrec_page->dbrs +
1279                                          txq_obj->sq_dbrec_offset +
1280                                          MLX5_SND_DBR * sizeof(uint32_t));
1281         *txq_data->qp_db = 0;
1282         txq_data->qp_num_8s = txq_obj->sq_devx->id << 8;
1283         /* Change Send Queue state to Ready-to-Send. */
1284         ret = mlx5_devx_modify_sq(txq_obj, MLX5_TXQ_MOD_RST2RDY, 0);
1285         if (ret) {
1286                 rte_errno = errno;
1287                 DRV_LOG(ERR,
1288                         "Port %u Tx queue %u SQ state to SQC_STATE_RDY failed.",
1289                         dev->data->port_id, idx);
1290                 goto error;
1291         }
1292 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
1293         /*
1294          * If using DevX need to query and store TIS transport domain value.
1295          * This is done once per port.
1296          * Will use this value on Rx, when creating matching TIR.
1297          */
1298         if (!priv->sh->tdn)
1299                 priv->sh->tdn = priv->sh->td->id;
1300 #endif
1301         MLX5_ASSERT(sh->tx_uar);
1302         reg_addr = mlx5_os_get_devx_uar_reg_addr(sh->tx_uar);
1303         MLX5_ASSERT(reg_addr);
1304         txq_ctrl->bf_reg = reg_addr;
1305         txq_ctrl->uar_mmap_offset =
1306                                 mlx5_os_get_devx_uar_mmap_offset(sh->tx_uar);
1307         txq_uar_init(txq_ctrl);
1308         return 0;
1309 error:
1310         ret = rte_errno; /* Save rte_errno before cleanup. */
1311         mlx5_txq_release_devx_resources(txq_obj);
1312         rte_errno = ret; /* Restore rte_errno. */
1313         return -rte_errno;
1314 #endif
1315 }
1316
1317 /**
1318  * Release an Tx DevX queue object.
1319  *
1320  * @param txq_obj
1321  *   DevX Tx queue object.
1322  */
1323 void
1324 mlx5_txq_devx_obj_release(struct mlx5_txq_obj *txq_obj)
1325 {
1326         MLX5_ASSERT(txq_obj);
1327         if (txq_obj->txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) {
1328                 if (txq_obj->tis)
1329                         claim_zero(mlx5_devx_cmd_destroy(txq_obj->tis));
1330 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET
1331         } else {
1332                 mlx5_txq_release_devx_resources(txq_obj);
1333 #endif
1334         }
1335 }
1336
1337 struct mlx5_obj_ops devx_obj_ops = {
1338         .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_rq_vlan_strip,
1339         .rxq_obj_new = mlx5_rxq_devx_obj_new,
1340         .rxq_event_get = mlx5_rx_devx_get_event,
1341         .rxq_obj_modify = mlx5_devx_modify_rq,
1342         .rxq_obj_release = mlx5_rxq_devx_obj_release,
1343         .ind_table_new = mlx5_devx_ind_table_new,
1344         .ind_table_destroy = mlx5_devx_ind_table_destroy,
1345         .hrxq_new = mlx5_devx_hrxq_new,
1346         .hrxq_destroy = mlx5_devx_tir_destroy,
1347         .drop_action_create = mlx5_devx_drop_action_create,
1348         .drop_action_destroy = mlx5_devx_drop_action_destroy,
1349         .txq_obj_new = mlx5_txq_devx_obj_new,
1350         .txq_obj_modify = mlx5_devx_modify_sq,
1351         .txq_obj_release = mlx5_txq_devx_obj_release,
1352 };