remove extra parentheses in return statement
[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 /* Initialization data for hash RX queues. */
68 const struct hash_rxq_init hash_rxq_init[] = {
69         [HASH_RXQ_TCPV4] = {
70                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV4 |
71                                 IBV_EXP_RX_HASH_DST_IPV4 |
72                                 IBV_EXP_RX_HASH_SRC_PORT_TCP |
73                                 IBV_EXP_RX_HASH_DST_PORT_TCP),
74                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_TCP,
75                 .flow_priority = 0,
76                 .flow_spec.tcp_udp = {
77                         .type = IBV_EXP_FLOW_SPEC_TCP,
78                         .size = sizeof(hash_rxq_init[0].flow_spec.tcp_udp),
79                 },
80                 .underlayer = &hash_rxq_init[HASH_RXQ_IPV4],
81         },
82         [HASH_RXQ_UDPV4] = {
83                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV4 |
84                                 IBV_EXP_RX_HASH_DST_IPV4 |
85                                 IBV_EXP_RX_HASH_SRC_PORT_UDP |
86                                 IBV_EXP_RX_HASH_DST_PORT_UDP),
87                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_UDP,
88                 .flow_priority = 0,
89                 .flow_spec.tcp_udp = {
90                         .type = IBV_EXP_FLOW_SPEC_UDP,
91                         .size = sizeof(hash_rxq_init[0].flow_spec.tcp_udp),
92                 },
93                 .underlayer = &hash_rxq_init[HASH_RXQ_IPV4],
94         },
95         [HASH_RXQ_IPV4] = {
96                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV4 |
97                                 IBV_EXP_RX_HASH_DST_IPV4),
98                 .dpdk_rss_hf = (ETH_RSS_IPV4 |
99                                 ETH_RSS_FRAG_IPV4),
100                 .flow_priority = 1,
101                 .flow_spec.ipv4 = {
102                         .type = IBV_EXP_FLOW_SPEC_IPV4,
103                         .size = sizeof(hash_rxq_init[0].flow_spec.ipv4),
104                 },
105                 .underlayer = &hash_rxq_init[HASH_RXQ_ETH],
106         },
107 #ifdef HAVE_FLOW_SPEC_IPV6
108         [HASH_RXQ_TCPV6] = {
109                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV6 |
110                                 IBV_EXP_RX_HASH_DST_IPV6 |
111                                 IBV_EXP_RX_HASH_SRC_PORT_TCP |
112                                 IBV_EXP_RX_HASH_DST_PORT_TCP),
113                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_TCP,
114                 .flow_priority = 0,
115                 .flow_spec.tcp_udp = {
116                         .type = IBV_EXP_FLOW_SPEC_TCP,
117                         .size = sizeof(hash_rxq_init[0].flow_spec.tcp_udp),
118                 },
119                 .underlayer = &hash_rxq_init[HASH_RXQ_IPV6],
120         },
121         [HASH_RXQ_UDPV6] = {
122                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV6 |
123                                 IBV_EXP_RX_HASH_DST_IPV6 |
124                                 IBV_EXP_RX_HASH_SRC_PORT_UDP |
125                                 IBV_EXP_RX_HASH_DST_PORT_UDP),
126                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_UDP,
127                 .flow_priority = 0,
128                 .flow_spec.tcp_udp = {
129                         .type = IBV_EXP_FLOW_SPEC_UDP,
130                         .size = sizeof(hash_rxq_init[0].flow_spec.tcp_udp),
131                 },
132                 .underlayer = &hash_rxq_init[HASH_RXQ_IPV6],
133         },
134         [HASH_RXQ_IPV6] = {
135                 .hash_fields = (IBV_EXP_RX_HASH_SRC_IPV6 |
136                                 IBV_EXP_RX_HASH_DST_IPV6),
137                 .dpdk_rss_hf = (ETH_RSS_IPV6 |
138                                 ETH_RSS_FRAG_IPV6),
139                 .flow_priority = 1,
140                 .flow_spec.ipv6 = {
141                         .type = IBV_EXP_FLOW_SPEC_IPV6,
142                         .size = sizeof(hash_rxq_init[0].flow_spec.ipv6),
143                 },
144                 .underlayer = &hash_rxq_init[HASH_RXQ_ETH],
145         },
146 #endif /* HAVE_FLOW_SPEC_IPV6 */
147         [HASH_RXQ_ETH] = {
148                 .hash_fields = 0,
149                 .dpdk_rss_hf = 0,
150                 .flow_priority = 2,
151                 .flow_spec.eth = {
152                         .type = IBV_EXP_FLOW_SPEC_ETH,
153                         .size = sizeof(hash_rxq_init[0].flow_spec.eth),
154                 },
155                 .underlayer = NULL,
156         },
157 };
158
159 /* Number of entries in hash_rxq_init[]. */
160 const unsigned int hash_rxq_init_n = RTE_DIM(hash_rxq_init);
161
162 /* Initialization data for hash RX queue indirection tables. */
163 static const struct ind_table_init ind_table_init[] = {
164         {
165                 .max_size = -1u, /* Superseded by HW limitations. */
166                 .hash_types =
167                         1 << HASH_RXQ_TCPV4 |
168                         1 << HASH_RXQ_UDPV4 |
169                         1 << HASH_RXQ_IPV4 |
170 #ifdef HAVE_FLOW_SPEC_IPV6
171                         1 << HASH_RXQ_TCPV6 |
172                         1 << HASH_RXQ_UDPV6 |
173                         1 << HASH_RXQ_IPV6 |
174 #endif /* HAVE_FLOW_SPEC_IPV6 */
175                         0,
176 #ifdef HAVE_FLOW_SPEC_IPV6
177                 .hash_types_n = 6,
178 #else /* HAVE_FLOW_SPEC_IPV6 */
179                 .hash_types_n = 3,
180 #endif /* HAVE_FLOW_SPEC_IPV6 */
181         },
182         {
183                 .max_size = 1,
184                 .hash_types = 1 << HASH_RXQ_ETH,
185                 .hash_types_n = 1,
186         },
187 };
188
189 #define IND_TABLE_INIT_N RTE_DIM(ind_table_init)
190
191 /* Default RSS hash key also used for ConnectX-3. */
192 uint8_t rss_hash_default_key[] = {
193         0x2c, 0xc6, 0x81, 0xd1,
194         0x5b, 0xdb, 0xf4, 0xf7,
195         0xfc, 0xa2, 0x83, 0x19,
196         0xdb, 0x1a, 0x3e, 0x94,
197         0x6b, 0x9e, 0x38, 0xd9,
198         0x2c, 0x9c, 0x03, 0xd1,
199         0xad, 0x99, 0x44, 0xa7,
200         0xd9, 0x56, 0x3d, 0x59,
201         0x06, 0x3c, 0x25, 0xf3,
202         0xfc, 0x1f, 0xdc, 0x2a,
203 };
204
205 /* Length of the default RSS hash key. */
206 const size_t rss_hash_default_key_len = sizeof(rss_hash_default_key);
207
208 /**
209  * Populate flow steering rule for a given hash RX queue type using
210  * information from hash_rxq_init[]. Nothing is written to flow_attr when
211  * flow_attr_size is not large enough, but the required size is still returned.
212  *
213  * @param[in] hash_rxq
214  *   Pointer to hash RX queue.
215  * @param[out] flow_attr
216  *   Pointer to flow attribute structure to fill. Note that the allocated
217  *   area must be larger and large enough to hold all flow specifications.
218  * @param flow_attr_size
219  *   Entire size of flow_attr and trailing room for flow specifications.
220  *
221  * @return
222  *   Total size of the flow attribute buffer. No errors are defined.
223  */
224 size_t
225 hash_rxq_flow_attr(const struct hash_rxq *hash_rxq,
226                    struct ibv_exp_flow_attr *flow_attr,
227                    size_t flow_attr_size)
228 {
229         size_t offset = sizeof(*flow_attr);
230         enum hash_rxq_type type = hash_rxq->type;
231         const struct hash_rxq_init *init = &hash_rxq_init[type];
232
233         assert(hash_rxq->priv != NULL);
234         assert((size_t)type < RTE_DIM(hash_rxq_init));
235         do {
236                 offset += init->flow_spec.hdr.size;
237                 init = init->underlayer;
238         } while (init != NULL);
239         if (offset > flow_attr_size)
240                 return offset;
241         flow_attr_size = offset;
242         init = &hash_rxq_init[type];
243         *flow_attr = (struct ibv_exp_flow_attr){
244                 .type = IBV_EXP_FLOW_ATTR_NORMAL,
245                 .priority = init->flow_priority,
246                 .num_of_specs = 0,
247                 .port = hash_rxq->priv->port,
248                 .flags = 0,
249         };
250         do {
251                 offset -= init->flow_spec.hdr.size;
252                 memcpy((void *)((uintptr_t)flow_attr + offset),
253                        &init->flow_spec,
254                        init->flow_spec.hdr.size);
255                 ++flow_attr->num_of_specs;
256                 init = init->underlayer;
257         } while (init != NULL);
258         return flow_attr_size;
259 }
260
261 /**
262  * Convert hash type position in indirection table initializer to
263  * hash RX queue type.
264  *
265  * @param table
266  *   Indirection table initializer.
267  * @param pos
268  *   Hash type position.
269  *
270  * @return
271  *   Hash RX queue type.
272  */
273 static enum hash_rxq_type
274 hash_rxq_type_from_pos(const struct ind_table_init *table, unsigned int pos)
275 {
276         enum hash_rxq_type type = 0;
277
278         assert(pos < table->hash_types_n);
279         do {
280                 if ((table->hash_types & (1 << type)) && (pos-- == 0))
281                         break;
282                 ++type;
283         } while (1);
284         return type;
285 }
286
287 /**
288  * Filter out disabled hash RX queue types from ind_table_init[].
289  *
290  * @param priv
291  *   Pointer to private structure.
292  * @param[out] table
293  *   Output table.
294  *
295  * @return
296  *   Number of table entries.
297  */
298 static unsigned int
299 priv_make_ind_table_init(struct priv *priv,
300                          struct ind_table_init (*table)[IND_TABLE_INIT_N])
301 {
302         uint64_t rss_hf;
303         unsigned int i;
304         unsigned int j;
305         unsigned int table_n = 0;
306         /* Mandatory to receive frames not handled by normal hash RX queues. */
307         unsigned int hash_types_sup = 1 << HASH_RXQ_ETH;
308
309         rss_hf = priv->dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
310         /* Process other protocols only if more than one queue. */
311         if (priv->rxqs_n > 1)
312                 for (i = 0; (i != hash_rxq_init_n); ++i)
313                         if (rss_hf & hash_rxq_init[i].dpdk_rss_hf)
314                                 hash_types_sup |= (1 << i);
315
316         /* Filter out entries whose protocols are not in the set. */
317         for (i = 0, j = 0; (i != IND_TABLE_INIT_N); ++i) {
318                 unsigned int nb;
319                 unsigned int h;
320
321                 /* j is increased only if the table has valid protocols. */
322                 assert(j <= i);
323                 (*table)[j] = ind_table_init[i];
324                 (*table)[j].hash_types &= hash_types_sup;
325                 for (h = 0, nb = 0; (h != hash_rxq_init_n); ++h)
326                         if (((*table)[j].hash_types >> h) & 0x1)
327                                 ++nb;
328                 (*table)[i].hash_types_n = nb;
329                 if (nb) {
330                         ++table_n;
331                         ++j;
332                 }
333         }
334         return table_n;
335 }
336
337 /**
338  * Initialize hash RX queues and indirection table.
339  *
340  * @param priv
341  *   Pointer to private structure.
342  *
343  * @return
344  *   0 on success, errno value on failure.
345  */
346 int
347 priv_create_hash_rxqs(struct priv *priv)
348 {
349         struct ibv_exp_wq *wqs[priv->reta_idx_n];
350         struct ind_table_init ind_table_init[IND_TABLE_INIT_N];
351         unsigned int ind_tables_n =
352                 priv_make_ind_table_init(priv, &ind_table_init);
353         unsigned int hash_rxqs_n = 0;
354         struct hash_rxq (*hash_rxqs)[] = NULL;
355         struct ibv_exp_rwq_ind_table *(*ind_tables)[] = NULL;
356         unsigned int i;
357         unsigned int j;
358         unsigned int k;
359         int err = 0;
360
361         assert(priv->ind_tables == NULL);
362         assert(priv->ind_tables_n == 0);
363         assert(priv->hash_rxqs == NULL);
364         assert(priv->hash_rxqs_n == 0);
365         assert(priv->pd != NULL);
366         assert(priv->ctx != NULL);
367         if (priv->rxqs_n == 0)
368                 return EINVAL;
369         assert(priv->rxqs != NULL);
370         if (ind_tables_n == 0) {
371                 ERROR("all hash RX queue types have been filtered out,"
372                       " indirection table cannot be created");
373                 return EINVAL;
374         }
375         if (priv->rxqs_n & (priv->rxqs_n - 1)) {
376                 INFO("%u RX queues are configured, consider rounding this"
377                      " number to the next power of two for better balancing",
378                      priv->rxqs_n);
379                 DEBUG("indirection table extended to assume %u WQs",
380                       priv->reta_idx_n);
381         }
382         for (i = 0; (i != priv->reta_idx_n); ++i)
383                 wqs[i] = (*priv->rxqs)[(*priv->reta_idx)[i]]->wq;
384         /* Get number of hash RX queues to configure. */
385         for (i = 0, hash_rxqs_n = 0; (i != ind_tables_n); ++i)
386                 hash_rxqs_n += ind_table_init[i].hash_types_n;
387         DEBUG("allocating %u hash RX queues for %u WQs, %u indirection tables",
388               hash_rxqs_n, priv->rxqs_n, ind_tables_n);
389         /* Create indirection tables. */
390         ind_tables = rte_calloc(__func__, ind_tables_n,
391                                 sizeof((*ind_tables)[0]), 0);
392         if (ind_tables == NULL) {
393                 err = ENOMEM;
394                 ERROR("cannot allocate indirection tables container: %s",
395                       strerror(err));
396                 goto error;
397         }
398         for (i = 0; (i != ind_tables_n); ++i) {
399                 struct ibv_exp_rwq_ind_table_init_attr ind_init_attr = {
400                         .pd = priv->pd,
401                         .log_ind_tbl_size = 0, /* Set below. */
402                         .ind_tbl = wqs,
403                         .comp_mask = 0,
404                 };
405                 unsigned int ind_tbl_size = ind_table_init[i].max_size;
406                 struct ibv_exp_rwq_ind_table *ind_table;
407
408                 if (priv->reta_idx_n < ind_tbl_size)
409                         ind_tbl_size = priv->reta_idx_n;
410                 ind_init_attr.log_ind_tbl_size = log2above(ind_tbl_size);
411                 errno = 0;
412                 ind_table = ibv_exp_create_rwq_ind_table(priv->ctx,
413                                                          &ind_init_attr);
414                 if (ind_table != NULL) {
415                         (*ind_tables)[i] = ind_table;
416                         continue;
417                 }
418                 /* Not clear whether errno is set. */
419                 err = (errno ? errno : EINVAL);
420                 ERROR("RX indirection table creation failed with error %d: %s",
421                       err, strerror(err));
422                 goto error;
423         }
424         /* Allocate array that holds hash RX queues and related data. */
425         hash_rxqs = rte_calloc(__func__, hash_rxqs_n,
426                                sizeof((*hash_rxqs)[0]), 0);
427         if (hash_rxqs == NULL) {
428                 err = ENOMEM;
429                 ERROR("cannot allocate hash RX queues container: %s",
430                       strerror(err));
431                 goto error;
432         }
433         for (i = 0, j = 0, k = 0;
434              ((i != hash_rxqs_n) && (j != ind_tables_n));
435              ++i) {
436                 struct hash_rxq *hash_rxq = &(*hash_rxqs)[i];
437                 enum hash_rxq_type type =
438                         hash_rxq_type_from_pos(&ind_table_init[j], k);
439                 struct rte_eth_rss_conf *priv_rss_conf =
440                         (*priv->rss_conf)[type];
441                 struct ibv_exp_rx_hash_conf hash_conf = {
442                         .rx_hash_function = IBV_EXP_RX_HASH_FUNC_TOEPLITZ,
443                         .rx_hash_key_len = (priv_rss_conf ?
444                                             priv_rss_conf->rss_key_len :
445                                             rss_hash_default_key_len),
446                         .rx_hash_key = (priv_rss_conf ?
447                                         priv_rss_conf->rss_key :
448                                         rss_hash_default_key),
449                         .rx_hash_fields_mask = hash_rxq_init[type].hash_fields,
450                         .rwq_ind_tbl = (*ind_tables)[j],
451                 };
452                 struct ibv_exp_qp_init_attr qp_init_attr = {
453                         .max_inl_recv = 0, /* Currently not supported. */
454                         .qp_type = IBV_QPT_RAW_PACKET,
455                         .comp_mask = (IBV_EXP_QP_INIT_ATTR_PD |
456                                       IBV_EXP_QP_INIT_ATTR_RX_HASH),
457                         .pd = priv->pd,
458                         .rx_hash_conf = &hash_conf,
459                         .port_num = priv->port,
460                 };
461
462                 DEBUG("using indirection table %u for hash RX queue %u type %d",
463                       j, i, type);
464                 *hash_rxq = (struct hash_rxq){
465                         .priv = priv,
466                         .qp = ibv_exp_create_qp(priv->ctx, &qp_init_attr),
467                         .type = type,
468                 };
469                 if (hash_rxq->qp == NULL) {
470                         err = (errno ? errno : EINVAL);
471                         ERROR("Hash RX QP creation failure: %s",
472                               strerror(err));
473                         goto error;
474                 }
475                 if (++k < ind_table_init[j].hash_types_n)
476                         continue;
477                 /* Switch to the next indirection table and reset hash RX
478                  * queue type array index. */
479                 ++j;
480                 k = 0;
481         }
482         priv->ind_tables = ind_tables;
483         priv->ind_tables_n = ind_tables_n;
484         priv->hash_rxqs = hash_rxqs;
485         priv->hash_rxqs_n = hash_rxqs_n;
486         assert(err == 0);
487         return 0;
488 error:
489         if (hash_rxqs != NULL) {
490                 for (i = 0; (i != hash_rxqs_n); ++i) {
491                         struct ibv_qp *qp = (*hash_rxqs)[i].qp;
492
493                         if (qp == NULL)
494                                 continue;
495                         claim_zero(ibv_destroy_qp(qp));
496                 }
497                 rte_free(hash_rxqs);
498         }
499         if (ind_tables != NULL) {
500                 for (j = 0; (j != ind_tables_n); ++j) {
501                         struct ibv_exp_rwq_ind_table *ind_table =
502                                 (*ind_tables)[j];
503
504                         if (ind_table == NULL)
505                                 continue;
506                         claim_zero(ibv_exp_destroy_rwq_ind_table(ind_table));
507                 }
508                 rte_free(ind_tables);
509         }
510         return err;
511 }
512
513 /**
514  * Clean up hash RX queues and indirection table.
515  *
516  * @param priv
517  *   Pointer to private structure.
518  */
519 void
520 priv_destroy_hash_rxqs(struct priv *priv)
521 {
522         unsigned int i;
523
524         DEBUG("destroying %u hash RX queues", priv->hash_rxqs_n);
525         if (priv->hash_rxqs_n == 0) {
526                 assert(priv->hash_rxqs == NULL);
527                 assert(priv->ind_tables == NULL);
528                 return;
529         }
530         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
531                 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];
532                 unsigned int j, k;
533
534                 assert(hash_rxq->priv == priv);
535                 assert(hash_rxq->qp != NULL);
536                 /* Also check that there are no remaining flows. */
537                 assert(hash_rxq->allmulti_flow == NULL);
538                 assert(hash_rxq->promisc_flow == NULL);
539                 for (j = 0; (j != RTE_DIM(hash_rxq->mac_flow)); ++j)
540                         for (k = 0; (k != RTE_DIM(hash_rxq->mac_flow[j])); ++k)
541                                 assert(hash_rxq->mac_flow[j][k] == NULL);
542                 claim_zero(ibv_destroy_qp(hash_rxq->qp));
543         }
544         priv->hash_rxqs_n = 0;
545         rte_free(priv->hash_rxqs);
546         priv->hash_rxqs = NULL;
547         for (i = 0; (i != priv->ind_tables_n); ++i) {
548                 struct ibv_exp_rwq_ind_table *ind_table =
549                         (*priv->ind_tables)[i];
550
551                 assert(ind_table != NULL);
552                 claim_zero(ibv_exp_destroy_rwq_ind_table(ind_table));
553         }
554         priv->ind_tables_n = 0;
555         rte_free(priv->ind_tables);
556         priv->ind_tables = NULL;
557 }
558
559 /**
560  * Check whether a given flow type is allowed.
561  *
562  * @param priv
563  *   Pointer to private structure.
564  * @param type
565  *   Flow type to check.
566  *
567  * @return
568  *   Nonzero if the given flow type is allowed.
569  */
570 int
571 priv_allow_flow_type(struct priv *priv, enum hash_rxq_flow_type type)
572 {
573         /* Only FLOW_TYPE_PROMISC is allowed when promiscuous mode
574          * has been requested. */
575         if (priv->promisc_req)
576                 return type == HASH_RXQ_FLOW_TYPE_PROMISC;
577         switch (type) {
578         case HASH_RXQ_FLOW_TYPE_PROMISC:
579                 return !!priv->promisc_req;
580         case HASH_RXQ_FLOW_TYPE_ALLMULTI:
581                 return !!priv->allmulti_req;
582         case HASH_RXQ_FLOW_TYPE_MAC:
583                 return 1;
584         }
585         return 0;
586 }
587
588 /**
589  * Allocate RX queue elements with scattered packets support.
590  *
591  * @param rxq
592  *   Pointer to RX queue structure.
593  * @param elts_n
594  *   Number of elements to allocate.
595  * @param[in] pool
596  *   If not NULL, fetch buffers from this array instead of allocating them
597  *   with rte_pktmbuf_alloc().
598  *
599  * @return
600  *   0 on success, errno value on failure.
601  */
602 static int
603 rxq_alloc_elts_sp(struct rxq *rxq, unsigned int elts_n,
604                   struct rte_mbuf **pool)
605 {
606         unsigned int i;
607         struct rxq_elt_sp (*elts)[elts_n] =
608                 rte_calloc_socket("RXQ elements", 1, sizeof(*elts), 0,
609                                   rxq->socket);
610         int ret = 0;
611
612         if (elts == NULL) {
613                 ERROR("%p: can't allocate packets array", (void *)rxq);
614                 ret = ENOMEM;
615                 goto error;
616         }
617         /* For each WR (packet). */
618         for (i = 0; (i != elts_n); ++i) {
619                 unsigned int j;
620                 struct rxq_elt_sp *elt = &(*elts)[i];
621                 struct ibv_sge (*sges)[RTE_DIM(elt->sges)] = &elt->sges;
622
623                 /* These two arrays must have the same size. */
624                 assert(RTE_DIM(elt->sges) == RTE_DIM(elt->bufs));
625                 /* For each SGE (segment). */
626                 for (j = 0; (j != RTE_DIM(elt->bufs)); ++j) {
627                         struct ibv_sge *sge = &(*sges)[j];
628                         struct rte_mbuf *buf;
629
630                         if (pool != NULL) {
631                                 buf = *(pool++);
632                                 assert(buf != NULL);
633                                 rte_pktmbuf_reset(buf);
634                         } else
635                                 buf = rte_pktmbuf_alloc(rxq->mp);
636                         if (buf == NULL) {
637                                 assert(pool == NULL);
638                                 ERROR("%p: empty mbuf pool", (void *)rxq);
639                                 ret = ENOMEM;
640                                 goto error;
641                         }
642                         elt->bufs[j] = buf;
643                         /* Headroom is reserved by rte_pktmbuf_alloc(). */
644                         assert(DATA_OFF(buf) == RTE_PKTMBUF_HEADROOM);
645                         /* Buffer is supposed to be empty. */
646                         assert(rte_pktmbuf_data_len(buf) == 0);
647                         assert(rte_pktmbuf_pkt_len(buf) == 0);
648                         /* sge->addr must be able to store a pointer. */
649                         assert(sizeof(sge->addr) >= sizeof(uintptr_t));
650                         if (j == 0) {
651                                 /* The first SGE keeps its headroom. */
652                                 sge->addr = rte_pktmbuf_mtod(buf, uintptr_t);
653                                 sge->length = (buf->buf_len -
654                                                RTE_PKTMBUF_HEADROOM);
655                         } else {
656                                 /* Subsequent SGEs lose theirs. */
657                                 assert(DATA_OFF(buf) == RTE_PKTMBUF_HEADROOM);
658                                 SET_DATA_OFF(buf, 0);
659                                 sge->addr = (uintptr_t)buf->buf_addr;
660                                 sge->length = buf->buf_len;
661                         }
662                         sge->lkey = rxq->mr->lkey;
663                         /* Redundant check for tailroom. */
664                         assert(sge->length == rte_pktmbuf_tailroom(buf));
665                 }
666         }
667         DEBUG("%p: allocated and configured %u WRs (%zu segments)",
668               (void *)rxq, elts_n, (elts_n * RTE_DIM((*elts)[0].sges)));
669         rxq->elts_n = elts_n;
670         rxq->elts_head = 0;
671         rxq->elts.sp = elts;
672         assert(ret == 0);
673         return 0;
674 error:
675         if (elts != NULL) {
676                 assert(pool == NULL);
677                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
678                         unsigned int j;
679                         struct rxq_elt_sp *elt = &(*elts)[i];
680
681                         for (j = 0; (j != RTE_DIM(elt->bufs)); ++j) {
682                                 struct rte_mbuf *buf = elt->bufs[j];
683
684                                 if (buf != NULL)
685                                         rte_pktmbuf_free_seg(buf);
686                         }
687                 }
688                 rte_free(elts);
689         }
690         DEBUG("%p: failed, freed everything", (void *)rxq);
691         assert(ret > 0);
692         return ret;
693 }
694
695 /**
696  * Free RX queue elements with scattered packets support.
697  *
698  * @param rxq
699  *   Pointer to RX queue structure.
700  */
701 static void
702 rxq_free_elts_sp(struct rxq *rxq)
703 {
704         unsigned int i;
705         unsigned int elts_n = rxq->elts_n;
706         struct rxq_elt_sp (*elts)[elts_n] = rxq->elts.sp;
707
708         DEBUG("%p: freeing WRs", (void *)rxq);
709         rxq->elts_n = 0;
710         rxq->elts.sp = NULL;
711         if (elts == NULL)
712                 return;
713         for (i = 0; (i != RTE_DIM(*elts)); ++i) {
714                 unsigned int j;
715                 struct rxq_elt_sp *elt = &(*elts)[i];
716
717                 for (j = 0; (j != RTE_DIM(elt->bufs)); ++j) {
718                         struct rte_mbuf *buf = elt->bufs[j];
719
720                         if (buf != NULL)
721                                 rte_pktmbuf_free_seg(buf);
722                 }
723         }
724         rte_free(elts);
725 }
726
727 /**
728  * Allocate RX queue elements.
729  *
730  * @param rxq
731  *   Pointer to RX queue structure.
732  * @param elts_n
733  *   Number of elements to allocate.
734  * @param[in] pool
735  *   If not NULL, fetch buffers from this array instead of allocating them
736  *   with rte_pktmbuf_alloc().
737  *
738  * @return
739  *   0 on success, errno value on failure.
740  */
741 static int
742 rxq_alloc_elts(struct rxq *rxq, unsigned int elts_n, struct rte_mbuf **pool)
743 {
744         unsigned int i;
745         struct rxq_elt (*elts)[elts_n] =
746                 rte_calloc_socket("RXQ elements", 1, sizeof(*elts), 0,
747                                   rxq->socket);
748         int ret = 0;
749
750         if (elts == NULL) {
751                 ERROR("%p: can't allocate packets array", (void *)rxq);
752                 ret = ENOMEM;
753                 goto error;
754         }
755         /* For each WR (packet). */
756         for (i = 0; (i != elts_n); ++i) {
757                 struct rxq_elt *elt = &(*elts)[i];
758                 struct ibv_sge *sge = &(*elts)[i].sge;
759                 struct rte_mbuf *buf;
760
761                 if (pool != NULL) {
762                         buf = *(pool++);
763                         assert(buf != NULL);
764                         rte_pktmbuf_reset(buf);
765                 } else
766                         buf = rte_pktmbuf_alloc(rxq->mp);
767                 if (buf == NULL) {
768                         assert(pool == NULL);
769                         ERROR("%p: empty mbuf pool", (void *)rxq);
770                         ret = ENOMEM;
771                         goto error;
772                 }
773                 elt->buf = buf;
774                 /* Headroom is reserved by rte_pktmbuf_alloc(). */
775                 assert(DATA_OFF(buf) == RTE_PKTMBUF_HEADROOM);
776                 /* Buffer is supposed to be empty. */
777                 assert(rte_pktmbuf_data_len(buf) == 0);
778                 assert(rte_pktmbuf_pkt_len(buf) == 0);
779                 /* sge->addr must be able to store a pointer. */
780                 assert(sizeof(sge->addr) >= sizeof(uintptr_t));
781                 /* SGE keeps its headroom. */
782                 sge->addr = (uintptr_t)
783                         ((uint8_t *)buf->buf_addr + RTE_PKTMBUF_HEADROOM);
784                 sge->length = (buf->buf_len - RTE_PKTMBUF_HEADROOM);
785                 sge->lkey = rxq->mr->lkey;
786                 /* Redundant check for tailroom. */
787                 assert(sge->length == rte_pktmbuf_tailroom(buf));
788         }
789         DEBUG("%p: allocated and configured %u single-segment WRs",
790               (void *)rxq, elts_n);
791         rxq->elts_n = elts_n;
792         rxq->elts_head = 0;
793         rxq->elts.no_sp = elts;
794         assert(ret == 0);
795         return 0;
796 error:
797         if (elts != NULL) {
798                 assert(pool == NULL);
799                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
800                         struct rxq_elt *elt = &(*elts)[i];
801                         struct rte_mbuf *buf = elt->buf;
802
803                         if (buf != NULL)
804                                 rte_pktmbuf_free_seg(buf);
805                 }
806                 rte_free(elts);
807         }
808         DEBUG("%p: failed, freed everything", (void *)rxq);
809         assert(ret > 0);
810         return ret;
811 }
812
813 /**
814  * Free RX queue elements.
815  *
816  * @param rxq
817  *   Pointer to RX queue structure.
818  */
819 static void
820 rxq_free_elts(struct rxq *rxq)
821 {
822         unsigned int i;
823         unsigned int elts_n = rxq->elts_n;
824         struct rxq_elt (*elts)[elts_n] = rxq->elts.no_sp;
825
826         DEBUG("%p: freeing WRs", (void *)rxq);
827         rxq->elts_n = 0;
828         rxq->elts.no_sp = NULL;
829         if (elts == NULL)
830                 return;
831         for (i = 0; (i != RTE_DIM(*elts)); ++i) {
832                 struct rxq_elt *elt = &(*elts)[i];
833                 struct rte_mbuf *buf = elt->buf;
834
835                 if (buf != NULL)
836                         rte_pktmbuf_free_seg(buf);
837         }
838         rte_free(elts);
839 }
840
841 /**
842  * Clean up a RX queue.
843  *
844  * Destroy objects, free allocated memory and reset the structure for reuse.
845  *
846  * @param rxq
847  *   Pointer to RX queue structure.
848  */
849 void
850 rxq_cleanup(struct rxq *rxq)
851 {
852         struct ibv_exp_release_intf_params params;
853
854         DEBUG("cleaning up %p", (void *)rxq);
855         if (rxq->sp)
856                 rxq_free_elts_sp(rxq);
857         else
858                 rxq_free_elts(rxq);
859         if (rxq->if_wq != NULL) {
860                 assert(rxq->priv != NULL);
861                 assert(rxq->priv->ctx != NULL);
862                 assert(rxq->wq != NULL);
863                 params = (struct ibv_exp_release_intf_params){
864                         .comp_mask = 0,
865                 };
866                 claim_zero(ibv_exp_release_intf(rxq->priv->ctx,
867                                                 rxq->if_wq,
868                                                 &params));
869         }
870         if (rxq->if_cq != NULL) {
871                 assert(rxq->priv != NULL);
872                 assert(rxq->priv->ctx != NULL);
873                 assert(rxq->cq != NULL);
874                 params = (struct ibv_exp_release_intf_params){
875                         .comp_mask = 0,
876                 };
877                 claim_zero(ibv_exp_release_intf(rxq->priv->ctx,
878                                                 rxq->if_cq,
879                                                 &params));
880         }
881         if (rxq->wq != NULL)
882                 claim_zero(ibv_exp_destroy_wq(rxq->wq));
883         if (rxq->cq != NULL)
884                 claim_zero(ibv_destroy_cq(rxq->cq));
885         if (rxq->rd != NULL) {
886                 struct ibv_exp_destroy_res_domain_attr attr = {
887                         .comp_mask = 0,
888                 };
889
890                 assert(rxq->priv != NULL);
891                 assert(rxq->priv->ctx != NULL);
892                 claim_zero(ibv_exp_destroy_res_domain(rxq->priv->ctx,
893                                                       rxq->rd,
894                                                       &attr));
895         }
896         if (rxq->mr != NULL)
897                 claim_zero(ibv_dereg_mr(rxq->mr));
898         memset(rxq, 0, sizeof(*rxq));
899 }
900
901 /**
902  * Reconfigure a RX queue with new parameters.
903  *
904  * rxq_rehash() does not allocate mbufs, which, if not done from the right
905  * thread (such as a control thread), may corrupt the pool.
906  * In case of failure, the queue is left untouched.
907  *
908  * @param dev
909  *   Pointer to Ethernet device structure.
910  * @param rxq
911  *   RX queue pointer.
912  *
913  * @return
914  *   0 on success, errno value on failure.
915  */
916 int
917 rxq_rehash(struct rte_eth_dev *dev, struct rxq *rxq)
918 {
919         struct priv *priv = rxq->priv;
920         struct rxq tmpl = *rxq;
921         unsigned int mbuf_n;
922         unsigned int desc_n;
923         struct rte_mbuf **pool;
924         unsigned int i, k;
925         struct ibv_exp_wq_attr mod;
926         int err;
927
928         DEBUG("%p: rehashing queue %p", (void *)dev, (void *)rxq);
929         /* Number of descriptors and mbufs currently allocated. */
930         desc_n = (tmpl.elts_n * (tmpl.sp ? MLX5_PMD_SGE_WR_N : 1));
931         mbuf_n = desc_n;
932         /* Toggle RX checksum offload if hardware supports it. */
933         if (priv->hw_csum) {
934                 tmpl.csum = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
935                 rxq->csum = tmpl.csum;
936         }
937         if (priv->hw_csum_l2tun) {
938                 tmpl.csum_l2tun = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
939                 rxq->csum_l2tun = tmpl.csum_l2tun;
940         }
941         /* Enable scattered packets support for this queue if necessary. */
942         if ((dev->data->dev_conf.rxmode.jumbo_frame) &&
943             (dev->data->dev_conf.rxmode.max_rx_pkt_len >
944              (tmpl.mb_len - RTE_PKTMBUF_HEADROOM))) {
945                 tmpl.sp = 1;
946                 desc_n /= MLX5_PMD_SGE_WR_N;
947         } else
948                 tmpl.sp = 0;
949         DEBUG("%p: %s scattered packets support (%u WRs)",
950               (void *)dev, (tmpl.sp ? "enabling" : "disabling"), desc_n);
951         /* If scatter mode is the same as before, nothing to do. */
952         if (tmpl.sp == rxq->sp) {
953                 DEBUG("%p: nothing to do", (void *)dev);
954                 return 0;
955         }
956         /* From now on, any failure will render the queue unusable.
957          * Reinitialize WQ. */
958         mod = (struct ibv_exp_wq_attr){
959                 .attr_mask = IBV_EXP_WQ_ATTR_STATE,
960                 .wq_state = IBV_EXP_WQS_RESET,
961         };
962         err = ibv_exp_modify_wq(tmpl.wq, &mod);
963         if (err) {
964                 ERROR("%p: cannot reset WQ: %s", (void *)dev, strerror(err));
965                 assert(err > 0);
966                 return err;
967         }
968         /* Allocate pool. */
969         pool = rte_malloc(__func__, (mbuf_n * sizeof(*pool)), 0);
970         if (pool == NULL) {
971                 ERROR("%p: cannot allocate memory", (void *)dev);
972                 return ENOBUFS;
973         }
974         /* Snatch mbufs from original queue. */
975         k = 0;
976         if (rxq->sp) {
977                 struct rxq_elt_sp (*elts)[rxq->elts_n] = rxq->elts.sp;
978
979                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
980                         struct rxq_elt_sp *elt = &(*elts)[i];
981                         unsigned int j;
982
983                         for (j = 0; (j != RTE_DIM(elt->bufs)); ++j) {
984                                 assert(elt->bufs[j] != NULL);
985                                 pool[k++] = elt->bufs[j];
986                         }
987                 }
988         } else {
989                 struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts.no_sp;
990
991                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
992                         struct rxq_elt *elt = &(*elts)[i];
993                         struct rte_mbuf *buf = elt->buf;
994
995                         pool[k++] = buf;
996                 }
997         }
998         assert(k == mbuf_n);
999         tmpl.elts_n = 0;
1000         tmpl.elts.sp = NULL;
1001         assert((void *)&tmpl.elts.sp == (void *)&tmpl.elts.no_sp);
1002         err = ((tmpl.sp) ?
1003                rxq_alloc_elts_sp(&tmpl, desc_n, pool) :
1004                rxq_alloc_elts(&tmpl, desc_n, pool));
1005         if (err) {
1006                 ERROR("%p: cannot reallocate WRs, aborting", (void *)dev);
1007                 rte_free(pool);
1008                 assert(err > 0);
1009                 return err;
1010         }
1011         assert(tmpl.elts_n == desc_n);
1012         assert(tmpl.elts.sp != NULL);
1013         rte_free(pool);
1014         /* Clean up original data. */
1015         rxq->elts_n = 0;
1016         rte_free(rxq->elts.sp);
1017         rxq->elts.sp = NULL;
1018         /* Change queue state to ready. */
1019         mod = (struct ibv_exp_wq_attr){
1020                 .attr_mask = IBV_EXP_WQ_ATTR_STATE,
1021                 .wq_state = IBV_EXP_WQS_RDY,
1022         };
1023         err = ibv_exp_modify_wq(tmpl.wq, &mod);
1024         if (err) {
1025                 ERROR("%p: WQ state to IBV_EXP_WQS_RDY failed: %s",
1026                       (void *)dev, strerror(err));
1027                 goto error;
1028         }
1029         /* Post SGEs. */
1030         assert(tmpl.if_wq != NULL);
1031         if (tmpl.sp) {
1032                 struct rxq_elt_sp (*elts)[tmpl.elts_n] = tmpl.elts.sp;
1033
1034                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
1035                         err = tmpl.if_wq->recv_sg_list
1036                                 (tmpl.wq,
1037                                  (*elts)[i].sges,
1038                                  RTE_DIM((*elts)[i].sges));
1039                         if (err)
1040                                 break;
1041                 }
1042         } else {
1043                 struct rxq_elt (*elts)[tmpl.elts_n] = tmpl.elts.no_sp;
1044
1045                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
1046                         err = tmpl.if_wq->recv_burst(
1047                                 tmpl.wq,
1048                                 &(*elts)[i].sge,
1049                                 1);
1050                         if (err)
1051                                 break;
1052                 }
1053         }
1054         if (err) {
1055                 ERROR("%p: failed to post SGEs with error %d",
1056                       (void *)dev, err);
1057                 /* Set err because it does not contain a valid errno value. */
1058                 err = EIO;
1059                 goto error;
1060         }
1061 error:
1062         *rxq = tmpl;
1063         assert(err >= 0);
1064         return err;
1065 }
1066
1067 /**
1068  * Configure a RX queue.
1069  *
1070  * @param dev
1071  *   Pointer to Ethernet device structure.
1072  * @param rxq
1073  *   Pointer to RX queue structure.
1074  * @param desc
1075  *   Number of descriptors to configure in queue.
1076  * @param socket
1077  *   NUMA socket on which memory must be allocated.
1078  * @param[in] conf
1079  *   Thresholds parameters.
1080  * @param mp
1081  *   Memory pool for buffer allocations.
1082  *
1083  * @return
1084  *   0 on success, errno value on failure.
1085  */
1086 int
1087 rxq_setup(struct rte_eth_dev *dev, struct rxq *rxq, uint16_t desc,
1088           unsigned int socket, const struct rte_eth_rxconf *conf,
1089           struct rte_mempool *mp)
1090 {
1091         struct priv *priv = dev->data->dev_private;
1092         struct rxq tmpl = {
1093                 .priv = priv,
1094                 .mp = mp,
1095                 .socket = socket
1096         };
1097         struct ibv_exp_wq_attr mod;
1098         union {
1099                 struct ibv_exp_query_intf_params params;
1100                 struct ibv_exp_cq_init_attr cq;
1101                 struct ibv_exp_res_domain_init_attr rd;
1102                 struct ibv_exp_wq_init_attr wq;
1103         } attr;
1104         enum ibv_exp_query_intf_status status;
1105         struct rte_mbuf *buf;
1106         int ret = 0;
1107         unsigned int i;
1108         unsigned int cq_size = desc;
1109
1110         (void)conf; /* Thresholds configuration (ignored). */
1111         if ((desc == 0) || (desc % MLX5_PMD_SGE_WR_N)) {
1112                 ERROR("%p: invalid number of RX descriptors (must be a"
1113                       " multiple of %d)", (void *)dev, MLX5_PMD_SGE_WR_N);
1114                 return EINVAL;
1115         }
1116         /* Get mbuf length. */
1117         buf = rte_pktmbuf_alloc(mp);
1118         if (buf == NULL) {
1119                 ERROR("%p: unable to allocate mbuf", (void *)dev);
1120                 return ENOMEM;
1121         }
1122         tmpl.mb_len = buf->buf_len;
1123         assert((rte_pktmbuf_headroom(buf) +
1124                 rte_pktmbuf_tailroom(buf)) == tmpl.mb_len);
1125         assert(rte_pktmbuf_headroom(buf) == RTE_PKTMBUF_HEADROOM);
1126         rte_pktmbuf_free(buf);
1127         /* Toggle RX checksum offload if hardware supports it. */
1128         if (priv->hw_csum)
1129                 tmpl.csum = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
1130         if (priv->hw_csum_l2tun)
1131                 tmpl.csum_l2tun = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
1132         /* Enable scattered packets support for this queue if necessary. */
1133         if ((dev->data->dev_conf.rxmode.jumbo_frame) &&
1134             (dev->data->dev_conf.rxmode.max_rx_pkt_len >
1135              (tmpl.mb_len - RTE_PKTMBUF_HEADROOM))) {
1136                 tmpl.sp = 1;
1137                 desc /= MLX5_PMD_SGE_WR_N;
1138         }
1139         DEBUG("%p: %s scattered packets support (%u WRs)",
1140               (void *)dev, (tmpl.sp ? "enabling" : "disabling"), desc);
1141         /* Use the entire RX mempool as the memory region. */
1142         tmpl.mr = ibv_reg_mr(priv->pd,
1143                              (void *)mp->elt_va_start,
1144                              (mp->elt_va_end - mp->elt_va_start),
1145                              (IBV_ACCESS_LOCAL_WRITE |
1146                               IBV_ACCESS_REMOTE_WRITE));
1147         if (tmpl.mr == NULL) {
1148                 ret = EINVAL;
1149                 ERROR("%p: MR creation failure: %s",
1150                       (void *)dev, strerror(ret));
1151                 goto error;
1152         }
1153         attr.rd = (struct ibv_exp_res_domain_init_attr){
1154                 .comp_mask = (IBV_EXP_RES_DOMAIN_THREAD_MODEL |
1155                               IBV_EXP_RES_DOMAIN_MSG_MODEL),
1156                 .thread_model = IBV_EXP_THREAD_SINGLE,
1157                 .msg_model = IBV_EXP_MSG_HIGH_BW,
1158         };
1159         tmpl.rd = ibv_exp_create_res_domain(priv->ctx, &attr.rd);
1160         if (tmpl.rd == NULL) {
1161                 ret = ENOMEM;
1162                 ERROR("%p: RD creation failure: %s",
1163                       (void *)dev, strerror(ret));
1164                 goto error;
1165         }
1166         attr.cq = (struct ibv_exp_cq_init_attr){
1167                 .comp_mask = IBV_EXP_CQ_INIT_ATTR_RES_DOMAIN,
1168                 .res_domain = tmpl.rd,
1169         };
1170         tmpl.cq = ibv_exp_create_cq(priv->ctx, cq_size, NULL, NULL, 0,
1171                                     &attr.cq);
1172         if (tmpl.cq == NULL) {
1173                 ret = ENOMEM;
1174                 ERROR("%p: CQ creation failure: %s",
1175                       (void *)dev, strerror(ret));
1176                 goto error;
1177         }
1178         DEBUG("priv->device_attr.max_qp_wr is %d",
1179               priv->device_attr.max_qp_wr);
1180         DEBUG("priv->device_attr.max_sge is %d",
1181               priv->device_attr.max_sge);
1182         attr.wq = (struct ibv_exp_wq_init_attr){
1183                 .wq_context = NULL, /* Could be useful in the future. */
1184                 .wq_type = IBV_EXP_WQT_RQ,
1185                 /* Max number of outstanding WRs. */
1186                 .max_recv_wr = ((priv->device_attr.max_qp_wr < (int)cq_size) ?
1187                                 priv->device_attr.max_qp_wr :
1188                                 (int)cq_size),
1189                 /* Max number of scatter/gather elements in a WR. */
1190                 .max_recv_sge = ((priv->device_attr.max_sge <
1191                                   MLX5_PMD_SGE_WR_N) ?
1192                                  priv->device_attr.max_sge :
1193                                  MLX5_PMD_SGE_WR_N),
1194                 .pd = priv->pd,
1195                 .cq = tmpl.cq,
1196                 .comp_mask = IBV_EXP_CREATE_WQ_RES_DOMAIN,
1197                 .res_domain = tmpl.rd,
1198         };
1199         tmpl.wq = ibv_exp_create_wq(priv->ctx, &attr.wq);
1200         if (tmpl.wq == NULL) {
1201                 ret = (errno ? errno : EINVAL);
1202                 ERROR("%p: WQ creation failure: %s",
1203                       (void *)dev, strerror(ret));
1204                 goto error;
1205         }
1206         if (tmpl.sp)
1207                 ret = rxq_alloc_elts_sp(&tmpl, desc, NULL);
1208         else
1209                 ret = rxq_alloc_elts(&tmpl, desc, NULL);
1210         if (ret) {
1211                 ERROR("%p: RXQ allocation failed: %s",
1212                       (void *)dev, strerror(ret));
1213                 goto error;
1214         }
1215         /* Save port ID. */
1216         tmpl.port_id = dev->data->port_id;
1217         DEBUG("%p: RTE port ID: %u", (void *)rxq, tmpl.port_id);
1218         attr.params = (struct ibv_exp_query_intf_params){
1219                 .intf_scope = IBV_EXP_INTF_GLOBAL,
1220                 .intf = IBV_EXP_INTF_CQ,
1221                 .obj = tmpl.cq,
1222         };
1223         tmpl.if_cq = ibv_exp_query_intf(priv->ctx, &attr.params, &status);
1224         if (tmpl.if_cq == NULL) {
1225                 ERROR("%p: CQ interface family query failed with status %d",
1226                       (void *)dev, status);
1227                 goto error;
1228         }
1229         attr.params = (struct ibv_exp_query_intf_params){
1230                 .intf_scope = IBV_EXP_INTF_GLOBAL,
1231                 .intf = IBV_EXP_INTF_WQ,
1232                 .obj = tmpl.wq,
1233         };
1234         tmpl.if_wq = ibv_exp_query_intf(priv->ctx, &attr.params, &status);
1235         if (tmpl.if_wq == NULL) {
1236                 ERROR("%p: WQ interface family query failed with status %d",
1237                       (void *)dev, status);
1238                 goto error;
1239         }
1240         /* Change queue state to ready. */
1241         mod = (struct ibv_exp_wq_attr){
1242                 .attr_mask = IBV_EXP_WQ_ATTR_STATE,
1243                 .wq_state = IBV_EXP_WQS_RDY,
1244         };
1245         ret = ibv_exp_modify_wq(tmpl.wq, &mod);
1246         if (ret) {
1247                 ERROR("%p: WQ state to IBV_EXP_WQS_RDY failed: %s",
1248                       (void *)dev, strerror(ret));
1249                 goto error;
1250         }
1251         /* Post SGEs. */
1252         if (tmpl.sp) {
1253                 struct rxq_elt_sp (*elts)[tmpl.elts_n] = tmpl.elts.sp;
1254
1255                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
1256                         ret = tmpl.if_wq->recv_sg_list
1257                                 (tmpl.wq,
1258                                  (*elts)[i].sges,
1259                                  RTE_DIM((*elts)[i].sges));
1260                         if (ret)
1261                                 break;
1262                 }
1263         } else {
1264                 struct rxq_elt (*elts)[tmpl.elts_n] = tmpl.elts.no_sp;
1265
1266                 for (i = 0; (i != RTE_DIM(*elts)); ++i) {
1267                         ret = tmpl.if_wq->recv_burst(
1268                                 tmpl.wq,
1269                                 &(*elts)[i].sge,
1270                                 1);
1271                         if (ret)
1272                                 break;
1273                 }
1274         }
1275         if (ret) {
1276                 ERROR("%p: failed to post SGEs with error %d",
1277                       (void *)dev, ret);
1278                 /* Set ret because it does not contain a valid errno value. */
1279                 ret = EIO;
1280                 goto error;
1281         }
1282         /* Clean up rxq in case we're reinitializing it. */
1283         DEBUG("%p: cleaning-up old rxq just in case", (void *)rxq);
1284         rxq_cleanup(rxq);
1285         *rxq = tmpl;
1286         DEBUG("%p: rxq updated with %p", (void *)rxq, (void *)&tmpl);
1287         assert(ret == 0);
1288         return 0;
1289 error:
1290         rxq_cleanup(&tmpl);
1291         assert(ret > 0);
1292         return ret;
1293 }
1294
1295 /**
1296  * DPDK callback to configure a RX queue.
1297  *
1298  * @param dev
1299  *   Pointer to Ethernet device structure.
1300  * @param idx
1301  *   RX queue index.
1302  * @param desc
1303  *   Number of descriptors to configure in queue.
1304  * @param socket
1305  *   NUMA socket on which memory must be allocated.
1306  * @param[in] conf
1307  *   Thresholds parameters.
1308  * @param mp
1309  *   Memory pool for buffer allocations.
1310  *
1311  * @return
1312  *   0 on success, negative errno value on failure.
1313  */
1314 int
1315 mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1316                     unsigned int socket, const struct rte_eth_rxconf *conf,
1317                     struct rte_mempool *mp)
1318 {
1319         struct priv *priv = dev->data->dev_private;
1320         struct rxq *rxq = (*priv->rxqs)[idx];
1321         int ret;
1322
1323         priv_lock(priv);
1324         DEBUG("%p: configuring queue %u for %u descriptors",
1325               (void *)dev, idx, desc);
1326         if (idx >= priv->rxqs_n) {
1327                 ERROR("%p: queue index out of range (%u >= %u)",
1328                       (void *)dev, idx, priv->rxqs_n);
1329                 priv_unlock(priv);
1330                 return -EOVERFLOW;
1331         }
1332         if (rxq != NULL) {
1333                 DEBUG("%p: reusing already allocated queue index %u (%p)",
1334                       (void *)dev, idx, (void *)rxq);
1335                 if (priv->started) {
1336                         priv_unlock(priv);
1337                         return -EEXIST;
1338                 }
1339                 (*priv->rxqs)[idx] = NULL;
1340                 rxq_cleanup(rxq);
1341         } else {
1342                 rxq = rte_calloc_socket("RXQ", 1, sizeof(*rxq), 0, socket);
1343                 if (rxq == NULL) {
1344                         ERROR("%p: unable to allocate queue index %u",
1345                               (void *)dev, idx);
1346                         priv_unlock(priv);
1347                         return -ENOMEM;
1348                 }
1349         }
1350         ret = rxq_setup(dev, rxq, desc, socket, conf, mp);
1351         if (ret)
1352                 rte_free(rxq);
1353         else {
1354                 rxq->stats.idx = idx;
1355                 DEBUG("%p: adding RX queue %p to list",
1356                       (void *)dev, (void *)rxq);
1357                 (*priv->rxqs)[idx] = rxq;
1358                 /* Update receive callback. */
1359                 if (rxq->sp)
1360                         dev->rx_pkt_burst = mlx5_rx_burst_sp;
1361                 else
1362                         dev->rx_pkt_burst = mlx5_rx_burst;
1363         }
1364         priv_unlock(priv);
1365         return -ret;
1366 }
1367
1368 /**
1369  * DPDK callback to release a RX queue.
1370  *
1371  * @param dpdk_rxq
1372  *   Generic RX queue pointer.
1373  */
1374 void
1375 mlx5_rx_queue_release(void *dpdk_rxq)
1376 {
1377         struct rxq *rxq = (struct rxq *)dpdk_rxq;
1378         struct priv *priv;
1379         unsigned int i;
1380
1381         if (rxq == NULL)
1382                 return;
1383         priv = rxq->priv;
1384         priv_lock(priv);
1385         for (i = 0; (i != priv->rxqs_n); ++i)
1386                 if ((*priv->rxqs)[i] == rxq) {
1387                         DEBUG("%p: removing RX queue %p from list",
1388                               (void *)priv->dev, (void *)rxq);
1389                         (*priv->rxqs)[i] = NULL;
1390                         break;
1391                 }
1392         rxq_cleanup(rxq);
1393         rte_free(rxq);
1394         priv_unlock(priv);
1395 }