mlx5: support non-scattered Tx and Rx
[dpdk.git] / drivers / net / mlx5 / mlx5_rxq.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stddef.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdint.h>
39
40 /* Verbs header. */
41 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
42 #ifdef PEDANTIC
43 #pragma GCC diagnostic ignored "-pedantic"
44 #endif
45 #include <infiniband/verbs.h>
46 #ifdef PEDANTIC
47 #pragma GCC diagnostic error "-pedantic"
48 #endif
49
50 /* DPDK headers don't like -pedantic. */
51 #ifdef PEDANTIC
52 #pragma GCC diagnostic ignored "-pedantic"
53 #endif
54 #include <rte_mbuf.h>
55 #include <rte_malloc.h>
56 #include <rte_ethdev.h>
57 #include <rte_common.h>
58 #ifdef PEDANTIC
59 #pragma GCC diagnostic error "-pedantic"
60 #endif
61
62 #include "mlx5.h"
63 #include "mlx5_rxtx.h"
64 #include "mlx5_utils.h"
65 #include "mlx5_defs.h"
66
67 /**
68  * Allocate RX queue elements.
69  *
70  * @param rxq
71  *   Pointer to RX queue structure.
72  * @param elts_n
73  *   Number of elements to allocate.
74  * @param[in] pool
75  *   If not NULL, fetch buffers from this array instead of allocating them
76  *   with rte_pktmbuf_alloc().
77  *
78  * @return
79  *   0 on success, errno value on failure.
80  */
81 static int
82 rxq_alloc_elts(struct rxq *rxq, unsigned int elts_n, struct rte_mbuf **pool)
83 {
84         unsigned int i;
85         struct rxq_elt (*elts)[elts_n] =
86                 rte_calloc_socket("RXQ elements", 1, sizeof(*elts), 0,
87                                   rxq->socket);
88         int ret = 0;
89
90         if (elts == NULL) {
91                 ERROR("%p: can't allocate packets array", (void *)rxq);
92                 ret = ENOMEM;
93                 goto error;
94         }
95         /* For each WR (packet). */
96         for (i = 0; (i != elts_n); ++i) {
97                 struct rxq_elt *elt = &(*elts)[i];
98                 struct ibv_recv_wr *wr = &elt->wr;
99                 struct ibv_sge *sge = &(*elts)[i].sge;
100                 struct rte_mbuf *buf;
101
102                 if (pool != NULL) {
103                         buf = *(pool++);
104                         assert(buf != NULL);
105                         rte_pktmbuf_reset(buf);
106                 } else
107                         buf = rte_pktmbuf_alloc(rxq->mp);
108                 if (buf == NULL) {
109                         assert(pool == NULL);
110                         ERROR("%p: empty mbuf pool", (void *)rxq);
111                         ret = ENOMEM;
112                         goto error;
113                 }
114                 /* Configure WR. Work request ID contains its own index in
115                  * the elts array and the offset between SGE buffer header and
116                  * its data. */
117                 WR_ID(wr->wr_id).id = i;
118                 WR_ID(wr->wr_id).offset =
119                         (((uintptr_t)buf->buf_addr + RTE_PKTMBUF_HEADROOM) -
120                          (uintptr_t)buf);
121                 wr->next = &(*elts)[(i + 1)].wr;
122                 wr->sg_list = sge;
123                 wr->num_sge = 1;
124                 /* Headroom is reserved by rte_pktmbuf_alloc(). */
125                 assert(DATA_OFF(buf) == RTE_PKTMBUF_HEADROOM);
126                 /* Buffer is supposed to be empty. */
127                 assert(rte_pktmbuf_data_len(buf) == 0);
128                 assert(rte_pktmbuf_pkt_len(buf) == 0);
129                 /* sge->addr must be able to store a pointer. */
130                 assert(sizeof(sge->addr) >= sizeof(uintptr_t));
131                 /* SGE keeps its headroom. */
132                 sge->addr = (uintptr_t)
133                         ((uint8_t *)buf->buf_addr + RTE_PKTMBUF_HEADROOM);
134                 sge->length = (buf->buf_len - RTE_PKTMBUF_HEADROOM);
135                 sge->lkey = rxq->mr->lkey;
136                 /* Redundant check for tailroom. */
137                 assert(sge->length == rte_pktmbuf_tailroom(buf));
138                 /* Make sure elts index and SGE mbuf pointer can be deduced
139                  * from WR ID. */
140                 if ((WR_ID(wr->wr_id).id != i) ||
141                     ((void *)((uintptr_t)sge->addr -
142                         WR_ID(wr->wr_id).offset) != buf)) {
143                         ERROR("%p: cannot store index and offset in WR ID",
144                               (void *)rxq);
145                         sge->addr = 0;
146                         rte_pktmbuf_free(buf);
147                         ret = EOVERFLOW;
148                         goto error;
149                 }
150         }
151         /* The last WR pointer must be NULL. */
152         (*elts)[(i - 1)].wr.next = NULL;
153         DEBUG("%p: allocated and configured %u single-segment WRs",
154               (void *)rxq, elts_n);
155         rxq->elts_n = elts_n;
156         rxq->elts_head = 0;
157         rxq->elts.no_sp = elts;
158         assert(ret == 0);
159         return 0;
160 error:
161         if (elts != NULL) {
162                 assert(pool == NULL);
163                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
164                         struct rxq_elt *elt = &(*elts)[i];
165                         struct rte_mbuf *buf;
166
167                         if (elt->sge.addr == 0)
168                                 continue;
169                         assert(WR_ID(elt->wr.wr_id).id == i);
170                         buf = (void *)((uintptr_t)elt->sge.addr -
171                                 WR_ID(elt->wr.wr_id).offset);
172                         rte_pktmbuf_free_seg(buf);
173                 }
174                 rte_free(elts);
175         }
176         DEBUG("%p: failed, freed everything", (void *)rxq);
177         assert(ret > 0);
178         return ret;
179 }
180
181 /**
182  * Free RX queue elements.
183  *
184  * @param rxq
185  *   Pointer to RX queue structure.
186  */
187 static void
188 rxq_free_elts(struct rxq *rxq)
189 {
190         unsigned int i;
191         unsigned int elts_n = rxq->elts_n;
192         struct rxq_elt (*elts)[elts_n] = rxq->elts.no_sp;
193
194         DEBUG("%p: freeing WRs", (void *)rxq);
195         rxq->elts_n = 0;
196         rxq->elts.no_sp = NULL;
197         if (elts == NULL)
198                 return;
199         for (i = 0; (i != RTE_DIM(*elts)); ++i) {
200                 struct rxq_elt *elt = &(*elts)[i];
201                 struct rte_mbuf *buf;
202
203                 if (elt->sge.addr == 0)
204                         continue;
205                 assert(WR_ID(elt->wr.wr_id).id == i);
206                 buf = (void *)((uintptr_t)elt->sge.addr -
207                         WR_ID(elt->wr.wr_id).offset);
208                 rte_pktmbuf_free_seg(buf);
209         }
210         rte_free(elts);
211 }
212
213 /**
214  * Clean up a RX queue.
215  *
216  * Destroy objects, free allocated memory and reset the structure for reuse.
217  *
218  * @param rxq
219  *   Pointer to RX queue structure.
220  */
221 void
222 rxq_cleanup(struct rxq *rxq)
223 {
224         struct ibv_exp_release_intf_params params;
225
226         DEBUG("cleaning up %p", (void *)rxq);
227         rxq_free_elts(rxq);
228         if (rxq->if_qp != NULL) {
229                 assert(rxq->priv != NULL);
230                 assert(rxq->priv->ctx != NULL);
231                 assert(rxq->qp != NULL);
232                 params = (struct ibv_exp_release_intf_params){
233                         .comp_mask = 0,
234                 };
235                 claim_zero(ibv_exp_release_intf(rxq->priv->ctx,
236                                                 rxq->if_qp,
237                                                 &params));
238         }
239         if (rxq->if_cq != NULL) {
240                 assert(rxq->priv != NULL);
241                 assert(rxq->priv->ctx != NULL);
242                 assert(rxq->cq != NULL);
243                 params = (struct ibv_exp_release_intf_params){
244                         .comp_mask = 0,
245                 };
246                 claim_zero(ibv_exp_release_intf(rxq->priv->ctx,
247                                                 rxq->if_cq,
248                                                 &params));
249         }
250         if (rxq->qp != NULL) {
251                 claim_zero(ibv_destroy_qp(rxq->qp));
252         }
253         if (rxq->cq != NULL)
254                 claim_zero(ibv_destroy_cq(rxq->cq));
255         if (rxq->rd != NULL) {
256                 struct ibv_exp_destroy_res_domain_attr attr = {
257                         .comp_mask = 0,
258                 };
259
260                 assert(rxq->priv != NULL);
261                 assert(rxq->priv->ctx != NULL);
262                 claim_zero(ibv_exp_destroy_res_domain(rxq->priv->ctx,
263                                                       rxq->rd,
264                                                       &attr));
265         }
266         if (rxq->mr != NULL)
267                 claim_zero(ibv_dereg_mr(rxq->mr));
268         memset(rxq, 0, sizeof(*rxq));
269 }
270
271 /**
272  * Allocate a Queue Pair.
273  * Optionally setup inline receive if supported.
274  *
275  * @param priv
276  *   Pointer to private structure.
277  * @param cq
278  *   Completion queue to associate with QP.
279  * @param desc
280  *   Number of descriptors in QP (hint only).
281  *
282  * @return
283  *   QP pointer or NULL in case of error.
284  */
285 static struct ibv_qp *
286 rxq_setup_qp(struct priv *priv, struct ibv_cq *cq, uint16_t desc,
287              struct ibv_exp_res_domain *rd)
288 {
289         struct ibv_exp_qp_init_attr attr = {
290                 /* CQ to be associated with the send queue. */
291                 .send_cq = cq,
292                 /* CQ to be associated with the receive queue. */
293                 .recv_cq = cq,
294                 .cap = {
295                         /* Max number of outstanding WRs. */
296                         .max_recv_wr = ((priv->device_attr.max_qp_wr < desc) ?
297                                         priv->device_attr.max_qp_wr :
298                                         desc),
299                         /* Max number of scatter/gather elements in a WR. */
300                         .max_recv_sge = ((priv->device_attr.max_sge <
301                                           MLX5_PMD_SGE_WR_N) ?
302                                          priv->device_attr.max_sge :
303                                          MLX5_PMD_SGE_WR_N),
304                 },
305                 .qp_type = IBV_QPT_RAW_PACKET,
306                 .comp_mask = (IBV_EXP_QP_INIT_ATTR_PD |
307                               IBV_EXP_QP_INIT_ATTR_RES_DOMAIN),
308                 .pd = priv->pd,
309                 .res_domain = rd,
310         };
311
312         return ibv_exp_create_qp(priv->ctx, &attr);
313 }
314
315 #ifdef RSS_SUPPORT
316
317 /**
318  * Allocate a RSS Queue Pair.
319  * Optionally setup inline receive if supported.
320  *
321  * @param priv
322  *   Pointer to private structure.
323  * @param cq
324  *   Completion queue to associate with QP.
325  * @param desc
326  *   Number of descriptors in QP (hint only).
327  * @param parent
328  *   If nonzero, create a parent QP, otherwise a child.
329  *
330  * @return
331  *   QP pointer or NULL in case of error.
332  */
333 static struct ibv_qp *
334 rxq_setup_qp_rss(struct priv *priv, struct ibv_cq *cq, uint16_t desc,
335                  int parent, struct ibv_exp_res_domain *rd)
336 {
337         struct ibv_exp_qp_init_attr attr = {
338                 /* CQ to be associated with the send queue. */
339                 .send_cq = cq,
340                 /* CQ to be associated with the receive queue. */
341                 .recv_cq = cq,
342                 .cap = {
343                         /* Max number of outstanding WRs. */
344                         .max_recv_wr = ((priv->device_attr.max_qp_wr < desc) ?
345                                         priv->device_attr.max_qp_wr :
346                                         desc),
347                         /* Max number of scatter/gather elements in a WR. */
348                         .max_recv_sge = ((priv->device_attr.max_sge <
349                                           MLX5_PMD_SGE_WR_N) ?
350                                          priv->device_attr.max_sge :
351                                          MLX5_PMD_SGE_WR_N),
352                 },
353                 .qp_type = IBV_QPT_RAW_PACKET,
354                 .comp_mask = (IBV_EXP_QP_INIT_ATTR_PD |
355                               IBV_EXP_QP_INIT_ATTR_RES_DOMAIN |
356                               IBV_EXP_QP_INIT_ATTR_QPG),
357                 .pd = priv->pd,
358                 .res_domain = rd,
359         };
360
361         if (parent) {
362                 attr.qpg.qpg_type = IBV_EXP_QPG_PARENT;
363                 /* TSS isn't necessary. */
364                 attr.qpg.parent_attrib.tss_child_count = 0;
365                 attr.qpg.parent_attrib.rss_child_count = priv->rxqs_n;
366                 DEBUG("initializing parent RSS queue");
367         } else {
368                 attr.qpg.qpg_type = IBV_EXP_QPG_CHILD_RX;
369                 attr.qpg.qpg_parent = priv->rxq_parent.qp;
370                 DEBUG("initializing child RSS queue");
371         }
372         return ibv_exp_create_qp(priv->ctx, &attr);
373 }
374
375 #endif /* RSS_SUPPORT */
376
377 /**
378  * Configure a RX queue.
379  *
380  * @param dev
381  *   Pointer to Ethernet device structure.
382  * @param rxq
383  *   Pointer to RX queue structure.
384  * @param desc
385  *   Number of descriptors to configure in queue.
386  * @param socket
387  *   NUMA socket on which memory must be allocated.
388  * @param[in] conf
389  *   Thresholds parameters.
390  * @param mp
391  *   Memory pool for buffer allocations.
392  *
393  * @return
394  *   0 on success, errno value on failure.
395  */
396 int
397 rxq_setup(struct rte_eth_dev *dev, struct rxq *rxq, uint16_t desc,
398           unsigned int socket, const struct rte_eth_rxconf *conf,
399           struct rte_mempool *mp)
400 {
401         struct priv *priv = dev->data->dev_private;
402         struct rxq tmpl = {
403                 .priv = priv,
404                 .mp = mp,
405                 .socket = socket
406         };
407         struct ibv_exp_qp_attr mod;
408         union {
409                 struct ibv_exp_query_intf_params params;
410                 struct ibv_exp_cq_init_attr cq;
411                 struct ibv_exp_res_domain_init_attr rd;
412         } attr;
413         enum ibv_exp_query_intf_status status;
414         struct ibv_recv_wr *bad_wr;
415         struct rte_mbuf *buf;
416         int ret = 0;
417         int parent = (rxq == &priv->rxq_parent);
418
419         (void)conf; /* Thresholds configuration (ignored). */
420         /*
421          * If this is a parent queue, hardware must support RSS and
422          * RSS must be enabled.
423          */
424         assert((!parent) || ((priv->hw_rss) && (priv->rss)));
425         if (parent) {
426                 /* Even if unused, ibv_create_cq() requires at least one
427                  * descriptor. */
428                 desc = 1;
429                 goto skip_mr;
430         }
431         if ((desc == 0) || (desc % MLX5_PMD_SGE_WR_N)) {
432                 ERROR("%p: invalid number of RX descriptors (must be a"
433                       " multiple of %d)", (void *)dev, MLX5_PMD_SGE_WR_N);
434                 return EINVAL;
435         }
436         /* Get mbuf length. */
437         buf = rte_pktmbuf_alloc(mp);
438         if (buf == NULL) {
439                 ERROR("%p: unable to allocate mbuf", (void *)dev);
440                 return ENOMEM;
441         }
442         tmpl.mb_len = buf->buf_len;
443         assert((rte_pktmbuf_headroom(buf) +
444                 rte_pktmbuf_tailroom(buf)) == tmpl.mb_len);
445         assert(rte_pktmbuf_headroom(buf) == RTE_PKTMBUF_HEADROOM);
446         rte_pktmbuf_free(buf);
447         /* Use the entire RX mempool as the memory region. */
448         tmpl.mr = ibv_reg_mr(priv->pd,
449                              (void *)mp->elt_va_start,
450                              (mp->elt_va_end - mp->elt_va_start),
451                              (IBV_ACCESS_LOCAL_WRITE |
452                               IBV_ACCESS_REMOTE_WRITE));
453         if (tmpl.mr == NULL) {
454                 ret = EINVAL;
455                 ERROR("%p: MR creation failure: %s",
456                       (void *)dev, strerror(ret));
457                 goto error;
458         }
459 skip_mr:
460         attr.rd = (struct ibv_exp_res_domain_init_attr){
461                 .comp_mask = (IBV_EXP_RES_DOMAIN_THREAD_MODEL |
462                               IBV_EXP_RES_DOMAIN_MSG_MODEL),
463                 .thread_model = IBV_EXP_THREAD_SINGLE,
464                 .msg_model = IBV_EXP_MSG_HIGH_BW,
465         };
466         tmpl.rd = ibv_exp_create_res_domain(priv->ctx, &attr.rd);
467         if (tmpl.rd == NULL) {
468                 ret = ENOMEM;
469                 ERROR("%p: RD creation failure: %s",
470                       (void *)dev, strerror(ret));
471                 goto error;
472         }
473         attr.cq = (struct ibv_exp_cq_init_attr){
474                 .comp_mask = IBV_EXP_CQ_INIT_ATTR_RES_DOMAIN,
475                 .res_domain = tmpl.rd,
476         };
477         tmpl.cq = ibv_exp_create_cq(priv->ctx, desc, NULL, NULL, 0, &attr.cq);
478         if (tmpl.cq == NULL) {
479                 ret = ENOMEM;
480                 ERROR("%p: CQ creation failure: %s",
481                       (void *)dev, strerror(ret));
482                 goto error;
483         }
484         DEBUG("priv->device_attr.max_qp_wr is %d",
485               priv->device_attr.max_qp_wr);
486         DEBUG("priv->device_attr.max_sge is %d",
487               priv->device_attr.max_sge);
488 #ifdef RSS_SUPPORT
489         if (priv->rss)
490                 tmpl.qp = rxq_setup_qp_rss(priv, tmpl.cq, desc, parent,
491                                            tmpl.rd);
492         else
493 #endif /* RSS_SUPPORT */
494                 tmpl.qp = rxq_setup_qp(priv, tmpl.cq, desc, tmpl.rd);
495         if (tmpl.qp == NULL) {
496                 ret = (errno ? errno : EINVAL);
497                 ERROR("%p: QP creation failure: %s",
498                       (void *)dev, strerror(ret));
499                 goto error;
500         }
501         mod = (struct ibv_exp_qp_attr){
502                 /* Move the QP to this state. */
503                 .qp_state = IBV_QPS_INIT,
504                 /* Primary port number. */
505                 .port_num = priv->port
506         };
507         ret = ibv_exp_modify_qp(tmpl.qp, &mod,
508                                 (IBV_EXP_QP_STATE |
509 #ifdef RSS_SUPPORT
510                                  (parent ? IBV_EXP_QP_GROUP_RSS : 0) |
511 #endif /* RSS_SUPPORT */
512                                  IBV_EXP_QP_PORT));
513         if (ret) {
514                 ERROR("%p: QP state to IBV_QPS_INIT failed: %s",
515                       (void *)dev, strerror(ret));
516                 goto error;
517         }
518         /* Allocate descriptors for RX queues, except for the RSS parent. */
519         if (parent)
520                 goto skip_alloc;
521         ret = rxq_alloc_elts(&tmpl, desc, NULL);
522         if (ret) {
523                 ERROR("%p: RXQ allocation failed: %s",
524                       (void *)dev, strerror(ret));
525                 goto error;
526         }
527         ret = ibv_post_recv(tmpl.qp,
528                             &(*tmpl.elts.no_sp)[0].wr,
529                             &bad_wr);
530         if (ret) {
531                 ERROR("%p: ibv_post_recv() failed for WR %p: %s",
532                       (void *)dev,
533                       (void *)bad_wr,
534                       strerror(ret));
535                 goto error;
536         }
537 skip_alloc:
538         mod = (struct ibv_exp_qp_attr){
539                 .qp_state = IBV_QPS_RTR
540         };
541         ret = ibv_exp_modify_qp(tmpl.qp, &mod, IBV_EXP_QP_STATE);
542         if (ret) {
543                 ERROR("%p: QP state to IBV_QPS_RTR failed: %s",
544                       (void *)dev, strerror(ret));
545                 goto error;
546         }
547         /* Save port ID. */
548         tmpl.port_id = dev->data->port_id;
549         DEBUG("%p: RTE port ID: %u", (void *)rxq, tmpl.port_id);
550         attr.params = (struct ibv_exp_query_intf_params){
551                 .intf_scope = IBV_EXP_INTF_GLOBAL,
552                 .intf = IBV_EXP_INTF_CQ,
553                 .obj = tmpl.cq,
554         };
555         tmpl.if_cq = ibv_exp_query_intf(priv->ctx, &attr.params, &status);
556         if (tmpl.if_cq == NULL) {
557                 ERROR("%p: CQ interface family query failed with status %d",
558                       (void *)dev, status);
559                 goto error;
560         }
561         attr.params = (struct ibv_exp_query_intf_params){
562                 .intf_scope = IBV_EXP_INTF_GLOBAL,
563                 .intf = IBV_EXP_INTF_QP_BURST,
564                 .obj = tmpl.qp,
565         };
566         tmpl.if_qp = ibv_exp_query_intf(priv->ctx, &attr.params, &status);
567         if (tmpl.if_qp == NULL) {
568                 ERROR("%p: QP interface family query failed with status %d",
569                       (void *)dev, status);
570                 goto error;
571         }
572         /* Clean up rxq in case we're reinitializing it. */
573         DEBUG("%p: cleaning-up old rxq just in case", (void *)rxq);
574         rxq_cleanup(rxq);
575         *rxq = tmpl;
576         DEBUG("%p: rxq updated with %p", (void *)rxq, (void *)&tmpl);
577         assert(ret == 0);
578         return 0;
579 error:
580         rxq_cleanup(&tmpl);
581         assert(ret > 0);
582         return ret;
583 }
584
585 /**
586  * DPDK callback to configure a RX queue.
587  *
588  * @param dev
589  *   Pointer to Ethernet device structure.
590  * @param idx
591  *   RX queue index.
592  * @param desc
593  *   Number of descriptors to configure in queue.
594  * @param socket
595  *   NUMA socket on which memory must be allocated.
596  * @param[in] conf
597  *   Thresholds parameters.
598  * @param mp
599  *   Memory pool for buffer allocations.
600  *
601  * @return
602  *   0 on success, negative errno value on failure.
603  */
604 int
605 mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
606                     unsigned int socket, const struct rte_eth_rxconf *conf,
607                     struct rte_mempool *mp)
608 {
609         struct priv *priv = dev->data->dev_private;
610         struct rxq *rxq = (*priv->rxqs)[idx];
611         int ret;
612
613         priv_lock(priv);
614         DEBUG("%p: configuring queue %u for %u descriptors",
615               (void *)dev, idx, desc);
616         if (idx >= priv->rxqs_n) {
617                 ERROR("%p: queue index out of range (%u >= %u)",
618                       (void *)dev, idx, priv->rxqs_n);
619                 priv_unlock(priv);
620                 return -EOVERFLOW;
621         }
622         if (rxq != NULL) {
623                 DEBUG("%p: reusing already allocated queue index %u (%p)",
624                       (void *)dev, idx, (void *)rxq);
625                 if (priv->started) {
626                         priv_unlock(priv);
627                         return -EEXIST;
628                 }
629                 (*priv->rxqs)[idx] = NULL;
630                 rxq_cleanup(rxq);
631         } else {
632                 rxq = rte_calloc_socket("RXQ", 1, sizeof(*rxq), 0, socket);
633                 if (rxq == NULL) {
634                         ERROR("%p: unable to allocate queue index %u",
635                               (void *)dev, idx);
636                         priv_unlock(priv);
637                         return -ENOMEM;
638                 }
639         }
640         ret = rxq_setup(dev, rxq, desc, socket, conf, mp);
641         if (ret)
642                 rte_free(rxq);
643         else {
644                 DEBUG("%p: adding RX queue %p to list",
645                       (void *)dev, (void *)rxq);
646                 (*priv->rxqs)[idx] = rxq;
647                 /* Update receive callback. */
648                 dev->rx_pkt_burst = mlx5_rx_burst;
649         }
650         priv_unlock(priv);
651         return -ret;
652 }
653
654 /**
655  * DPDK callback to release a RX queue.
656  *
657  * @param dpdk_rxq
658  *   Generic RX queue pointer.
659  */
660 void
661 mlx5_rx_queue_release(void *dpdk_rxq)
662 {
663         struct rxq *rxq = (struct rxq *)dpdk_rxq;
664         struct priv *priv;
665         unsigned int i;
666
667         if (rxq == NULL)
668                 return;
669         priv = rxq->priv;
670         priv_lock(priv);
671         assert(rxq != &priv->rxq_parent);
672         for (i = 0; (i != priv->rxqs_n); ++i)
673                 if ((*priv->rxqs)[i] == rxq) {
674                         DEBUG("%p: removing RX queue %p from list",
675                               (void *)priv->dev, (void *)rxq);
676                         (*priv->rxqs)[i] = NULL;
677                         break;
678                 }
679         rxq_cleanup(rxq);
680         rte_free(rxq);
681         priv_unlock(priv);
682 }