e577e38aa4cfc8a21c72a964d59e17ad23cb97e3
[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
26
27 /**
28  * Modify RQ vlan stripping offload
29  *
30  * @param rxq_obj
31  *   Rx queue object.
32  *
33  * @return
34  *   0 on success, non-0 otherwise
35  */
36 static int
37 mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_obj *rxq_obj, int on)
38 {
39         struct mlx5_devx_modify_rq_attr rq_attr;
40
41         memset(&rq_attr, 0, sizeof(rq_attr));
42         rq_attr.rq_state = MLX5_RQC_STATE_RDY;
43         rq_attr.state = MLX5_RQC_STATE_RDY;
44         rq_attr.vsd = (on ? 0 : 1);
45         rq_attr.modify_bitmask = MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD;
46         return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);
47 }
48
49 /**
50  * Release the resources allocated for an RQ DevX object.
51  *
52  * @param rxq_ctrl
53  *   DevX Rx queue object.
54  */
55 static void
56 rxq_release_devx_rq_resources(struct mlx5_rxq_ctrl *rxq_ctrl)
57 {
58         struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->rq_dbrec_page;
59
60         if (rxq_ctrl->rxq.wqes) {
61                 mlx5_free((void *)(uintptr_t)rxq_ctrl->rxq.wqes);
62                 rxq_ctrl->rxq.wqes = NULL;
63         }
64         if (rxq_ctrl->wq_umem) {
65                 mlx5_glue->devx_umem_dereg(rxq_ctrl->wq_umem);
66                 rxq_ctrl->wq_umem = NULL;
67         }
68         if (dbr_page) {
69                 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs,
70                                             mlx5_os_get_umem_id(dbr_page->umem),
71                                             rxq_ctrl->rq_dbr_offset));
72                 rxq_ctrl->rq_dbrec_page = NULL;
73         }
74 }
75
76 /**
77  * Release the resources allocated for the Rx CQ DevX object.
78  *
79  * @param rxq_ctrl
80  *   DevX Rx queue object.
81  */
82 static void
83 rxq_release_devx_cq_resources(struct mlx5_rxq_ctrl *rxq_ctrl)
84 {
85         struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->cq_dbrec_page;
86
87         if (rxq_ctrl->rxq.cqes) {
88                 rte_free((void *)(uintptr_t)rxq_ctrl->rxq.cqes);
89                 rxq_ctrl->rxq.cqes = NULL;
90         }
91         if (rxq_ctrl->cq_umem) {
92                 mlx5_glue->devx_umem_dereg(rxq_ctrl->cq_umem);
93                 rxq_ctrl->cq_umem = NULL;
94         }
95         if (dbr_page) {
96                 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs,
97                                             mlx5_os_get_umem_id(dbr_page->umem),
98                                             rxq_ctrl->cq_dbr_offset));
99                 rxq_ctrl->cq_dbrec_page = NULL;
100         }
101 }
102
103 /**
104  * Release an Rx hairpin related resources.
105  *
106  * @param rxq_obj
107  *   Hairpin Rx queue object.
108  */
109 static void
110 mlx5_rxq_obj_hairpin_release(struct mlx5_rxq_obj *rxq_obj)
111 {
112         struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
113
114         MLX5_ASSERT(rxq_obj);
115         rq_attr.state = MLX5_RQC_STATE_RST;
116         rq_attr.rq_state = MLX5_RQC_STATE_RDY;
117         mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);
118         claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));
119 }
120
121 /**
122  * Release an Rx DevX queue object.
123  *
124  * @param rxq_obj
125  *   DevX Rx queue object.
126  */
127 static void
128 mlx5_rxq_devx_obj_release(struct mlx5_rxq_obj *rxq_obj)
129 {
130         MLX5_ASSERT(rxq_obj);
131         MLX5_ASSERT(rxq_obj->rq);
132         if (rxq_obj->type == MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN) {
133                 mlx5_rxq_obj_hairpin_release(rxq_obj);
134         } else {
135                 MLX5_ASSERT(rxq_obj->devx_cq);
136                 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));
137                 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->devx_cq));
138                 if (rxq_obj->devx_channel)
139                         mlx5_glue->devx_destroy_event_channel
140                                                         (rxq_obj->devx_channel);
141                 rxq_release_devx_rq_resources(rxq_obj->rxq_ctrl);
142                 rxq_release_devx_cq_resources(rxq_obj->rxq_ctrl);
143         }
144 }
145
146 /**
147  * Modify RQ using DevX API.
148  *
149  * @param rxq_obj
150  *   DevX Rx queue object.
151  *
152  * @return
153  *   0 on success, a negative errno value otherwise and rte_errno is set.
154  */
155 static int
156 mlx5_devx_modify_rq(struct mlx5_rxq_obj *rxq_obj, bool is_start)
157 {
158         struct mlx5_devx_modify_rq_attr rq_attr;
159
160         memset(&rq_attr, 0, sizeof(rq_attr));
161         if (is_start) {
162                 rq_attr.rq_state = MLX5_RQC_STATE_RST;
163                 rq_attr.state = MLX5_RQC_STATE_RDY;
164         } else {
165                 rq_attr.rq_state = MLX5_RQC_STATE_RDY;
166                 rq_attr.state = MLX5_RQC_STATE_RST;
167         }
168         return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);
169 }
170
171 /**
172  * Get event for an Rx DevX queue object.
173  *
174  * @param rxq_obj
175  *   DevX Rx queue object.
176  *
177  * @return
178  *   0 on success, a negative errno value otherwise and rte_errno is set.
179  */
180 static int
181 mlx5_rx_devx_get_event(struct mlx5_rxq_obj *rxq_obj)
182 {
183 #ifdef HAVE_IBV_DEVX_EVENT
184         union {
185                 struct mlx5dv_devx_async_event_hdr event_resp;
186                 uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
187         } out;
188         int ret = mlx5_glue->devx_get_event(rxq_obj->devx_channel,
189                                             &out.event_resp,
190                                             sizeof(out.buf));
191
192         if (ret < 0) {
193                 rte_errno = errno;
194                 return -rte_errno;
195         }
196         if (out.event_resp.cookie != (uint64_t)(uintptr_t)rxq_obj->devx_cq) {
197                 rte_errno = EINVAL;
198                 return -rte_errno;
199         }
200         return 0;
201 #else
202         (void)rxq_obj;
203         rte_errno = ENOTSUP;
204         return -rte_errno;
205 #endif /* HAVE_IBV_DEVX_EVENT */
206 }
207
208 /**
209  * Fill common fields of create RQ attributes structure.
210  *
211  * @param rxq_data
212  *   Pointer to Rx queue data.
213  * @param cqn
214  *   CQ number to use with this RQ.
215  * @param rq_attr
216  *   RQ attributes structure to fill..
217  */
218 static void
219 mlx5_devx_create_rq_attr_fill(struct mlx5_rxq_data *rxq_data, uint32_t cqn,
220                               struct mlx5_devx_create_rq_attr *rq_attr)
221 {
222         rq_attr->state = MLX5_RQC_STATE_RST;
223         rq_attr->vsd = (rxq_data->vlan_strip) ? 0 : 1;
224         rq_attr->cqn = cqn;
225         rq_attr->scatter_fcs = (rxq_data->crc_present) ? 1 : 0;
226 }
227
228 /**
229  * Fill common fields of DevX WQ attributes structure.
230  *
231  * @param priv
232  *   Pointer to device private data.
233  * @param rxq_ctrl
234  *   Pointer to Rx queue control structure.
235  * @param wq_attr
236  *   WQ attributes structure to fill..
237  */
238 static void
239 mlx5_devx_wq_attr_fill(struct mlx5_priv *priv, struct mlx5_rxq_ctrl *rxq_ctrl,
240                        struct mlx5_devx_wq_attr *wq_attr)
241 {
242         wq_attr->end_padding_mode = priv->config.cqe_pad ?
243                                         MLX5_WQ_END_PAD_MODE_ALIGN :
244                                         MLX5_WQ_END_PAD_MODE_NONE;
245         wq_attr->pd = priv->sh->pdn;
246         wq_attr->dbr_addr = rxq_ctrl->rq_dbr_offset;
247         wq_attr->dbr_umem_id =
248                         mlx5_os_get_umem_id(rxq_ctrl->rq_dbrec_page->umem);
249         wq_attr->dbr_umem_valid = 1;
250         wq_attr->wq_umem_id = mlx5_os_get_umem_id(rxq_ctrl->wq_umem);
251         wq_attr->wq_umem_valid = 1;
252 }
253
254 /**
255  * Create a RQ object using DevX.
256  *
257  * @param dev
258  *   Pointer to Ethernet device.
259  * @param idx
260  *   Queue index in DPDK Rx queue array.
261  *
262  * @return
263  *   The DevX RQ object initialized, NULL otherwise and rte_errno is set.
264  */
265 static struct mlx5_devx_obj *
266 rxq_create_devx_rq_resources(struct rte_eth_dev *dev, uint16_t idx)
267 {
268         struct mlx5_priv *priv = dev->data->dev_private;
269         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
270         struct mlx5_rxq_ctrl *rxq_ctrl =
271                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
272         struct mlx5_devx_create_rq_attr rq_attr = { 0 };
273         uint32_t wqe_n = 1 << (rxq_data->elts_n - rxq_data->sges_n);
274         uint32_t cqn = rxq_ctrl->obj->devx_cq->id;
275         struct mlx5_devx_dbr_page *dbr_page;
276         int64_t dbr_offset;
277         uint32_t wq_size = 0;
278         uint32_t wqe_size = 0;
279         uint32_t log_wqe_size = 0;
280         void *buf = NULL;
281         struct mlx5_devx_obj *rq;
282
283         /* Fill RQ attributes. */
284         rq_attr.mem_rq_type = MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE;
285         rq_attr.flush_in_error_en = 1;
286         mlx5_devx_create_rq_attr_fill(rxq_data, cqn, &rq_attr);
287         /* Fill WQ attributes for this RQ. */
288         if (mlx5_rxq_mprq_enabled(rxq_data)) {
289                 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ;
290                 /*
291                  * Number of strides in each WQE:
292                  * 512*2^single_wqe_log_num_of_strides.
293                  */
294                 rq_attr.wq_attr.single_wqe_log_num_of_strides =
295                                 rxq_data->strd_num_n -
296                                 MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES;
297                 /* Stride size = (2^single_stride_log_num_of_bytes)*64B. */
298                 rq_attr.wq_attr.single_stride_log_num_of_bytes =
299                                 rxq_data->strd_sz_n -
300                                 MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES;
301                 wqe_size = sizeof(struct mlx5_wqe_mprq);
302         } else {
303                 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
304                 wqe_size = sizeof(struct mlx5_wqe_data_seg);
305         }
306         log_wqe_size = log2above(wqe_size) + rxq_data->sges_n;
307         rq_attr.wq_attr.log_wq_stride = log_wqe_size;
308         rq_attr.wq_attr.log_wq_sz = rxq_data->elts_n - rxq_data->sges_n;
309         /* Calculate and allocate WQ memory space. */
310         wqe_size = 1 << log_wqe_size; /* round up power of two.*/
311         wq_size = wqe_n * wqe_size;
312         size_t alignment = MLX5_WQE_BUF_ALIGNMENT;
313         if (alignment == (size_t)-1) {
314                 DRV_LOG(ERR, "Failed to get mem page size");
315                 rte_errno = ENOMEM;
316                 return NULL;
317         }
318         buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, wq_size,
319                           alignment, rxq_ctrl->socket);
320         if (!buf)
321                 return NULL;
322         rxq_data->wqes = buf;
323         rxq_ctrl->wq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx,
324                                                      buf, wq_size, 0);
325         if (!rxq_ctrl->wq_umem)
326                 goto error;
327         /* Allocate RQ door-bell. */
328         dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page);
329         if (dbr_offset < 0) {
330                 DRV_LOG(ERR, "Failed to allocate RQ door-bell.");
331                 goto error;
332         }
333         rxq_ctrl->rq_dbr_offset = dbr_offset;
334         rxq_ctrl->rq_dbrec_page = dbr_page;
335         rxq_data->rq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs +
336                           (uintptr_t)rxq_ctrl->rq_dbr_offset);
337         /* Create RQ using DevX API. */
338         mlx5_devx_wq_attr_fill(priv, rxq_ctrl, &rq_attr.wq_attr);
339         rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &rq_attr, rxq_ctrl->socket);
340         if (!rq)
341                 goto error;
342         return rq;
343 error:
344         rxq_release_devx_rq_resources(rxq_ctrl);
345         return NULL;
346 }
347
348 /**
349  * Create a DevX CQ object for an Rx queue.
350  *
351  * @param dev
352  *   Pointer to Ethernet device.
353  * @param idx
354  *   Queue index in DPDK Rx queue array.
355  *
356  * @return
357  *   The DevX CQ object initialized, NULL otherwise and rte_errno is set.
358  */
359 static struct mlx5_devx_obj *
360 rxq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx)
361 {
362         struct mlx5_devx_obj *cq_obj = 0;
363         struct mlx5_devx_cq_attr cq_attr = { 0 };
364         struct mlx5_priv *priv = dev->data->dev_private;
365         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
366         struct mlx5_rxq_ctrl *rxq_ctrl =
367                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
368         size_t page_size = rte_mem_page_size();
369         uint32_t lcore = (uint32_t)rte_lcore_to_cpu_id(-1);
370         unsigned int cqe_n = mlx5_rxq_cqe_num(rxq_data);
371         struct mlx5_devx_dbr_page *dbr_page;
372         int64_t dbr_offset;
373         uint32_t eqn = 0;
374         void *buf = NULL;
375         uint16_t event_nums[1] = {0};
376         uint32_t log_cqe_n;
377         uint32_t cq_size;
378         int ret = 0;
379
380         if (page_size == (size_t)-1) {
381                 DRV_LOG(ERR, "Failed to get page_size.");
382                 goto error;
383         }
384         if (priv->config.cqe_comp && !rxq_data->hw_timestamp &&
385             !rxq_data->lro) {
386                 cq_attr.cqe_comp_en = MLX5DV_CQ_INIT_ATTR_MASK_COMPRESSED_CQE;
387 #ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
388                 cq_attr.mini_cqe_res_format =
389                                 mlx5_rxq_mprq_enabled(rxq_data) ?
390                                 MLX5DV_CQE_RES_FORMAT_CSUM_STRIDX :
391                                 MLX5DV_CQE_RES_FORMAT_HASH;
392 #else
393                 cq_attr.mini_cqe_res_format = MLX5DV_CQE_RES_FORMAT_HASH;
394 #endif
395                 /*
396                  * For vectorized Rx, it must not be doubled in order to
397                  * make cq_ci and rq_ci aligned.
398                  */
399                 if (mlx5_rxq_check_vec_support(rxq_data) < 0)
400                         cqe_n *= 2;
401         } else if (priv->config.cqe_comp && rxq_data->hw_timestamp) {
402                 DRV_LOG(DEBUG,
403                         "Port %u Rx CQE compression is disabled for HW"
404                         " timestamp.",
405                         dev->data->port_id);
406         } else if (priv->config.cqe_comp && rxq_data->lro) {
407                 DRV_LOG(DEBUG,
408                         "Port %u Rx CQE compression is disabled for LRO.",
409                         dev->data->port_id);
410         }
411 #ifdef HAVE_IBV_MLX5_MOD_CQE_128B_PAD
412         if (priv->config.cqe_pad)
413                 cq_attr.cqe_size = MLX5DV_CQ_INIT_ATTR_FLAGS_CQE_PAD;
414 #endif
415         log_cqe_n = log2above(cqe_n);
416         cq_size = sizeof(struct mlx5_cqe) * (1 << log_cqe_n);
417         /* Query the EQN for this core. */
418         if (mlx5_glue->devx_query_eqn(priv->sh->ctx, lcore, &eqn)) {
419                 DRV_LOG(ERR, "Failed to query EQN for CQ.");
420                 goto error;
421         }
422         cq_attr.eqn = eqn;
423         buf = rte_calloc_socket(__func__, 1, cq_size, page_size,
424                                 rxq_ctrl->socket);
425         if (!buf) {
426                 DRV_LOG(ERR, "Failed to allocate memory for CQ.");
427                 goto error;
428         }
429         rxq_data->cqes = (volatile struct mlx5_cqe (*)[])(uintptr_t)buf;
430         rxq_ctrl->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx, buf,
431                                                      cq_size,
432                                                      IBV_ACCESS_LOCAL_WRITE);
433         if (!rxq_ctrl->cq_umem) {
434                 DRV_LOG(ERR, "Failed to register umem for CQ.");
435                 goto error;
436         }
437         /* Allocate CQ door-bell. */
438         dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page);
439         if (dbr_offset < 0) {
440                 DRV_LOG(ERR, "Failed to allocate CQ door-bell.");
441                 goto error;
442         }
443         rxq_ctrl->cq_dbr_offset = dbr_offset;
444         rxq_ctrl->cq_dbrec_page = dbr_page;
445         rxq_data->cq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs +
446                           (uintptr_t)rxq_ctrl->cq_dbr_offset);
447         rxq_data->cq_uar =
448                         mlx5_os_get_devx_uar_base_addr(priv->sh->devx_rx_uar);
449         /* Create CQ using DevX API. */
450         cq_attr.uar_page_id =
451                         mlx5_os_get_devx_uar_page_id(priv->sh->devx_rx_uar);
452         cq_attr.q_umem_id = mlx5_os_get_umem_id(rxq_ctrl->cq_umem);
453         cq_attr.q_umem_valid = 1;
454         cq_attr.log_cq_size = log_cqe_n;
455         cq_attr.log_page_size = rte_log2_u32(page_size);
456         cq_attr.db_umem_offset = rxq_ctrl->cq_dbr_offset;
457         cq_attr.db_umem_id = mlx5_os_get_umem_id(dbr_page->umem);
458         cq_attr.db_umem_valid = 1;
459         cq_obj = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr);
460         if (!cq_obj)
461                 goto error;
462         rxq_data->cqe_n = log_cqe_n;
463         rxq_data->cqn = cq_obj->id;
464         if (rxq_ctrl->obj->devx_channel) {
465                 ret = mlx5_glue->devx_subscribe_devx_event
466                                                 (rxq_ctrl->obj->devx_channel,
467                                                  cq_obj->obj,
468                                                  sizeof(event_nums),
469                                                  event_nums,
470                                                  (uint64_t)(uintptr_t)cq_obj);
471                 if (ret) {
472                         DRV_LOG(ERR, "Fail to subscribe CQ to event channel.");
473                         rte_errno = errno;
474                         goto error;
475                 }
476         }
477         /* Initialise CQ to 1's to mark HW ownership for all CQEs. */
478         memset((void *)(uintptr_t)rxq_data->cqes, 0xFF, cq_size);
479         return cq_obj;
480 error:
481         if (cq_obj)
482                 mlx5_devx_cmd_destroy(cq_obj);
483         rxq_release_devx_cq_resources(rxq_ctrl);
484         return NULL;
485 }
486
487 /**
488  * Create the Rx hairpin queue object.
489  *
490  * @param dev
491  *   Pointer to Ethernet device.
492  * @param idx
493  *   Queue index in DPDK Rx queue array.
494  *
495  * @return
496  *   0 on success, a negative errno value otherwise and rte_errno is set.
497  */
498 static int
499 mlx5_rxq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx)
500 {
501         struct mlx5_priv *priv = dev->data->dev_private;
502         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
503         struct mlx5_rxq_ctrl *rxq_ctrl =
504                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
505         struct mlx5_devx_create_rq_attr attr = { 0 };
506         struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
507         uint32_t max_wq_data;
508
509         MLX5_ASSERT(rxq_data);
510         MLX5_ASSERT(tmpl);
511         tmpl->type = MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN;
512         tmpl->rxq_ctrl = rxq_ctrl;
513         attr.hairpin = 1;
514         max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz;
515         /* Jumbo frames > 9KB should be supported, and more packets. */
516         if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
517                 if (priv->config.log_hp_size > max_wq_data) {
518                         DRV_LOG(ERR, "Total data size %u power of 2 is "
519                                 "too large for hairpin.",
520                                 priv->config.log_hp_size);
521                         rte_errno = ERANGE;
522                         return -rte_errno;
523                 }
524                 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
525         } else {
526                 attr.wq_attr.log_hairpin_data_sz =
527                                 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
528                                  max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
529         }
530         /* Set the packets number to the maximum value for performance. */
531         attr.wq_attr.log_hairpin_num_packets =
532                         attr.wq_attr.log_hairpin_data_sz -
533                         MLX5_HAIRPIN_QUEUE_STRIDE;
534         tmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &attr,
535                                            rxq_ctrl->socket);
536         if (!tmpl->rq) {
537                 DRV_LOG(ERR,
538                         "Port %u Rx hairpin queue %u can't create rq object.",
539                         dev->data->port_id, idx);
540                 rte_errno = errno;
541                 return -rte_errno;
542         }
543         dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_HAIRPIN;
544         return 0;
545 }
546
547 /**
548  * Create the Rx queue DevX object.
549  *
550  * @param dev
551  *   Pointer to Ethernet device.
552  * @param idx
553  *   Queue index in DPDK Rx queue array.
554  *
555  * @return
556  *   0 on success, a negative errno value otherwise and rte_errno is set.
557  */
558 static int
559 mlx5_rxq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx)
560 {
561         struct mlx5_priv *priv = dev->data->dev_private;
562         struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];
563         struct mlx5_rxq_ctrl *rxq_ctrl =
564                 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq);
565         struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
566         struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
567         int ret = 0;
568
569         MLX5_ASSERT(rxq_data);
570         MLX5_ASSERT(tmpl);
571         if (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN)
572                 return mlx5_rxq_obj_hairpin_new(dev, idx);
573         tmpl->type = MLX5_RXQ_OBJ_TYPE_DEVX_RQ;
574         tmpl->rxq_ctrl = rxq_ctrl;
575         if (rxq_ctrl->irq) {
576                 int devx_ev_flag =
577                           MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA;
578
579                 tmpl->devx_channel = mlx5_glue->devx_create_event_channel
580                                                                 (priv->sh->ctx,
581                                                                  devx_ev_flag);
582                 if (!tmpl->devx_channel) {
583                         rte_errno = errno;
584                         DRV_LOG(ERR, "Failed to create event channel %d.",
585                                 rte_errno);
586                         goto error;
587                 }
588                 tmpl->fd = mlx5_os_get_devx_channel_fd(tmpl->devx_channel);
589         }
590         /* Create CQ using DevX API. */
591         tmpl->devx_cq = rxq_create_devx_cq_resources(dev, idx);
592         if (!tmpl->devx_cq) {
593                 DRV_LOG(ERR, "Failed to create CQ.");
594                 goto error;
595         }
596         /* Create RQ using DevX API. */
597         tmpl->rq = rxq_create_devx_rq_resources(dev, idx);
598         if (!tmpl->rq) {
599                 DRV_LOG(ERR, "Port %u Rx queue %u RQ creation failure.",
600                         dev->data->port_id, idx);
601                 rte_errno = ENOMEM;
602                 goto error;
603         }
604         /* Change queue state to ready. */
605         rq_attr.rq_state = MLX5_RQC_STATE_RST;
606         rq_attr.state = MLX5_RQC_STATE_RDY;
607         ret = mlx5_devx_cmd_modify_rq(tmpl->rq, &rq_attr);
608         if (ret)
609                 goto error;
610         rxq_data->cq_arm_sn = 0;
611         mlx5_rxq_initialize(rxq_data);
612         rxq_data->cq_ci = 0;
613         dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
614         rxq_ctrl->wqn = tmpl->rq->id;
615         return 0;
616 error:
617         ret = rte_errno; /* Save rte_errno before cleanup. */
618         if (tmpl->rq)
619                 claim_zero(mlx5_devx_cmd_destroy(tmpl->rq));
620         if (tmpl->devx_cq)
621                 claim_zero(mlx5_devx_cmd_destroy(tmpl->devx_cq));
622         if (tmpl->devx_channel)
623                 mlx5_glue->devx_destroy_event_channel(tmpl->devx_channel);
624         rxq_release_devx_rq_resources(rxq_ctrl);
625         rxq_release_devx_cq_resources(rxq_ctrl);
626         rte_errno = ret; /* Restore rte_errno. */
627         return -rte_errno;
628 }
629
630 struct mlx5_obj_ops devx_obj_ops = {
631         .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_rq_vlan_strip,
632         .rxq_obj_new = mlx5_rxq_devx_obj_new,
633         .rxq_event_get = mlx5_rx_devx_get_event,
634         .rxq_obj_modify = mlx5_devx_modify_rq,
635         .rxq_obj_release = mlx5_rxq_devx_obj_release,
636 };