1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 6WIND S.A. 3 * Copyright 2017 Mellanox Technologies, Ltd 4 */ 5 6 /** 7 * @file 8 * Rx queues configuration for mlx4 driver. 9 */ 10 11 #include <assert.h> 12 #include <errno.h> 13 #include <stddef.h> 14 #include <stdint.h> 15 #include <string.h> 16 17 /* Verbs headers do not support -pedantic. */ 18 #ifdef PEDANTIC 19 #pragma GCC diagnostic ignored "-Wpedantic" 20 #endif 21 #include <infiniband/mlx4dv.h> 22 #include <infiniband/verbs.h> 23 #ifdef PEDANTIC 24 #pragma GCC diagnostic error "-Wpedantic" 25 #endif 26 27 #include <rte_byteorder.h> 28 #include <rte_common.h> 29 #include <rte_errno.h> 30 #include <rte_ethdev_driver.h> 31 #include <rte_flow.h> 32 #include <rte_malloc.h> 33 #include <rte_mbuf.h> 34 #include <rte_mempool.h> 35 36 #include "mlx4.h" 37 #include "mlx4_glue.h" 38 #include "mlx4_flow.h" 39 #include "mlx4_rxtx.h" 40 #include "mlx4_utils.h" 41 42 /** 43 * Historical RSS hash key. 44 * 45 * This used to be the default for mlx4 in Linux before v3.19 switched to 46 * generating random hash keys through netdev_rss_key_fill(). 47 * 48 * It is used in this PMD for consistency with past DPDK releases but can 49 * now be overridden through user configuration. 50 * 51 * Note: this is not const to work around API quirks. 52 */ 53 uint8_t 54 mlx4_rss_hash_key_default[MLX4_RSS_HASH_KEY_SIZE] = { 55 0x2c, 0xc6, 0x81, 0xd1, 56 0x5b, 0xdb, 0xf4, 0xf7, 57 0xfc, 0xa2, 0x83, 0x19, 58 0xdb, 0x1a, 0x3e, 0x94, 59 0x6b, 0x9e, 0x38, 0xd9, 60 0x2c, 0x9c, 0x03, 0xd1, 61 0xad, 0x99, 0x44, 0xa7, 62 0xd9, 0x56, 0x3d, 0x59, 63 0x06, 0x3c, 0x25, 0xf3, 64 0xfc, 0x1f, 0xdc, 0x2a, 65 }; 66 67 /** 68 * Obtain a RSS context with specified properties. 69 * 70 * Used when creating a flow rule targeting one or several Rx queues. 71 * 72 * If a matching RSS context already exists, it is returned with its 73 * reference count incremented. 74 * 75 * @param priv 76 * Pointer to private structure. 77 * @param fields 78 * Fields for RSS processing (Verbs format). 79 * @param[in] key 80 * Hash key to use (whose size is exactly MLX4_RSS_HASH_KEY_SIZE). 81 * @param queues 82 * Number of target queues. 83 * @param[in] queue_id 84 * Target queues. 85 * 86 * @return 87 * Pointer to RSS context on success, NULL otherwise and rte_errno is set. 88 */ 89 struct mlx4_rss * 90 mlx4_rss_get(struct mlx4_priv *priv, uint64_t fields, 91 const uint8_t key[MLX4_RSS_HASH_KEY_SIZE], 92 uint16_t queues, const uint16_t queue_id[]) 93 { 94 struct mlx4_rss *rss; 95 size_t queue_id_size = sizeof(queue_id[0]) * queues; 96 97 LIST_FOREACH(rss, &priv->rss, next) 98 if (fields == rss->fields && 99 queues == rss->queues && 100 !memcmp(key, rss->key, MLX4_RSS_HASH_KEY_SIZE) && 101 !memcmp(queue_id, rss->queue_id, queue_id_size)) { 102 ++rss->refcnt; 103 return rss; 104 } 105 rss = rte_malloc(__func__, offsetof(struct mlx4_rss, queue_id) + 106 queue_id_size, 0); 107 if (!rss) 108 goto error; 109 *rss = (struct mlx4_rss){ 110 .priv = priv, 111 .refcnt = 1, 112 .usecnt = 0, 113 .qp = NULL, 114 .ind = NULL, 115 .fields = fields, 116 .queues = queues, 117 }; 118 memcpy(rss->key, key, MLX4_RSS_HASH_KEY_SIZE); 119 memcpy(rss->queue_id, queue_id, queue_id_size); 120 LIST_INSERT_HEAD(&priv->rss, rss, next); 121 return rss; 122 error: 123 rte_errno = ENOMEM; 124 return NULL; 125 } 126 127 /** 128 * Release a RSS context instance. 129 * 130 * Used when destroying a flow rule targeting one or several Rx queues. 131 * 132 * This function decrements the reference count of the context and destroys 133 * it after reaching 0. The context must have no users at this point; all 134 * prior calls to mlx4_rss_attach() must have been followed by matching 135 * calls to mlx4_rss_detach(). 136 * 137 * @param rss 138 * RSS context to release. 139 */ 140 void 141 mlx4_rss_put(struct mlx4_rss *rss) 142 { 143 assert(rss->refcnt); 144 if (--rss->refcnt) 145 return; 146 assert(!rss->usecnt); 147 assert(!rss->qp); 148 assert(!rss->ind); 149 LIST_REMOVE(rss, next); 150 rte_free(rss); 151 } 152 153 /** 154 * Attach a user to a RSS context instance. 155 * 156 * Used when the RSS QP and indirection table objects must be instantiated, 157 * that is, when a flow rule must be enabled. 158 * 159 * This function increments the usage count of the context. 160 * 161 * @param rss 162 * RSS context to attach to. 163 * 164 * @return 165 * 0 on success, a negative errno value otherwise and rte_errno is set. 166 */ 167 int 168 mlx4_rss_attach(struct mlx4_rss *rss) 169 { 170 assert(rss->refcnt); 171 if (rss->usecnt++) { 172 assert(rss->qp); 173 assert(rss->ind); 174 return 0; 175 } 176 177 struct ibv_wq *ind_tbl[rss->queues]; 178 struct mlx4_priv *priv = rss->priv; 179 struct rte_eth_dev *dev = ETH_DEV(priv); 180 const char *msg; 181 unsigned int i = 0; 182 int ret; 183 184 if (!rte_is_power_of_2(RTE_DIM(ind_tbl))) { 185 ret = EINVAL; 186 msg = "number of RSS queues must be a power of two"; 187 goto error; 188 } 189 for (i = 0; i != RTE_DIM(ind_tbl); ++i) { 190 uint16_t id = rss->queue_id[i]; 191 struct rxq *rxq = NULL; 192 193 if (id < dev->data->nb_rx_queues) 194 rxq = dev->data->rx_queues[id]; 195 if (!rxq) { 196 ret = EINVAL; 197 msg = "RSS target queue is not configured"; 198 goto error; 199 } 200 ret = mlx4_rxq_attach(rxq); 201 if (ret) { 202 ret = -ret; 203 msg = "unable to attach RSS target queue"; 204 goto error; 205 } 206 ind_tbl[i] = rxq->wq; 207 } 208 rss->ind = mlx4_glue->create_rwq_ind_table 209 (priv->ctx, 210 &(struct ibv_rwq_ind_table_init_attr){ 211 .log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)), 212 .ind_tbl = ind_tbl, 213 .comp_mask = 0, 214 }); 215 if (!rss->ind) { 216 ret = errno ? errno : EINVAL; 217 msg = "RSS indirection table creation failure"; 218 goto error; 219 } 220 rss->qp = mlx4_glue->create_qp_ex 221 (priv->ctx, 222 &(struct ibv_qp_init_attr_ex){ 223 .comp_mask = (IBV_QP_INIT_ATTR_PD | 224 IBV_QP_INIT_ATTR_RX_HASH | 225 IBV_QP_INIT_ATTR_IND_TABLE), 226 .qp_type = IBV_QPT_RAW_PACKET, 227 .pd = priv->pd, 228 .rwq_ind_tbl = rss->ind, 229 .rx_hash_conf = { 230 .rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ, 231 .rx_hash_key_len = MLX4_RSS_HASH_KEY_SIZE, 232 .rx_hash_key = rss->key, 233 .rx_hash_fields_mask = rss->fields, 234 }, 235 }); 236 if (!rss->qp) { 237 ret = errno ? errno : EINVAL; 238 msg = "RSS hash QP creation failure"; 239 goto error; 240 } 241 ret = mlx4_glue->modify_qp 242 (rss->qp, 243 &(struct ibv_qp_attr){ 244 .qp_state = IBV_QPS_INIT, 245 .port_num = priv->port, 246 }, 247 IBV_QP_STATE | IBV_QP_PORT); 248 if (ret) { 249 msg = "failed to switch RSS hash QP to INIT state"; 250 goto error; 251 } 252 ret = mlx4_glue->modify_qp 253 (rss->qp, 254 &(struct ibv_qp_attr){ 255 .qp_state = IBV_QPS_RTR, 256 }, 257 IBV_QP_STATE); 258 if (ret) { 259 msg = "failed to switch RSS hash QP to RTR state"; 260 goto error; 261 } 262 return 0; 263 error: 264 if (rss->qp) { 265 claim_zero(mlx4_glue->destroy_qp(rss->qp)); 266 rss->qp = NULL; 267 } 268 if (rss->ind) { 269 claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind)); 270 rss->ind = NULL; 271 } 272 while (i--) 273 mlx4_rxq_detach(dev->data->rx_queues[rss->queue_id[i]]); 274 ERROR("mlx4: %s", msg); 275 --rss->usecnt; 276 rte_errno = ret; 277 return -ret; 278 } 279 280 /** 281 * Detach a user from a RSS context instance. 282 * 283 * Used when disabling (not destroying) a flow rule. 284 * 285 * This function decrements the usage count of the context and destroys 286 * usage resources after reaching 0. 287 * 288 * @param rss 289 * RSS context to detach from. 290 */ 291 void 292 mlx4_rss_detach(struct mlx4_rss *rss) 293 { 294 struct mlx4_priv *priv = rss->priv; 295 struct rte_eth_dev *dev = ETH_DEV(priv); 296 unsigned int i; 297 298 assert(rss->refcnt); 299 assert(rss->qp); 300 assert(rss->ind); 301 if (--rss->usecnt) 302 return; 303 claim_zero(mlx4_glue->destroy_qp(rss->qp)); 304 rss->qp = NULL; 305 claim_zero(mlx4_glue->destroy_rwq_ind_table(rss->ind)); 306 rss->ind = NULL; 307 for (i = 0; i != rss->queues; ++i) 308 mlx4_rxq_detach(dev->data->rx_queues[rss->queue_id[i]]); 309 } 310 311 /** 312 * Initialize common RSS context resources. 313 * 314 * Because ConnectX-3 hardware limitations require a fixed order in the 315 * indirection table, WQs must be allocated sequentially to be part of a 316 * common RSS context. 317 * 318 * Since a newly created WQ cannot be moved to a different context, this 319 * function allocates them all at once, one for each configured Rx queue, 320 * as well as all related resources (CQs and mbufs). 321 * 322 * This must therefore be done before creating any Rx flow rules relying on 323 * indirection tables. 324 * 325 * @param priv 326 * Pointer to private structure. 327 * 328 * @return 329 * 0 on success, a negative errno value otherwise and rte_errno is set. 330 */ 331 int 332 mlx4_rss_init(struct mlx4_priv *priv) 333 { 334 struct rte_eth_dev *dev = ETH_DEV(priv); 335 uint8_t log2_range = rte_log2_u32(dev->data->nb_rx_queues); 336 uint32_t wq_num_prev = 0; 337 const char *msg; 338 unsigned int i; 339 int ret; 340 341 if (priv->rss_init) 342 return 0; 343 if (ETH_DEV(priv)->data->nb_rx_queues > priv->hw_rss_max_qps) { 344 ERROR("RSS does not support more than %d queues", 345 priv->hw_rss_max_qps); 346 rte_errno = EINVAL; 347 return -rte_errno; 348 } 349 /* Prepare range for RSS contexts before creating the first WQ. */ 350 ret = mlx4_glue->dv_set_context_attr 351 (priv->ctx, 352 MLX4DV_SET_CTX_ATTR_LOG_WQS_RANGE_SZ, 353 &log2_range); 354 if (ret) { 355 ERROR("cannot set up range size for RSS context to %u" 356 " (for %u Rx queues), error: %s", 357 1 << log2_range, dev->data->nb_rx_queues, strerror(ret)); 358 rte_errno = ret; 359 return -ret; 360 } 361 for (i = 0; i != ETH_DEV(priv)->data->nb_rx_queues; ++i) { 362 struct rxq *rxq = ETH_DEV(priv)->data->rx_queues[i]; 363 struct ibv_cq *cq; 364 struct ibv_wq *wq; 365 uint32_t wq_num; 366 367 /* Attach the configured Rx queues. */ 368 if (rxq) { 369 assert(!rxq->usecnt); 370 ret = mlx4_rxq_attach(rxq); 371 if (!ret) { 372 wq_num = rxq->wq->wq_num; 373 goto wq_num_check; 374 } 375 ret = -ret; 376 msg = "unable to create Rx queue resources"; 377 goto error; 378 } 379 /* 380 * WQs are temporarily allocated for unconfigured Rx queues 381 * to maintain proper index alignment in indirection table 382 * by skipping unused WQ numbers. 383 * 384 * The reason this works at all even though these WQs are 385 * immediately destroyed is that WQNs are allocated 386 * sequentially and are guaranteed to never be reused in the 387 * same context by the underlying implementation. 388 */ 389 cq = mlx4_glue->create_cq(priv->ctx, 1, NULL, NULL, 0); 390 if (!cq) { 391 ret = ENOMEM; 392 msg = "placeholder CQ creation failure"; 393 goto error; 394 } 395 wq = mlx4_glue->create_wq 396 (priv->ctx, 397 &(struct ibv_wq_init_attr){ 398 .wq_type = IBV_WQT_RQ, 399 .max_wr = 1, 400 .max_sge = 1, 401 .pd = priv->pd, 402 .cq = cq, 403 }); 404 if (wq) { 405 wq_num = wq->wq_num; 406 claim_zero(mlx4_glue->destroy_wq(wq)); 407 } else { 408 wq_num = 0; /* Shut up GCC 4.8 warnings. */ 409 } 410 claim_zero(mlx4_glue->destroy_cq(cq)); 411 if (!wq) { 412 ret = ENOMEM; 413 msg = "placeholder WQ creation failure"; 414 goto error; 415 } 416 wq_num_check: 417 /* 418 * While guaranteed by the implementation, make sure WQ 419 * numbers are really sequential (as the saying goes, 420 * trust, but verify). 421 */ 422 if (i && wq_num - wq_num_prev != 1) { 423 if (rxq) 424 mlx4_rxq_detach(rxq); 425 ret = ERANGE; 426 msg = "WQ numbers are not sequential"; 427 goto error; 428 } 429 wq_num_prev = wq_num; 430 } 431 priv->rss_init = 1; 432 return 0; 433 error: 434 ERROR("cannot initialize common RSS resources (queue %u): %s: %s", 435 i, msg, strerror(ret)); 436 while (i--) { 437 struct rxq *rxq = ETH_DEV(priv)->data->rx_queues[i]; 438 439 if (rxq) 440 mlx4_rxq_detach(rxq); 441 } 442 rte_errno = ret; 443 return -ret; 444 } 445 446 /** 447 * Release common RSS context resources. 448 * 449 * As the reverse of mlx4_rss_init(), this must be done after removing all 450 * flow rules relying on indirection tables. 451 * 452 * @param priv 453 * Pointer to private structure. 454 */ 455 void 456 mlx4_rss_deinit(struct mlx4_priv *priv) 457 { 458 unsigned int i; 459 460 if (!priv->rss_init) 461 return; 462 for (i = 0; i != ETH_DEV(priv)->data->nb_rx_queues; ++i) { 463 struct rxq *rxq = ETH_DEV(priv)->data->rx_queues[i]; 464 465 if (rxq) { 466 assert(rxq->usecnt == 1); 467 mlx4_rxq_detach(rxq); 468 } 469 } 470 priv->rss_init = 0; 471 } 472 473 /** 474 * Attach a user to a Rx queue. 475 * 476 * Used when the resources of an Rx queue must be instantiated for it to 477 * become in a usable state. 478 * 479 * This function increments the usage count of the Rx queue. 480 * 481 * @param rxq 482 * Pointer to Rx queue structure. 483 * 484 * @return 485 * 0 on success, negative errno value otherwise and rte_errno is set. 486 */ 487 int 488 mlx4_rxq_attach(struct rxq *rxq) 489 { 490 if (rxq->usecnt++) { 491 assert(rxq->cq); 492 assert(rxq->wq); 493 assert(rxq->wqes); 494 assert(rxq->rq_db); 495 return 0; 496 } 497 498 struct mlx4_priv *priv = rxq->priv; 499 struct rte_eth_dev *dev = ETH_DEV(priv); 500 const uint32_t elts_n = 1 << rxq->elts_n; 501 const uint32_t sges_n = 1 << rxq->sges_n; 502 struct rte_mbuf *(*elts)[elts_n] = rxq->elts; 503 struct mlx4dv_obj mlxdv; 504 struct mlx4dv_rwq dv_rwq; 505 struct mlx4dv_cq dv_cq = { .comp_mask = MLX4DV_CQ_MASK_UAR, }; 506 const char *msg; 507 struct ibv_cq *cq = NULL; 508 struct ibv_wq *wq = NULL; 509 uint32_t create_flags = 0; 510 uint32_t comp_mask = 0; 511 volatile struct mlx4_wqe_data_seg (*wqes)[]; 512 unsigned int i; 513 int ret; 514 515 assert(rte_is_power_of_2(elts_n)); 516 cq = mlx4_glue->create_cq(priv->ctx, elts_n / sges_n, NULL, 517 rxq->channel, 0); 518 if (!cq) { 519 ret = ENOMEM; 520 msg = "CQ creation failure"; 521 goto error; 522 } 523 /* By default, FCS (CRC) is stripped by hardware. */ 524 if (rxq->crc_present) { 525 create_flags |= IBV_WQ_FLAGS_SCATTER_FCS; 526 comp_mask |= IBV_WQ_INIT_ATTR_FLAGS; 527 } 528 wq = mlx4_glue->create_wq 529 (priv->ctx, 530 &(struct ibv_wq_init_attr){ 531 .wq_type = IBV_WQT_RQ, 532 .max_wr = elts_n / sges_n, 533 .max_sge = sges_n, 534 .pd = priv->pd, 535 .cq = cq, 536 .comp_mask = comp_mask, 537 .create_flags = create_flags, 538 }); 539 if (!wq) { 540 ret = errno ? errno : EINVAL; 541 msg = "WQ creation failure"; 542 goto error; 543 } 544 ret = mlx4_glue->modify_wq 545 (wq, 546 &(struct ibv_wq_attr){ 547 .attr_mask = IBV_WQ_ATTR_STATE, 548 .wq_state = IBV_WQS_RDY, 549 }); 550 if (ret) { 551 msg = "WQ state change to IBV_WQS_RDY failed"; 552 goto error; 553 } 554 /* Retrieve device queue information. */ 555 mlxdv.cq.in = cq; 556 mlxdv.cq.out = &dv_cq; 557 mlxdv.rwq.in = wq; 558 mlxdv.rwq.out = &dv_rwq; 559 ret = mlx4_glue->dv_init_obj(&mlxdv, MLX4DV_OBJ_RWQ | MLX4DV_OBJ_CQ); 560 if (ret) { 561 msg = "failed to obtain device information from WQ/CQ objects"; 562 goto error; 563 } 564 /* Pre-register Rx mempool. */ 565 DEBUG("port %u Rx queue %u registering mp %s having %u chunks", 566 ETH_DEV(priv)->data->port_id, rxq->stats.idx, 567 rxq->mp->name, rxq->mp->nb_mem_chunks); 568 mlx4_mr_update_mp(dev, &rxq->mr_ctrl, rxq->mp); 569 wqes = (volatile struct mlx4_wqe_data_seg (*)[]) 570 ((uintptr_t)dv_rwq.buf.buf + dv_rwq.rq.offset); 571 for (i = 0; i != RTE_DIM(*elts); ++i) { 572 volatile struct mlx4_wqe_data_seg *scat = &(*wqes)[i]; 573 struct rte_mbuf *buf = rte_pktmbuf_alloc(rxq->mp); 574 575 if (buf == NULL) { 576 while (i--) { 577 rte_pktmbuf_free_seg((*elts)[i]); 578 (*elts)[i] = NULL; 579 } 580 ret = ENOMEM; 581 msg = "cannot allocate mbuf"; 582 goto error; 583 } 584 /* Headroom is reserved by rte_pktmbuf_alloc(). */ 585 assert(buf->data_off == RTE_PKTMBUF_HEADROOM); 586 /* Buffer is supposed to be empty. */ 587 assert(rte_pktmbuf_data_len(buf) == 0); 588 assert(rte_pktmbuf_pkt_len(buf) == 0); 589 /* Only the first segment keeps headroom. */ 590 if (i % sges_n) 591 buf->data_off = 0; 592 buf->port = rxq->port_id; 593 buf->data_len = rte_pktmbuf_tailroom(buf); 594 buf->pkt_len = rte_pktmbuf_tailroom(buf); 595 buf->nb_segs = 1; 596 *scat = (struct mlx4_wqe_data_seg){ 597 .addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, 598 uintptr_t)), 599 .byte_count = rte_cpu_to_be_32(buf->data_len), 600 .lkey = mlx4_rx_mb2mr(rxq, buf), 601 }; 602 (*elts)[i] = buf; 603 } 604 DEBUG("%p: allocated and configured %u segments (max %u packets)", 605 (void *)rxq, elts_n, elts_n / sges_n); 606 rxq->cq = cq; 607 rxq->wq = wq; 608 rxq->wqes = wqes; 609 rxq->rq_db = dv_rwq.rdb; 610 rxq->mcq.buf = dv_cq.buf.buf; 611 rxq->mcq.cqe_cnt = dv_cq.cqe_cnt; 612 rxq->mcq.set_ci_db = dv_cq.set_ci_db; 613 rxq->mcq.cqe_64 = (dv_cq.cqe_size & 64) ? 1 : 0; 614 rxq->mcq.arm_db = dv_cq.arm_db; 615 rxq->mcq.arm_sn = dv_cq.arm_sn; 616 rxq->mcq.cqn = dv_cq.cqn; 617 rxq->mcq.cq_uar = dv_cq.cq_uar; 618 rxq->mcq.cq_db_reg = (uint8_t *)dv_cq.cq_uar + MLX4_CQ_DOORBELL; 619 /* Update doorbell counter. */ 620 rxq->rq_ci = elts_n / sges_n; 621 rte_wmb(); 622 *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 623 return 0; 624 error: 625 if (wq) 626 claim_zero(mlx4_glue->destroy_wq(wq)); 627 if (cq) 628 claim_zero(mlx4_glue->destroy_cq(cq)); 629 --rxq->usecnt; 630 rte_errno = ret; 631 ERROR("error while attaching Rx queue %p: %s: %s", 632 (void *)rxq, msg, strerror(ret)); 633 return -ret; 634 } 635 636 /** 637 * Detach a user from a Rx queue. 638 * 639 * This function decrements the usage count of the Rx queue and destroys 640 * usage resources after reaching 0. 641 * 642 * @param rxq 643 * Pointer to Rx queue structure. 644 */ 645 void 646 mlx4_rxq_detach(struct rxq *rxq) 647 { 648 unsigned int i; 649 struct rte_mbuf *(*elts)[1 << rxq->elts_n] = rxq->elts; 650 651 if (--rxq->usecnt) 652 return; 653 rxq->rq_ci = 0; 654 memset(&rxq->mcq, 0, sizeof(rxq->mcq)); 655 rxq->rq_db = NULL; 656 rxq->wqes = NULL; 657 claim_zero(mlx4_glue->destroy_wq(rxq->wq)); 658 rxq->wq = NULL; 659 claim_zero(mlx4_glue->destroy_cq(rxq->cq)); 660 rxq->cq = NULL; 661 DEBUG("%p: freeing Rx queue elements", (void *)rxq); 662 for (i = 0; (i != RTE_DIM(*elts)); ++i) { 663 if (!(*elts)[i]) 664 continue; 665 rte_pktmbuf_free_seg((*elts)[i]); 666 (*elts)[i] = NULL; 667 } 668 } 669 670 /** 671 * Returns the per-queue supported offloads. 672 * 673 * @param priv 674 * Pointer to private structure. 675 * 676 * @return 677 * Supported Tx offloads. 678 */ 679 uint64_t 680 mlx4_get_rx_queue_offloads(struct mlx4_priv *priv) 681 { 682 uint64_t offloads = DEV_RX_OFFLOAD_SCATTER | 683 DEV_RX_OFFLOAD_KEEP_CRC | 684 DEV_RX_OFFLOAD_JUMBO_FRAME; 685 686 if (priv->hw_csum) 687 offloads |= DEV_RX_OFFLOAD_CHECKSUM; 688 return offloads; 689 } 690 691 /** 692 * Returns the per-port supported offloads. 693 * 694 * @param priv 695 * Pointer to private structure. 696 * 697 * @return 698 * Supported Rx offloads. 699 */ 700 uint64_t 701 mlx4_get_rx_port_offloads(struct mlx4_priv *priv) 702 { 703 uint64_t offloads = DEV_RX_OFFLOAD_VLAN_FILTER; 704 705 (void)priv; 706 return offloads; 707 } 708 709 /** 710 * DPDK callback to configure a Rx queue. 711 * 712 * @param dev 713 * Pointer to Ethernet device structure. 714 * @param idx 715 * Rx queue index. 716 * @param desc 717 * Number of descriptors to configure in queue. 718 * @param socket 719 * NUMA socket on which memory must be allocated. 720 * @param[in] conf 721 * Thresholds parameters. 722 * @param mp 723 * Memory pool for buffer allocations. 724 * 725 * @return 726 * 0 on success, negative errno value otherwise and rte_errno is set. 727 */ 728 int 729 mlx4_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, 730 unsigned int socket, const struct rte_eth_rxconf *conf, 731 struct rte_mempool *mp) 732 { 733 struct mlx4_priv *priv = dev->data->dev_private; 734 uint32_t mb_len = rte_pktmbuf_data_room_size(mp); 735 struct rte_mbuf *(*elts)[rte_align32pow2(desc)]; 736 struct rxq *rxq; 737 struct mlx4_malloc_vec vec[] = { 738 { 739 .align = RTE_CACHE_LINE_SIZE, 740 .size = sizeof(*rxq), 741 .addr = (void **)&rxq, 742 }, 743 { 744 .align = RTE_CACHE_LINE_SIZE, 745 .size = sizeof(*elts), 746 .addr = (void **)&elts, 747 }, 748 }; 749 int ret; 750 uint32_t crc_present; 751 uint64_t offloads; 752 753 offloads = conf->offloads | dev->data->dev_conf.rxmode.offloads; 754 755 DEBUG("%p: configuring queue %u for %u descriptors", 756 (void *)dev, idx, desc); 757 758 if (idx >= dev->data->nb_rx_queues) { 759 rte_errno = EOVERFLOW; 760 ERROR("%p: queue index out of range (%u >= %u)", 761 (void *)dev, idx, dev->data->nb_rx_queues); 762 return -rte_errno; 763 } 764 rxq = dev->data->rx_queues[idx]; 765 if (rxq) { 766 rte_errno = EEXIST; 767 ERROR("%p: Rx queue %u already configured, release it first", 768 (void *)dev, idx); 769 return -rte_errno; 770 } 771 if (!desc) { 772 rte_errno = EINVAL; 773 ERROR("%p: invalid number of Rx descriptors", (void *)dev); 774 return -rte_errno; 775 } 776 if (desc != RTE_DIM(*elts)) { 777 desc = RTE_DIM(*elts); 778 WARN("%p: increased number of descriptors in Rx queue %u" 779 " to the next power of two (%u)", 780 (void *)dev, idx, desc); 781 } 782 /* By default, FCS (CRC) is stripped by hardware. */ 783 crc_present = 0; 784 if (offloads & DEV_RX_OFFLOAD_KEEP_CRC) { 785 if (priv->hw_fcs_strip) { 786 crc_present = 1; 787 } else { 788 WARN("%p: CRC stripping has been disabled but will still" 789 " be performed by hardware, make sure MLNX_OFED and" 790 " firmware are up to date", 791 (void *)dev); 792 } 793 } 794 DEBUG("%p: CRC stripping is %s, %u bytes will be subtracted from" 795 " incoming frames to hide it", 796 (void *)dev, 797 crc_present ? "disabled" : "enabled", 798 crc_present << 2); 799 /* Allocate and initialize Rx queue. */ 800 mlx4_zmallocv_socket("RXQ", vec, RTE_DIM(vec), socket); 801 if (!rxq) { 802 ERROR("%p: unable to allocate queue index %u", 803 (void *)dev, idx); 804 return -rte_errno; 805 } 806 *rxq = (struct rxq){ 807 .priv = priv, 808 .mp = mp, 809 .port_id = dev->data->port_id, 810 .sges_n = 0, 811 .elts_n = rte_log2_u32(desc), 812 .elts = elts, 813 /* Toggle Rx checksum offload if hardware supports it. */ 814 .csum = priv->hw_csum && 815 (offloads & DEV_RX_OFFLOAD_CHECKSUM), 816 .csum_l2tun = priv->hw_csum_l2tun && 817 (offloads & DEV_RX_OFFLOAD_CHECKSUM), 818 .crc_present = crc_present, 819 .l2tun_offload = priv->hw_csum_l2tun, 820 .stats = { 821 .idx = idx, 822 }, 823 .socket = socket, 824 }; 825 /* Enable scattered packets support for this queue if necessary. */ 826 assert(mb_len >= RTE_PKTMBUF_HEADROOM); 827 if (dev->data->dev_conf.rxmode.max_rx_pkt_len <= 828 (mb_len - RTE_PKTMBUF_HEADROOM)) { 829 ; 830 } else if (offloads & DEV_RX_OFFLOAD_SCATTER) { 831 uint32_t size = 832 RTE_PKTMBUF_HEADROOM + 833 dev->data->dev_conf.rxmode.max_rx_pkt_len; 834 uint32_t sges_n; 835 836 /* 837 * Determine the number of SGEs needed for a full packet 838 * and round it to the next power of two. 839 */ 840 sges_n = rte_log2_u32((size / mb_len) + !!(size % mb_len)); 841 rxq->sges_n = sges_n; 842 /* Make sure sges_n did not overflow. */ 843 size = mb_len * (1 << rxq->sges_n); 844 size -= RTE_PKTMBUF_HEADROOM; 845 if (size < dev->data->dev_conf.rxmode.max_rx_pkt_len) { 846 rte_errno = EOVERFLOW; 847 ERROR("%p: too many SGEs (%u) needed to handle" 848 " requested maximum packet size %u", 849 (void *)dev, 850 1 << sges_n, 851 dev->data->dev_conf.rxmode.max_rx_pkt_len); 852 goto error; 853 } 854 } else { 855 WARN("%p: the requested maximum Rx packet size (%u) is" 856 " larger than a single mbuf (%u) and scattered" 857 " mode has not been requested", 858 (void *)dev, 859 dev->data->dev_conf.rxmode.max_rx_pkt_len, 860 mb_len - RTE_PKTMBUF_HEADROOM); 861 } 862 DEBUG("%p: maximum number of segments per packet: %u", 863 (void *)dev, 1 << rxq->sges_n); 864 if (desc % (1 << rxq->sges_n)) { 865 rte_errno = EINVAL; 866 ERROR("%p: number of Rx queue descriptors (%u) is not a" 867 " multiple of maximum segments per packet (%u)", 868 (void *)dev, 869 desc, 870 1 << rxq->sges_n); 871 goto error; 872 } 873 if (mlx4_mr_btree_init(&rxq->mr_ctrl.cache_bh, 874 MLX4_MR_BTREE_CACHE_N, socket)) { 875 /* rte_errno is already set. */ 876 goto error; 877 } 878 if (dev->data->dev_conf.intr_conf.rxq) { 879 rxq->channel = mlx4_glue->create_comp_channel(priv->ctx); 880 if (rxq->channel == NULL) { 881 rte_errno = ENOMEM; 882 ERROR("%p: Rx interrupt completion channel creation" 883 " failure: %s", 884 (void *)dev, strerror(rte_errno)); 885 goto error; 886 } 887 if (mlx4_fd_set_non_blocking(rxq->channel->fd) < 0) { 888 ERROR("%p: unable to make Rx interrupt completion" 889 " channel non-blocking: %s", 890 (void *)dev, strerror(rte_errno)); 891 goto error; 892 } 893 } 894 DEBUG("%p: adding Rx queue %p to list", (void *)dev, (void *)rxq); 895 dev->data->rx_queues[idx] = rxq; 896 return 0; 897 error: 898 dev->data->rx_queues[idx] = NULL; 899 ret = rte_errno; 900 mlx4_rx_queue_release(rxq); 901 rte_errno = ret; 902 assert(rte_errno > 0); 903 return -rte_errno; 904 } 905 906 /** 907 * DPDK callback to release a Rx queue. 908 * 909 * @param dpdk_rxq 910 * Generic Rx queue pointer. 911 */ 912 void 913 mlx4_rx_queue_release(void *dpdk_rxq) 914 { 915 struct rxq *rxq = (struct rxq *)dpdk_rxq; 916 struct mlx4_priv *priv; 917 unsigned int i; 918 919 if (rxq == NULL) 920 return; 921 priv = rxq->priv; 922 for (i = 0; i != ETH_DEV(priv)->data->nb_rx_queues; ++i) 923 if (ETH_DEV(priv)->data->rx_queues[i] == rxq) { 924 DEBUG("%p: removing Rx queue %p from list", 925 (void *)ETH_DEV(priv), (void *)rxq); 926 ETH_DEV(priv)->data->rx_queues[i] = NULL; 927 break; 928 } 929 assert(!rxq->cq); 930 assert(!rxq->wq); 931 assert(!rxq->wqes); 932 assert(!rxq->rq_db); 933 if (rxq->channel) 934 claim_zero(mlx4_glue->destroy_comp_channel(rxq->channel)); 935 mlx4_mr_btree_free(&rxq->mr_ctrl.cache_bh); 936 rte_free(rxq); 937 } 938