1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2020 Mellanox Technologies, Ltd 3 */ 4 5 #include <stddef.h> 6 #include <errno.h> 7 #include <stdbool.h> 8 #include <string.h> 9 #include <stdint.h> 10 #include <sys/queue.h> 11 12 #include <rte_malloc.h> 13 #include <rte_common.h> 14 #include <rte_eal_paging.h> 15 16 #include <mlx5_glue.h> 17 #include <mlx5_devx_cmds.h> 18 #include <mlx5_malloc.h> 19 20 #include "mlx5.h" 21 #include "mlx5_common_os.h" 22 #include "mlx5_rxtx.h" 23 #include "mlx5_utils.h" 24 #include "mlx5_devx.h" 25 #include "mlx5_flow.h" 26 27 28 /** 29 * Modify RQ vlan stripping offload 30 * 31 * @param rxq_obj 32 * Rx queue object. 33 * 34 * @return 35 * 0 on success, non-0 otherwise 36 */ 37 static int 38 mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_obj *rxq_obj, int on) 39 { 40 struct mlx5_devx_modify_rq_attr rq_attr; 41 42 memset(&rq_attr, 0, sizeof(rq_attr)); 43 rq_attr.rq_state = MLX5_RQC_STATE_RDY; 44 rq_attr.state = MLX5_RQC_STATE_RDY; 45 rq_attr.vsd = (on ? 0 : 1); 46 rq_attr.modify_bitmask = MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD; 47 return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr); 48 } 49 50 /** 51 * Modify RQ using DevX API. 52 * 53 * @param rxq_obj 54 * DevX Rx queue object. 55 * @param type 56 * Type of change queue state. 57 * 58 * @return 59 * 0 on success, a negative errno value otherwise and rte_errno is set. 60 */ 61 static int 62 mlx5_devx_modify_rq(struct mlx5_rxq_obj *rxq_obj, uint8_t type) 63 { 64 struct mlx5_devx_modify_rq_attr rq_attr; 65 66 memset(&rq_attr, 0, sizeof(rq_attr)); 67 switch (type) { 68 case MLX5_RXQ_MOD_ERR2RST: 69 rq_attr.rq_state = MLX5_RQC_STATE_ERR; 70 rq_attr.state = MLX5_RQC_STATE_RST; 71 break; 72 case MLX5_RXQ_MOD_RST2RDY: 73 rq_attr.rq_state = MLX5_RQC_STATE_RST; 74 rq_attr.state = MLX5_RQC_STATE_RDY; 75 break; 76 case MLX5_RXQ_MOD_RDY2ERR: 77 rq_attr.rq_state = MLX5_RQC_STATE_RDY; 78 rq_attr.state = MLX5_RQC_STATE_ERR; 79 break; 80 case MLX5_RXQ_MOD_RDY2RST: 81 rq_attr.rq_state = MLX5_RQC_STATE_RDY; 82 rq_attr.state = MLX5_RQC_STATE_RST; 83 break; 84 default: 85 break; 86 } 87 return mlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr); 88 } 89 90 /** 91 * Modify SQ using DevX API. 92 * 93 * @param txq_obj 94 * DevX Tx queue object. 95 * @param type 96 * Type of change queue state. 97 * @param dev_port 98 * Unnecessary. 99 * 100 * @return 101 * 0 on success, a negative errno value otherwise and rte_errno is set. 102 */ 103 static int 104 mlx5_devx_modify_sq(struct mlx5_txq_obj *obj, enum mlx5_txq_modify_type type, 105 uint8_t dev_port) 106 { 107 struct mlx5_devx_modify_sq_attr msq_attr = { 0 }; 108 int ret; 109 110 if (type != MLX5_TXQ_MOD_RST2RDY) { 111 /* Change queue state to reset. */ 112 if (type == MLX5_TXQ_MOD_ERR2RDY) 113 msq_attr.sq_state = MLX5_SQC_STATE_ERR; 114 else 115 msq_attr.sq_state = MLX5_SQC_STATE_RDY; 116 msq_attr.state = MLX5_SQC_STATE_RST; 117 ret = mlx5_devx_cmd_modify_sq(obj->sq_devx, &msq_attr); 118 if (ret) { 119 DRV_LOG(ERR, "Cannot change the Tx SQ state to RESET" 120 " %s", strerror(errno)); 121 rte_errno = errno; 122 return ret; 123 } 124 } 125 if (type != MLX5_TXQ_MOD_RDY2RST) { 126 /* Change queue state to ready. */ 127 msq_attr.sq_state = MLX5_SQC_STATE_RST; 128 msq_attr.state = MLX5_SQC_STATE_RDY; 129 ret = mlx5_devx_cmd_modify_sq(obj->sq_devx, &msq_attr); 130 if (ret) { 131 DRV_LOG(ERR, "Cannot change the Tx SQ state to READY" 132 " %s", strerror(errno)); 133 rte_errno = errno; 134 return ret; 135 } 136 } 137 /* 138 * The dev_port variable is relevant only in Verbs API, and there is a 139 * pointer that points to this function and a parallel function in verbs 140 * intermittently, so they should have the same parameters. 141 */ 142 (void)dev_port; 143 return 0; 144 } 145 146 /** 147 * Release the resources allocated for an RQ DevX object. 148 * 149 * @param rxq_ctrl 150 * DevX Rx queue object. 151 */ 152 static void 153 mlx5_rxq_release_devx_rq_resources(struct mlx5_rxq_ctrl *rxq_ctrl) 154 { 155 struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->rq_dbrec_page; 156 157 if (rxq_ctrl->rxq.wqes) { 158 mlx5_free((void *)(uintptr_t)rxq_ctrl->rxq.wqes); 159 rxq_ctrl->rxq.wqes = NULL; 160 } 161 if (rxq_ctrl->wq_umem) { 162 mlx5_glue->devx_umem_dereg(rxq_ctrl->wq_umem); 163 rxq_ctrl->wq_umem = NULL; 164 } 165 if (dbr_page) { 166 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs, 167 mlx5_os_get_umem_id(dbr_page->umem), 168 rxq_ctrl->rq_dbr_offset)); 169 rxq_ctrl->rq_dbrec_page = NULL; 170 } 171 } 172 173 /** 174 * Release the resources allocated for the Rx CQ DevX object. 175 * 176 * @param rxq_ctrl 177 * DevX Rx queue object. 178 */ 179 static void 180 mlx5_rxq_release_devx_cq_resources(struct mlx5_rxq_ctrl *rxq_ctrl) 181 { 182 struct mlx5_devx_dbr_page *dbr_page = rxq_ctrl->cq_dbrec_page; 183 184 if (rxq_ctrl->rxq.cqes) { 185 rte_free((void *)(uintptr_t)rxq_ctrl->rxq.cqes); 186 rxq_ctrl->rxq.cqes = NULL; 187 } 188 if (rxq_ctrl->cq_umem) { 189 mlx5_glue->devx_umem_dereg(rxq_ctrl->cq_umem); 190 rxq_ctrl->cq_umem = NULL; 191 } 192 if (dbr_page) { 193 claim_zero(mlx5_release_dbr(&rxq_ctrl->priv->dbrpgs, 194 mlx5_os_get_umem_id(dbr_page->umem), 195 rxq_ctrl->cq_dbr_offset)); 196 rxq_ctrl->cq_dbrec_page = NULL; 197 } 198 } 199 200 /** 201 * Release an Rx DevX queue object. 202 * 203 * @param rxq_obj 204 * DevX Rx queue object. 205 */ 206 static void 207 mlx5_rxq_devx_obj_release(struct mlx5_rxq_obj *rxq_obj) 208 { 209 MLX5_ASSERT(rxq_obj); 210 MLX5_ASSERT(rxq_obj->rq); 211 if (rxq_obj->rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN) { 212 mlx5_devx_modify_rq(rxq_obj, MLX5_RXQ_MOD_RDY2RST); 213 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq)); 214 } else { 215 MLX5_ASSERT(rxq_obj->devx_cq); 216 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq)); 217 claim_zero(mlx5_devx_cmd_destroy(rxq_obj->devx_cq)); 218 if (rxq_obj->devx_channel) 219 mlx5_glue->devx_destroy_event_channel 220 (rxq_obj->devx_channel); 221 mlx5_rxq_release_devx_rq_resources(rxq_obj->rxq_ctrl); 222 mlx5_rxq_release_devx_cq_resources(rxq_obj->rxq_ctrl); 223 } 224 } 225 226 /** 227 * Get event for an Rx DevX queue object. 228 * 229 * @param rxq_obj 230 * DevX Rx queue object. 231 * 232 * @return 233 * 0 on success, a negative errno value otherwise and rte_errno is set. 234 */ 235 static int 236 mlx5_rx_devx_get_event(struct mlx5_rxq_obj *rxq_obj) 237 { 238 #ifdef HAVE_IBV_DEVX_EVENT 239 union { 240 struct mlx5dv_devx_async_event_hdr event_resp; 241 uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128]; 242 } out; 243 int ret = mlx5_glue->devx_get_event(rxq_obj->devx_channel, 244 &out.event_resp, 245 sizeof(out.buf)); 246 247 if (ret < 0) { 248 rte_errno = errno; 249 return -rte_errno; 250 } 251 if (out.event_resp.cookie != (uint64_t)(uintptr_t)rxq_obj->devx_cq) { 252 rte_errno = EINVAL; 253 return -rte_errno; 254 } 255 return 0; 256 #else 257 (void)rxq_obj; 258 rte_errno = ENOTSUP; 259 return -rte_errno; 260 #endif /* HAVE_IBV_DEVX_EVENT */ 261 } 262 263 /** 264 * Fill common fields of create RQ attributes structure. 265 * 266 * @param rxq_data 267 * Pointer to Rx queue data. 268 * @param cqn 269 * CQ number to use with this RQ. 270 * @param rq_attr 271 * RQ attributes structure to fill.. 272 */ 273 static void 274 mlx5_devx_create_rq_attr_fill(struct mlx5_rxq_data *rxq_data, uint32_t cqn, 275 struct mlx5_devx_create_rq_attr *rq_attr) 276 { 277 rq_attr->state = MLX5_RQC_STATE_RST; 278 rq_attr->vsd = (rxq_data->vlan_strip) ? 0 : 1; 279 rq_attr->cqn = cqn; 280 rq_attr->scatter_fcs = (rxq_data->crc_present) ? 1 : 0; 281 } 282 283 /** 284 * Fill common fields of DevX WQ attributes structure. 285 * 286 * @param priv 287 * Pointer to device private data. 288 * @param rxq_ctrl 289 * Pointer to Rx queue control structure. 290 * @param wq_attr 291 * WQ attributes structure to fill.. 292 */ 293 static void 294 mlx5_devx_wq_attr_fill(struct mlx5_priv *priv, struct mlx5_rxq_ctrl *rxq_ctrl, 295 struct mlx5_devx_wq_attr *wq_attr) 296 { 297 wq_attr->end_padding_mode = priv->config.cqe_pad ? 298 MLX5_WQ_END_PAD_MODE_ALIGN : 299 MLX5_WQ_END_PAD_MODE_NONE; 300 wq_attr->pd = priv->sh->pdn; 301 wq_attr->dbr_addr = rxq_ctrl->rq_dbr_offset; 302 wq_attr->dbr_umem_id = 303 mlx5_os_get_umem_id(rxq_ctrl->rq_dbrec_page->umem); 304 wq_attr->dbr_umem_valid = 1; 305 wq_attr->wq_umem_id = mlx5_os_get_umem_id(rxq_ctrl->wq_umem); 306 wq_attr->wq_umem_valid = 1; 307 } 308 309 /** 310 * Create a RQ object using DevX. 311 * 312 * @param dev 313 * Pointer to Ethernet device. 314 * @param idx 315 * Queue index in DPDK Rx queue array. 316 * 317 * @return 318 * The DevX RQ object initialized, NULL otherwise and rte_errno is set. 319 */ 320 static struct mlx5_devx_obj * 321 mlx5_rxq_create_devx_rq_resources(struct rte_eth_dev *dev, uint16_t idx) 322 { 323 struct mlx5_priv *priv = dev->data->dev_private; 324 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx]; 325 struct mlx5_rxq_ctrl *rxq_ctrl = 326 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); 327 struct mlx5_devx_create_rq_attr rq_attr = { 0 }; 328 uint32_t wqe_n = 1 << (rxq_data->elts_n - rxq_data->sges_n); 329 uint32_t cqn = rxq_ctrl->obj->devx_cq->id; 330 struct mlx5_devx_dbr_page *dbr_page; 331 int64_t dbr_offset; 332 uint32_t wq_size = 0; 333 uint32_t wqe_size = 0; 334 uint32_t log_wqe_size = 0; 335 void *buf = NULL; 336 struct mlx5_devx_obj *rq; 337 338 /* Fill RQ attributes. */ 339 rq_attr.mem_rq_type = MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE; 340 rq_attr.flush_in_error_en = 1; 341 mlx5_devx_create_rq_attr_fill(rxq_data, cqn, &rq_attr); 342 /* Fill WQ attributes for this RQ. */ 343 if (mlx5_rxq_mprq_enabled(rxq_data)) { 344 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ; 345 /* 346 * Number of strides in each WQE: 347 * 512*2^single_wqe_log_num_of_strides. 348 */ 349 rq_attr.wq_attr.single_wqe_log_num_of_strides = 350 rxq_data->strd_num_n - 351 MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES; 352 /* Stride size = (2^single_stride_log_num_of_bytes)*64B. */ 353 rq_attr.wq_attr.single_stride_log_num_of_bytes = 354 rxq_data->strd_sz_n - 355 MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES; 356 wqe_size = sizeof(struct mlx5_wqe_mprq); 357 } else { 358 rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC; 359 wqe_size = sizeof(struct mlx5_wqe_data_seg); 360 } 361 log_wqe_size = log2above(wqe_size) + rxq_data->sges_n; 362 rq_attr.wq_attr.log_wq_stride = log_wqe_size; 363 rq_attr.wq_attr.log_wq_sz = rxq_data->elts_n - rxq_data->sges_n; 364 /* Calculate and allocate WQ memory space. */ 365 wqe_size = 1 << log_wqe_size; /* round up power of two.*/ 366 wq_size = wqe_n * wqe_size; 367 size_t alignment = MLX5_WQE_BUF_ALIGNMENT; 368 if (alignment == (size_t)-1) { 369 DRV_LOG(ERR, "Failed to get mem page size"); 370 rte_errno = ENOMEM; 371 return NULL; 372 } 373 buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, wq_size, 374 alignment, rxq_ctrl->socket); 375 if (!buf) 376 return NULL; 377 rxq_data->wqes = buf; 378 rxq_ctrl->wq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx, 379 buf, wq_size, 0); 380 if (!rxq_ctrl->wq_umem) 381 goto error; 382 /* Allocate RQ door-bell. */ 383 dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page); 384 if (dbr_offset < 0) { 385 DRV_LOG(ERR, "Failed to allocate RQ door-bell."); 386 goto error; 387 } 388 rxq_ctrl->rq_dbr_offset = dbr_offset; 389 rxq_ctrl->rq_dbrec_page = dbr_page; 390 rxq_data->rq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs + 391 (uintptr_t)rxq_ctrl->rq_dbr_offset); 392 /* Create RQ using DevX API. */ 393 mlx5_devx_wq_attr_fill(priv, rxq_ctrl, &rq_attr.wq_attr); 394 rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &rq_attr, rxq_ctrl->socket); 395 if (!rq) 396 goto error; 397 return rq; 398 error: 399 mlx5_rxq_release_devx_rq_resources(rxq_ctrl); 400 return NULL; 401 } 402 403 /** 404 * Create a DevX CQ object for an Rx queue. 405 * 406 * @param dev 407 * Pointer to Ethernet device. 408 * @param idx 409 * Queue index in DPDK Rx queue array. 410 * 411 * @return 412 * The DevX CQ object initialized, NULL otherwise and rte_errno is set. 413 */ 414 static struct mlx5_devx_obj * 415 mlx5_rxq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx) 416 { 417 struct mlx5_devx_obj *cq_obj = 0; 418 struct mlx5_devx_cq_attr cq_attr = { 0 }; 419 struct mlx5_priv *priv = dev->data->dev_private; 420 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx]; 421 struct mlx5_rxq_ctrl *rxq_ctrl = 422 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); 423 size_t page_size = rte_mem_page_size(); 424 unsigned int cqe_n = mlx5_rxq_cqe_num(rxq_data); 425 struct mlx5_devx_dbr_page *dbr_page; 426 int64_t dbr_offset; 427 void *buf = NULL; 428 uint16_t event_nums[1] = {0}; 429 uint32_t log_cqe_n; 430 uint32_t cq_size; 431 int ret = 0; 432 433 if (page_size == (size_t)-1) { 434 DRV_LOG(ERR, "Failed to get page_size."); 435 goto error; 436 } 437 if (priv->config.cqe_comp && !rxq_data->hw_timestamp && 438 !rxq_data->lro) { 439 cq_attr.cqe_comp_en = 1u; 440 rxq_data->mcqe_format = priv->config.cqe_comp_fmt; 441 rxq_data->byte_mask = UINT32_MAX; 442 switch (priv->config.cqe_comp_fmt) { 443 case MLX5_CQE_RESP_FORMAT_HASH: 444 /* fallthrough */ 445 case MLX5_CQE_RESP_FORMAT_CSUM: 446 /* 447 * Select CSUM miniCQE format only for non-vectorized 448 * MPRQ Rx burst, use HASH miniCQE format for others. 449 */ 450 if (mlx5_rxq_check_vec_support(rxq_data) < 0 && 451 mlx5_rxq_mprq_enabled(rxq_data)) 452 cq_attr.mini_cqe_res_format = 453 MLX5_CQE_RESP_FORMAT_CSUM_STRIDX; 454 else 455 cq_attr.mini_cqe_res_format = 456 MLX5_CQE_RESP_FORMAT_HASH; 457 rxq_data->mcqe_format = cq_attr.mini_cqe_res_format; 458 break; 459 case MLX5_CQE_RESP_FORMAT_FTAG_STRIDX: 460 rxq_data->byte_mask = MLX5_LEN_WITH_MARK_MASK; 461 /* fallthrough */ 462 case MLX5_CQE_RESP_FORMAT_CSUM_STRIDX: 463 cq_attr.mini_cqe_res_format = priv->config.cqe_comp_fmt; 464 break; 465 case MLX5_CQE_RESP_FORMAT_L34H_STRIDX: 466 cq_attr.mini_cqe_res_format = 0; 467 cq_attr.mini_cqe_res_format_ext = 1; 468 break; 469 } 470 DRV_LOG(DEBUG, 471 "Port %u Rx CQE compression is enabled, format %d.", 472 dev->data->port_id, priv->config.cqe_comp_fmt); 473 /* 474 * For vectorized Rx, it must not be doubled in order to 475 * make cq_ci and rq_ci aligned. 476 */ 477 if (mlx5_rxq_check_vec_support(rxq_data) < 0) 478 cqe_n *= 2; 479 } else if (priv->config.cqe_comp && rxq_data->hw_timestamp) { 480 DRV_LOG(DEBUG, 481 "Port %u Rx CQE compression is disabled for HW" 482 " timestamp.", 483 dev->data->port_id); 484 } else if (priv->config.cqe_comp && rxq_data->lro) { 485 DRV_LOG(DEBUG, 486 "Port %u Rx CQE compression is disabled for LRO.", 487 dev->data->port_id); 488 } 489 if (priv->config.cqe_pad) 490 cq_attr.cqe_size = MLX5_CQE_SIZE_128B; 491 log_cqe_n = log2above(cqe_n); 492 cq_size = sizeof(struct mlx5_cqe) * (1 << log_cqe_n); 493 buf = rte_calloc_socket(__func__, 1, cq_size, page_size, 494 rxq_ctrl->socket); 495 if (!buf) { 496 DRV_LOG(ERR, "Failed to allocate memory for CQ."); 497 goto error; 498 } 499 rxq_data->cqes = (volatile struct mlx5_cqe (*)[])(uintptr_t)buf; 500 rxq_ctrl->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx, buf, 501 cq_size, 502 IBV_ACCESS_LOCAL_WRITE); 503 if (!rxq_ctrl->cq_umem) { 504 DRV_LOG(ERR, "Failed to register umem for CQ."); 505 goto error; 506 } 507 /* Allocate CQ door-bell. */ 508 dbr_offset = mlx5_get_dbr(priv->sh->ctx, &priv->dbrpgs, &dbr_page); 509 if (dbr_offset < 0) { 510 DRV_LOG(ERR, "Failed to allocate CQ door-bell."); 511 goto error; 512 } 513 rxq_ctrl->cq_dbr_offset = dbr_offset; 514 rxq_ctrl->cq_dbrec_page = dbr_page; 515 rxq_data->cq_db = (uint32_t *)((uintptr_t)dbr_page->dbrs + 516 (uintptr_t)rxq_ctrl->cq_dbr_offset); 517 rxq_data->cq_uar = 518 mlx5_os_get_devx_uar_base_addr(priv->sh->devx_rx_uar); 519 /* Create CQ using DevX API. */ 520 cq_attr.eqn = priv->sh->eqn; 521 cq_attr.uar_page_id = 522 mlx5_os_get_devx_uar_page_id(priv->sh->devx_rx_uar); 523 cq_attr.q_umem_id = mlx5_os_get_umem_id(rxq_ctrl->cq_umem); 524 cq_attr.q_umem_valid = 1; 525 cq_attr.log_cq_size = log_cqe_n; 526 cq_attr.log_page_size = rte_log2_u32(page_size); 527 cq_attr.db_umem_offset = rxq_ctrl->cq_dbr_offset; 528 cq_attr.db_umem_id = mlx5_os_get_umem_id(dbr_page->umem); 529 cq_attr.db_umem_valid = 1; 530 cq_obj = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr); 531 if (!cq_obj) 532 goto error; 533 rxq_data->cqe_n = log_cqe_n; 534 rxq_data->cqn = cq_obj->id; 535 if (rxq_ctrl->obj->devx_channel) { 536 ret = mlx5_glue->devx_subscribe_devx_event 537 (rxq_ctrl->obj->devx_channel, 538 cq_obj->obj, 539 sizeof(event_nums), 540 event_nums, 541 (uint64_t)(uintptr_t)cq_obj); 542 if (ret) { 543 DRV_LOG(ERR, "Fail to subscribe CQ to event channel."); 544 rte_errno = errno; 545 goto error; 546 } 547 } 548 /* Initialise CQ to 1's to mark HW ownership for all CQEs. */ 549 memset((void *)(uintptr_t)rxq_data->cqes, 0xFF, cq_size); 550 return cq_obj; 551 error: 552 if (cq_obj) 553 mlx5_devx_cmd_destroy(cq_obj); 554 mlx5_rxq_release_devx_cq_resources(rxq_ctrl); 555 return NULL; 556 } 557 558 /** 559 * Create the Rx hairpin queue object. 560 * 561 * @param dev 562 * Pointer to Ethernet device. 563 * @param idx 564 * Queue index in DPDK Rx queue array. 565 * 566 * @return 567 * 0 on success, a negative errno value otherwise and rte_errno is set. 568 */ 569 static int 570 mlx5_rxq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx) 571 { 572 struct mlx5_priv *priv = dev->data->dev_private; 573 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx]; 574 struct mlx5_rxq_ctrl *rxq_ctrl = 575 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); 576 struct mlx5_devx_create_rq_attr attr = { 0 }; 577 struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj; 578 uint32_t max_wq_data; 579 580 MLX5_ASSERT(rxq_data); 581 MLX5_ASSERT(tmpl); 582 tmpl->rxq_ctrl = rxq_ctrl; 583 attr.hairpin = 1; 584 max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz; 585 /* Jumbo frames > 9KB should be supported, and more packets. */ 586 if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) { 587 if (priv->config.log_hp_size > max_wq_data) { 588 DRV_LOG(ERR, "Total data size %u power of 2 is " 589 "too large for hairpin.", 590 priv->config.log_hp_size); 591 rte_errno = ERANGE; 592 return -rte_errno; 593 } 594 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size; 595 } else { 596 attr.wq_attr.log_hairpin_data_sz = 597 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ? 598 max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE; 599 } 600 /* Set the packets number to the maximum value for performance. */ 601 attr.wq_attr.log_hairpin_num_packets = 602 attr.wq_attr.log_hairpin_data_sz - 603 MLX5_HAIRPIN_QUEUE_STRIDE; 604 tmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &attr, 605 rxq_ctrl->socket); 606 if (!tmpl->rq) { 607 DRV_LOG(ERR, 608 "Port %u Rx hairpin queue %u can't create rq object.", 609 dev->data->port_id, idx); 610 rte_errno = errno; 611 return -rte_errno; 612 } 613 dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_HAIRPIN; 614 return 0; 615 } 616 617 /** 618 * Create the Rx queue DevX object. 619 * 620 * @param dev 621 * Pointer to Ethernet device. 622 * @param idx 623 * Queue index in DPDK Rx queue array. 624 * 625 * @return 626 * 0 on success, a negative errno value otherwise and rte_errno is set. 627 */ 628 static int 629 mlx5_rxq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx) 630 { 631 struct mlx5_priv *priv = dev->data->dev_private; 632 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx]; 633 struct mlx5_rxq_ctrl *rxq_ctrl = 634 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); 635 struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj; 636 int ret = 0; 637 638 MLX5_ASSERT(rxq_data); 639 MLX5_ASSERT(tmpl); 640 if (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN) 641 return mlx5_rxq_obj_hairpin_new(dev, idx); 642 tmpl->rxq_ctrl = rxq_ctrl; 643 if (rxq_ctrl->irq) { 644 int devx_ev_flag = 645 MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA; 646 647 tmpl->devx_channel = mlx5_glue->devx_create_event_channel 648 (priv->sh->ctx, 649 devx_ev_flag); 650 if (!tmpl->devx_channel) { 651 rte_errno = errno; 652 DRV_LOG(ERR, "Failed to create event channel %d.", 653 rte_errno); 654 goto error; 655 } 656 tmpl->fd = mlx5_os_get_devx_channel_fd(tmpl->devx_channel); 657 } 658 /* Create CQ using DevX API. */ 659 tmpl->devx_cq = mlx5_rxq_create_devx_cq_resources(dev, idx); 660 if (!tmpl->devx_cq) { 661 DRV_LOG(ERR, "Failed to create CQ."); 662 goto error; 663 } 664 /* Create RQ using DevX API. */ 665 tmpl->rq = mlx5_rxq_create_devx_rq_resources(dev, idx); 666 if (!tmpl->rq) { 667 DRV_LOG(ERR, "Port %u Rx queue %u RQ creation failure.", 668 dev->data->port_id, idx); 669 rte_errno = ENOMEM; 670 goto error; 671 } 672 /* Change queue state to ready. */ 673 ret = mlx5_devx_modify_rq(tmpl, MLX5_RXQ_MOD_RST2RDY); 674 if (ret) 675 goto error; 676 rxq_data->cq_arm_sn = 0; 677 mlx5_rxq_initialize(rxq_data); 678 rxq_data->cq_ci = 0; 679 dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED; 680 rxq_ctrl->wqn = tmpl->rq->id; 681 return 0; 682 error: 683 ret = rte_errno; /* Save rte_errno before cleanup. */ 684 if (tmpl->rq) 685 claim_zero(mlx5_devx_cmd_destroy(tmpl->rq)); 686 if (tmpl->devx_cq) 687 claim_zero(mlx5_devx_cmd_destroy(tmpl->devx_cq)); 688 if (tmpl->devx_channel) 689 mlx5_glue->devx_destroy_event_channel(tmpl->devx_channel); 690 mlx5_rxq_release_devx_rq_resources(rxq_ctrl); 691 mlx5_rxq_release_devx_cq_resources(rxq_ctrl); 692 rte_errno = ret; /* Restore rte_errno. */ 693 return -rte_errno; 694 } 695 696 /** 697 * Create RQT using DevX API as a filed of indirection table. 698 * 699 * @param dev 700 * Pointer to Ethernet device. 701 * @param log_n 702 * Log of number of queues in the array. 703 * @param ind_tbl 704 * DevX indirection table object. 705 * 706 * @return 707 * 0 on success, a negative errno value otherwise and rte_errno is set. 708 */ 709 static int 710 mlx5_devx_ind_table_new(struct rte_eth_dev *dev, const unsigned int log_n, 711 struct mlx5_ind_table_obj *ind_tbl) 712 { 713 struct mlx5_priv *priv = dev->data->dev_private; 714 struct mlx5_devx_rqt_attr *rqt_attr = NULL; 715 const unsigned int rqt_n = 1 << log_n; 716 unsigned int i, j; 717 718 MLX5_ASSERT(ind_tbl); 719 rqt_attr = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rqt_attr) + 720 rqt_n * sizeof(uint32_t), 0, SOCKET_ID_ANY); 721 if (!rqt_attr) { 722 DRV_LOG(ERR, "Port %u cannot allocate RQT resources.", 723 dev->data->port_id); 724 rte_errno = ENOMEM; 725 return -rte_errno; 726 } 727 rqt_attr->rqt_max_size = priv->config.ind_table_max_size; 728 rqt_attr->rqt_actual_size = rqt_n; 729 for (i = 0; i != ind_tbl->queues_n; ++i) { 730 struct mlx5_rxq_data *rxq = (*priv->rxqs)[ind_tbl->queues[i]]; 731 struct mlx5_rxq_ctrl *rxq_ctrl = 732 container_of(rxq, struct mlx5_rxq_ctrl, rxq); 733 734 rqt_attr->rq_list[i] = rxq_ctrl->obj->rq->id; 735 } 736 MLX5_ASSERT(i > 0); 737 for (j = 0; i != rqt_n; ++j, ++i) 738 rqt_attr->rq_list[i] = rqt_attr->rq_list[j]; 739 ind_tbl->rqt = mlx5_devx_cmd_create_rqt(priv->sh->ctx, rqt_attr); 740 mlx5_free(rqt_attr); 741 if (!ind_tbl->rqt) { 742 DRV_LOG(ERR, "Port %u cannot create DevX RQT.", 743 dev->data->port_id); 744 rte_errno = errno; 745 return -rte_errno; 746 } 747 return 0; 748 } 749 750 /** 751 * Destroy the DevX RQT object. 752 * 753 * @param ind_table 754 * Indirection table to release. 755 */ 756 static void 757 mlx5_devx_ind_table_destroy(struct mlx5_ind_table_obj *ind_tbl) 758 { 759 claim_zero(mlx5_devx_cmd_destroy(ind_tbl->rqt)); 760 } 761 762 /** 763 * Set TIR attribute struct with relevant input values. 764 * 765 * @param[in] dev 766 * Pointer to Ethernet device. 767 * @param[in] rss_key 768 * RSS key for the Rx hash queue. 769 * @param[in] hash_fields 770 * Verbs protocol hash field to make the RSS on. 771 * @param[in] ind_tbl 772 * Indirection table for TIR. 773 * @param[in] tunnel 774 * Tunnel type. 775 * @param[out] tir_attr 776 * Parameters structure for TIR creation/modification. 777 * 778 * @return 779 * The Verbs/DevX object initialised index, 0 otherwise and rte_errno is set. 780 */ 781 static void 782 mlx5_devx_tir_attr_set(struct rte_eth_dev *dev, const uint8_t *rss_key, 783 uint64_t hash_fields, 784 const struct mlx5_ind_table_obj *ind_tbl, 785 int tunnel, struct mlx5_devx_tir_attr *tir_attr) 786 { 787 struct mlx5_priv *priv = dev->data->dev_private; 788 struct mlx5_rxq_data *rxq_data = (*priv->rxqs)[ind_tbl->queues[0]]; 789 struct mlx5_rxq_ctrl *rxq_ctrl = 790 container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); 791 enum mlx5_rxq_type rxq_obj_type = rxq_ctrl->type; 792 bool lro = true; 793 uint32_t i; 794 795 /* Enable TIR LRO only if all the queues were configured for. */ 796 for (i = 0; i < ind_tbl->queues_n; ++i) { 797 if (!(*priv->rxqs)[ind_tbl->queues[i]]->lro) { 798 lro = false; 799 break; 800 } 801 } 802 memset(tir_attr, 0, sizeof(*tir_attr)); 803 tir_attr->disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT; 804 tir_attr->rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ; 805 tir_attr->tunneled_offload_en = !!tunnel; 806 /* If needed, translate hash_fields bitmap to PRM format. */ 807 if (hash_fields) { 808 struct mlx5_rx_hash_field_select *rx_hash_field_select = 809 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT 810 hash_fields & IBV_RX_HASH_INNER ? 811 &tir_attr->rx_hash_field_selector_inner : 812 #endif 813 &tir_attr->rx_hash_field_selector_outer; 814 /* 1 bit: 0: IPv4, 1: IPv6. */ 815 rx_hash_field_select->l3_prot_type = 816 !!(hash_fields & MLX5_IPV6_IBV_RX_HASH); 817 /* 1 bit: 0: TCP, 1: UDP. */ 818 rx_hash_field_select->l4_prot_type = 819 !!(hash_fields & MLX5_UDP_IBV_RX_HASH); 820 /* Bitmask which sets which fields to use in RX Hash. */ 821 rx_hash_field_select->selected_fields = 822 ((!!(hash_fields & MLX5_L3_SRC_IBV_RX_HASH)) << 823 MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) | 824 (!!(hash_fields & MLX5_L3_DST_IBV_RX_HASH)) << 825 MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP | 826 (!!(hash_fields & MLX5_L4_SRC_IBV_RX_HASH)) << 827 MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT | 828 (!!(hash_fields & MLX5_L4_DST_IBV_RX_HASH)) << 829 MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT; 830 } 831 if (rxq_obj_type == MLX5_RXQ_TYPE_HAIRPIN) 832 tir_attr->transport_domain = priv->sh->td->id; 833 else 834 tir_attr->transport_domain = priv->sh->tdn; 835 memcpy(tir_attr->rx_hash_toeplitz_key, rss_key, MLX5_RSS_HASH_KEY_LEN); 836 tir_attr->indirect_table = ind_tbl->rqt->id; 837 if (dev->data->dev_conf.lpbk_mode) 838 tir_attr->self_lb_block = 839 MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; 840 if (lro) { 841 tir_attr->lro_timeout_period_usecs = priv->config.lro.timeout; 842 tir_attr->lro_max_msg_sz = priv->max_lro_msg_size; 843 tir_attr->lro_enable_mask = 844 MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | 845 MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO; 846 } 847 } 848 849 /** 850 * Create an Rx Hash queue. 851 * 852 * @param dev 853 * Pointer to Ethernet device. 854 * @param hrxq 855 * Pointer to Rx Hash queue. 856 * @param tunnel 857 * Tunnel type. 858 * 859 * @return 860 * 0 on success, a negative errno value otherwise and rte_errno is set. 861 */ 862 static int 863 mlx5_devx_hrxq_new(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq, 864 int tunnel __rte_unused) 865 { 866 struct mlx5_priv *priv = dev->data->dev_private; 867 struct mlx5_devx_tir_attr tir_attr = {0}; 868 int err; 869 870 mlx5_devx_tir_attr_set(dev, hrxq->rss_key, hrxq->hash_fields, 871 hrxq->ind_table, tunnel, &tir_attr); 872 hrxq->tir = mlx5_devx_cmd_create_tir(priv->sh->ctx, &tir_attr); 873 if (!hrxq->tir) { 874 DRV_LOG(ERR, "Port %u cannot create DevX TIR.", 875 dev->data->port_id); 876 rte_errno = errno; 877 goto error; 878 } 879 #ifdef HAVE_IBV_FLOW_DV_SUPPORT 880 hrxq->action = mlx5_glue->dv_create_flow_action_dest_devx_tir 881 (hrxq->tir->obj); 882 if (!hrxq->action) { 883 rte_errno = errno; 884 goto error; 885 } 886 #endif 887 return 0; 888 error: 889 err = rte_errno; /* Save rte_errno before cleanup. */ 890 if (hrxq->tir) 891 claim_zero(mlx5_devx_cmd_destroy(hrxq->tir)); 892 rte_errno = err; /* Restore rte_errno. */ 893 return -rte_errno; 894 } 895 896 /** 897 * Destroy a DevX TIR object. 898 * 899 * @param hrxq 900 * Hash Rx queue to release its tir. 901 */ 902 static void 903 mlx5_devx_tir_destroy(struct mlx5_hrxq *hrxq) 904 { 905 claim_zero(mlx5_devx_cmd_destroy(hrxq->tir)); 906 } 907 908 /** 909 * Modify an Rx Hash queue configuration. 910 * 911 * @param dev 912 * Pointer to Ethernet device. 913 * @param hrxq 914 * Hash Rx queue to modify. 915 * @param rss_key 916 * RSS key for the Rx hash queue. 917 * @param hash_fields 918 * Verbs protocol hash field to make the RSS on. 919 * @param[in] ind_tbl 920 * Indirection table for TIR. 921 * 922 * @return 923 * 0 on success, a negative errno value otherwise and rte_errno is set. 924 */ 925 static int 926 mlx5_devx_hrxq_modify(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq, 927 const uint8_t *rss_key, 928 uint64_t hash_fields, 929 const struct mlx5_ind_table_obj *ind_tbl) 930 { 931 struct mlx5_devx_modify_tir_attr modify_tir = {0}; 932 933 /* 934 * untested for modification fields: 935 * - rx_hash_symmetric not set in hrxq_new(), 936 * - rx_hash_fn set hard-coded in hrxq_new(), 937 * - lro_xxx not set after rxq setup 938 */ 939 if (ind_tbl != hrxq->ind_table) 940 modify_tir.modify_bitmask |= 941 MLX5_MODIFY_TIR_IN_MODIFY_BITMASK_INDIRECT_TABLE; 942 if (hash_fields != hrxq->hash_fields || 943 memcmp(hrxq->rss_key, rss_key, MLX5_RSS_HASH_KEY_LEN)) 944 modify_tir.modify_bitmask |= 945 MLX5_MODIFY_TIR_IN_MODIFY_BITMASK_HASH; 946 mlx5_devx_tir_attr_set(dev, rss_key, hash_fields, ind_tbl, 947 0, /* N/A - tunnel modification unsupported */ 948 &modify_tir.tir); 949 modify_tir.tirn = hrxq->tir->id; 950 if (mlx5_devx_cmd_modify_tir(hrxq->tir, &modify_tir)) { 951 DRV_LOG(ERR, "port %u cannot modify DevX TIR", 952 dev->data->port_id); 953 rte_errno = errno; 954 return -rte_errno; 955 } 956 return 0; 957 } 958 959 /** 960 * Create a DevX drop action for Rx Hash queue. 961 * 962 * @param dev 963 * Pointer to Ethernet device. 964 * 965 * @return 966 * 0 on success, a negative errno value otherwise and rte_errno is set. 967 */ 968 static int 969 mlx5_devx_drop_action_create(struct rte_eth_dev *dev) 970 { 971 (void)dev; 972 DRV_LOG(ERR, "DevX drop action is not supported yet."); 973 rte_errno = ENOTSUP; 974 return -rte_errno; 975 } 976 977 /** 978 * Release a drop hash Rx queue. 979 * 980 * @param dev 981 * Pointer to Ethernet device. 982 */ 983 static void 984 mlx5_devx_drop_action_destroy(struct rte_eth_dev *dev) 985 { 986 (void)dev; 987 DRV_LOG(ERR, "DevX drop action is not supported yet."); 988 rte_errno = ENOTSUP; 989 } 990 991 /** 992 * Create the Tx hairpin queue object. 993 * 994 * @param dev 995 * Pointer to Ethernet device. 996 * @param idx 997 * Queue index in DPDK Tx queue array. 998 * 999 * @return 1000 * 0 on success, a negative errno value otherwise and rte_errno is set. 1001 */ 1002 static int 1003 mlx5_txq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx) 1004 { 1005 struct mlx5_priv *priv = dev->data->dev_private; 1006 struct mlx5_txq_data *txq_data = (*priv->txqs)[idx]; 1007 struct mlx5_txq_ctrl *txq_ctrl = 1008 container_of(txq_data, struct mlx5_txq_ctrl, txq); 1009 struct mlx5_devx_create_sq_attr attr = { 0 }; 1010 struct mlx5_txq_obj *tmpl = txq_ctrl->obj; 1011 uint32_t max_wq_data; 1012 1013 MLX5_ASSERT(txq_data); 1014 MLX5_ASSERT(tmpl); 1015 tmpl->txq_ctrl = txq_ctrl; 1016 attr.hairpin = 1; 1017 attr.tis_lst_sz = 1; 1018 max_wq_data = priv->config.hca_attr.log_max_hairpin_wq_data_sz; 1019 /* Jumbo frames > 9KB should be supported, and more packets. */ 1020 if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) { 1021 if (priv->config.log_hp_size > max_wq_data) { 1022 DRV_LOG(ERR, "Total data size %u power of 2 is " 1023 "too large for hairpin.", 1024 priv->config.log_hp_size); 1025 rte_errno = ERANGE; 1026 return -rte_errno; 1027 } 1028 attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size; 1029 } else { 1030 attr.wq_attr.log_hairpin_data_sz = 1031 (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ? 1032 max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE; 1033 } 1034 /* Set the packets number to the maximum value for performance. */ 1035 attr.wq_attr.log_hairpin_num_packets = 1036 attr.wq_attr.log_hairpin_data_sz - 1037 MLX5_HAIRPIN_QUEUE_STRIDE; 1038 attr.tis_num = priv->sh->tis->id; 1039 tmpl->sq = mlx5_devx_cmd_create_sq(priv->sh->ctx, &attr); 1040 if (!tmpl->sq) { 1041 DRV_LOG(ERR, 1042 "Port %u tx hairpin queue %u can't create SQ object.", 1043 dev->data->port_id, idx); 1044 rte_errno = errno; 1045 return -rte_errno; 1046 } 1047 return 0; 1048 } 1049 1050 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET 1051 /** 1052 * Release DevX SQ resources. 1053 * 1054 * @param txq_obj 1055 * DevX Tx queue object. 1056 */ 1057 static void 1058 mlx5_txq_release_devx_sq_resources(struct mlx5_txq_obj *txq_obj) 1059 { 1060 if (txq_obj->sq_devx) { 1061 claim_zero(mlx5_devx_cmd_destroy(txq_obj->sq_devx)); 1062 txq_obj->sq_devx = NULL; 1063 } 1064 if (txq_obj->sq_umem) { 1065 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->sq_umem)); 1066 txq_obj->sq_umem = NULL; 1067 } 1068 if (txq_obj->sq_buf) { 1069 mlx5_free(txq_obj->sq_buf); 1070 txq_obj->sq_buf = NULL; 1071 } 1072 if (txq_obj->sq_dbrec_page) { 1073 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs, 1074 mlx5_os_get_umem_id 1075 (txq_obj->sq_dbrec_page->umem), 1076 txq_obj->sq_dbrec_offset)); 1077 txq_obj->sq_dbrec_page = NULL; 1078 } 1079 } 1080 1081 /** 1082 * Release DevX Tx CQ resources. 1083 * 1084 * @param txq_obj 1085 * DevX Tx queue object. 1086 */ 1087 static void 1088 mlx5_txq_release_devx_cq_resources(struct mlx5_txq_obj *txq_obj) 1089 { 1090 if (txq_obj->cq_devx) 1091 claim_zero(mlx5_devx_cmd_destroy(txq_obj->cq_devx)); 1092 if (txq_obj->cq_umem) 1093 claim_zero(mlx5_glue->devx_umem_dereg(txq_obj->cq_umem)); 1094 if (txq_obj->cq_buf) 1095 mlx5_free(txq_obj->cq_buf); 1096 if (txq_obj->cq_dbrec_page) 1097 claim_zero(mlx5_release_dbr(&txq_obj->txq_ctrl->priv->dbrpgs, 1098 mlx5_os_get_umem_id 1099 (txq_obj->cq_dbrec_page->umem), 1100 txq_obj->cq_dbrec_offset)); 1101 } 1102 1103 /** 1104 * Destroy the Tx queue DevX object. 1105 * 1106 * @param txq_obj 1107 * Txq object to destroy. 1108 */ 1109 static void 1110 mlx5_txq_release_devx_resources(struct mlx5_txq_obj *txq_obj) 1111 { 1112 mlx5_txq_release_devx_cq_resources(txq_obj); 1113 mlx5_txq_release_devx_sq_resources(txq_obj); 1114 } 1115 1116 /** 1117 * Create a DevX CQ object and its resources for an Tx queue. 1118 * 1119 * @param dev 1120 * Pointer to Ethernet device. 1121 * @param idx 1122 * Queue index in DPDK Tx queue array. 1123 * 1124 * @return 1125 * Number of CQEs in CQ, 0 otherwise and rte_errno is set. 1126 */ 1127 static uint32_t 1128 mlx5_txq_create_devx_cq_resources(struct rte_eth_dev *dev, uint16_t idx) 1129 { 1130 struct mlx5_priv *priv = dev->data->dev_private; 1131 struct mlx5_txq_data *txq_data = (*priv->txqs)[idx]; 1132 struct mlx5_txq_ctrl *txq_ctrl = 1133 container_of(txq_data, struct mlx5_txq_ctrl, txq); 1134 struct mlx5_txq_obj *txq_obj = txq_ctrl->obj; 1135 struct mlx5_devx_cq_attr cq_attr = { 0 }; 1136 struct mlx5_cqe *cqe; 1137 size_t page_size; 1138 size_t alignment; 1139 uint32_t cqe_n; 1140 uint32_t i; 1141 int ret; 1142 1143 MLX5_ASSERT(txq_data); 1144 MLX5_ASSERT(txq_obj); 1145 page_size = rte_mem_page_size(); 1146 if (page_size == (size_t)-1) { 1147 DRV_LOG(ERR, "Failed to get mem page size."); 1148 rte_errno = ENOMEM; 1149 return 0; 1150 } 1151 /* Allocate memory buffer for CQEs. */ 1152 alignment = MLX5_CQE_BUF_ALIGNMENT; 1153 if (alignment == (size_t)-1) { 1154 DRV_LOG(ERR, "Failed to get CQE buf alignment."); 1155 rte_errno = ENOMEM; 1156 return 0; 1157 } 1158 /* Create the Completion Queue. */ 1159 cqe_n = (1UL << txq_data->elts_n) / MLX5_TX_COMP_THRESH + 1160 1 + MLX5_TX_COMP_THRESH_INLINE_DIV; 1161 cqe_n = 1UL << log2above(cqe_n); 1162 if (cqe_n > UINT16_MAX) { 1163 DRV_LOG(ERR, 1164 "Port %u Tx queue %u requests to many CQEs %u.", 1165 dev->data->port_id, txq_data->idx, cqe_n); 1166 rte_errno = EINVAL; 1167 return 0; 1168 } 1169 txq_obj->cq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, 1170 cqe_n * sizeof(struct mlx5_cqe), 1171 alignment, 1172 priv->sh->numa_node); 1173 if (!txq_obj->cq_buf) { 1174 DRV_LOG(ERR, 1175 "Port %u Tx queue %u cannot allocate memory (CQ).", 1176 dev->data->port_id, txq_data->idx); 1177 rte_errno = ENOMEM; 1178 return 0; 1179 } 1180 /* Register allocated buffer in user space with DevX. */ 1181 txq_obj->cq_umem = mlx5_glue->devx_umem_reg(priv->sh->ctx, 1182 (void *)txq_obj->cq_buf, 1183 cqe_n * sizeof(struct mlx5_cqe), 1184 IBV_ACCESS_LOCAL_WRITE); 1185 if (!txq_obj->cq_umem) { 1186 rte_errno = errno; 1187 DRV_LOG(ERR, 1188 "Port %u Tx queue %u cannot register memory (CQ).", 1189 dev->data->port_id, txq_data->idx); 1190 goto error; 1191 } 1192 /* Allocate doorbell record for completion queue. */ 1193 txq_obj->cq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx, 1194 &priv->dbrpgs, 1195 &txq_obj->cq_dbrec_page); 1196 if (txq_obj->cq_dbrec_offset < 0) { 1197 rte_errno = errno; 1198 DRV_LOG(ERR, "Failed to allocate CQ door-bell."); 1199 goto error; 1200 } 1201 cq_attr.cqe_size = (sizeof(struct mlx5_cqe) == 128) ? 1202 MLX5_CQE_SIZE_128B : MLX5_CQE_SIZE_64B; 1203 cq_attr.uar_page_id = mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar); 1204 cq_attr.eqn = priv->sh->eqn; 1205 cq_attr.q_umem_valid = 1; 1206 cq_attr.q_umem_offset = (uintptr_t)txq_obj->cq_buf % page_size; 1207 cq_attr.q_umem_id = mlx5_os_get_umem_id(txq_obj->cq_umem); 1208 cq_attr.db_umem_valid = 1; 1209 cq_attr.db_umem_offset = txq_obj->cq_dbrec_offset; 1210 cq_attr.db_umem_id = mlx5_os_get_umem_id(txq_obj->cq_dbrec_page->umem); 1211 cq_attr.log_cq_size = rte_log2_u32(cqe_n); 1212 cq_attr.log_page_size = rte_log2_u32(page_size); 1213 /* Create completion queue object with DevX. */ 1214 txq_obj->cq_devx = mlx5_devx_cmd_create_cq(priv->sh->ctx, &cq_attr); 1215 if (!txq_obj->cq_devx) { 1216 rte_errno = errno; 1217 DRV_LOG(ERR, "Port %u Tx queue %u CQ creation failure.", 1218 dev->data->port_id, idx); 1219 goto error; 1220 } 1221 /* Initial fill CQ buffer with invalid CQE opcode. */ 1222 cqe = (struct mlx5_cqe *)txq_obj->cq_buf; 1223 for (i = 0; i < cqe_n; i++) { 1224 cqe->op_own = (MLX5_CQE_INVALID << 4) | MLX5_CQE_OWNER_MASK; 1225 ++cqe; 1226 } 1227 return cqe_n; 1228 error: 1229 ret = rte_errno; 1230 mlx5_txq_release_devx_cq_resources(txq_obj); 1231 rte_errno = ret; 1232 return 0; 1233 } 1234 1235 /** 1236 * Create a SQ object and its resources using DevX. 1237 * 1238 * @param dev 1239 * Pointer to Ethernet device. 1240 * @param idx 1241 * Queue index in DPDK Tx queue array. 1242 * 1243 * @return 1244 * Number of WQEs in SQ, 0 otherwise and rte_errno is set. 1245 */ 1246 static uint32_t 1247 mlx5_txq_create_devx_sq_resources(struct rte_eth_dev *dev, uint16_t idx) 1248 { 1249 struct mlx5_priv *priv = dev->data->dev_private; 1250 struct mlx5_txq_data *txq_data = (*priv->txqs)[idx]; 1251 struct mlx5_txq_ctrl *txq_ctrl = 1252 container_of(txq_data, struct mlx5_txq_ctrl, txq); 1253 struct mlx5_txq_obj *txq_obj = txq_ctrl->obj; 1254 struct mlx5_devx_create_sq_attr sq_attr = { 0 }; 1255 size_t page_size; 1256 uint32_t wqe_n; 1257 int ret; 1258 1259 MLX5_ASSERT(txq_data); 1260 MLX5_ASSERT(txq_obj); 1261 page_size = rte_mem_page_size(); 1262 if (page_size == (size_t)-1) { 1263 DRV_LOG(ERR, "Failed to get mem page size."); 1264 rte_errno = ENOMEM; 1265 return 0; 1266 } 1267 wqe_n = RTE_MIN(1UL << txq_data->elts_n, 1268 (uint32_t)priv->sh->device_attr.max_qp_wr); 1269 txq_obj->sq_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, 1270 wqe_n * sizeof(struct mlx5_wqe), 1271 page_size, priv->sh->numa_node); 1272 if (!txq_obj->sq_buf) { 1273 DRV_LOG(ERR, 1274 "Port %u Tx queue %u cannot allocate memory (SQ).", 1275 dev->data->port_id, txq_data->idx); 1276 rte_errno = ENOMEM; 1277 goto error; 1278 } 1279 /* Register allocated buffer in user space with DevX. */ 1280 txq_obj->sq_umem = mlx5_glue->devx_umem_reg 1281 (priv->sh->ctx, 1282 (void *)txq_obj->sq_buf, 1283 wqe_n * sizeof(struct mlx5_wqe), 1284 IBV_ACCESS_LOCAL_WRITE); 1285 if (!txq_obj->sq_umem) { 1286 rte_errno = errno; 1287 DRV_LOG(ERR, 1288 "Port %u Tx queue %u cannot register memory (SQ).", 1289 dev->data->port_id, txq_data->idx); 1290 goto error; 1291 } 1292 /* Allocate doorbell record for send queue. */ 1293 txq_obj->sq_dbrec_offset = mlx5_get_dbr(priv->sh->ctx, 1294 &priv->dbrpgs, 1295 &txq_obj->sq_dbrec_page); 1296 if (txq_obj->sq_dbrec_offset < 0) { 1297 rte_errno = errno; 1298 DRV_LOG(ERR, "Failed to allocate SQ door-bell."); 1299 goto error; 1300 } 1301 sq_attr.tis_lst_sz = 1; 1302 sq_attr.tis_num = priv->sh->tis->id; 1303 sq_attr.state = MLX5_SQC_STATE_RST; 1304 sq_attr.cqn = txq_obj->cq_devx->id; 1305 sq_attr.flush_in_error_en = 1; 1306 sq_attr.allow_multi_pkt_send_wqe = !!priv->config.mps; 1307 sq_attr.allow_swp = !!priv->config.swp; 1308 sq_attr.min_wqe_inline_mode = priv->config.hca_attr.vport_inline_mode; 1309 sq_attr.wq_attr.uar_page = 1310 mlx5_os_get_devx_uar_page_id(priv->sh->tx_uar); 1311 sq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC; 1312 sq_attr.wq_attr.pd = priv->sh->pdn; 1313 sq_attr.wq_attr.log_wq_stride = rte_log2_u32(MLX5_WQE_SIZE); 1314 sq_attr.wq_attr.log_wq_sz = log2above(wqe_n); 1315 sq_attr.wq_attr.dbr_umem_valid = 1; 1316 sq_attr.wq_attr.dbr_addr = txq_obj->sq_dbrec_offset; 1317 sq_attr.wq_attr.dbr_umem_id = 1318 mlx5_os_get_umem_id(txq_obj->sq_dbrec_page->umem); 1319 sq_attr.wq_attr.wq_umem_valid = 1; 1320 sq_attr.wq_attr.wq_umem_id = mlx5_os_get_umem_id(txq_obj->sq_umem); 1321 sq_attr.wq_attr.wq_umem_offset = (uintptr_t)txq_obj->sq_buf % page_size; 1322 /* Create Send Queue object with DevX. */ 1323 txq_obj->sq_devx = mlx5_devx_cmd_create_sq(priv->sh->ctx, &sq_attr); 1324 if (!txq_obj->sq_devx) { 1325 rte_errno = errno; 1326 DRV_LOG(ERR, "Port %u Tx queue %u SQ creation failure.", 1327 dev->data->port_id, idx); 1328 goto error; 1329 } 1330 return wqe_n; 1331 error: 1332 ret = rte_errno; 1333 mlx5_txq_release_devx_sq_resources(txq_obj); 1334 rte_errno = ret; 1335 return 0; 1336 } 1337 #endif 1338 1339 /** 1340 * Create the Tx queue DevX object. 1341 * 1342 * @param dev 1343 * Pointer to Ethernet device. 1344 * @param idx 1345 * Queue index in DPDK Tx queue array. 1346 * 1347 * @return 1348 * 0 on success, a negative errno value otherwise and rte_errno is set. 1349 */ 1350 int 1351 mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx) 1352 { 1353 struct mlx5_priv *priv = dev->data->dev_private; 1354 struct mlx5_txq_data *txq_data = (*priv->txqs)[idx]; 1355 struct mlx5_txq_ctrl *txq_ctrl = 1356 container_of(txq_data, struct mlx5_txq_ctrl, txq); 1357 1358 if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) 1359 return mlx5_txq_obj_hairpin_new(dev, idx); 1360 #ifndef HAVE_MLX5DV_DEVX_UAR_OFFSET 1361 DRV_LOG(ERR, "Port %u Tx queue %u cannot create with DevX, no UAR.", 1362 dev->data->port_id, idx); 1363 rte_errno = ENOMEM; 1364 return -rte_errno; 1365 #else 1366 struct mlx5_dev_ctx_shared *sh = priv->sh; 1367 struct mlx5_txq_obj *txq_obj = txq_ctrl->obj; 1368 void *reg_addr; 1369 uint32_t cqe_n; 1370 uint32_t wqe_n; 1371 int ret = 0; 1372 1373 MLX5_ASSERT(txq_data); 1374 MLX5_ASSERT(txq_obj); 1375 txq_obj->txq_ctrl = txq_ctrl; 1376 txq_obj->dev = dev; 1377 cqe_n = mlx5_txq_create_devx_cq_resources(dev, idx); 1378 if (!cqe_n) { 1379 rte_errno = errno; 1380 goto error; 1381 } 1382 txq_data->cqe_n = log2above(cqe_n); 1383 txq_data->cqe_s = 1 << txq_data->cqe_n; 1384 txq_data->cqe_m = txq_data->cqe_s - 1; 1385 txq_data->cqes = (volatile struct mlx5_cqe *)txq_obj->cq_buf; 1386 txq_data->cq_ci = 0; 1387 txq_data->cq_pi = 0; 1388 txq_data->cq_db = (volatile uint32_t *)(txq_obj->cq_dbrec_page->dbrs + 1389 txq_obj->cq_dbrec_offset); 1390 *txq_data->cq_db = 0; 1391 /* Create Send Queue object with DevX. */ 1392 wqe_n = mlx5_txq_create_devx_sq_resources(dev, idx); 1393 if (!wqe_n) { 1394 rte_errno = errno; 1395 goto error; 1396 } 1397 /* Create the Work Queue. */ 1398 txq_data->wqe_n = log2above(wqe_n); 1399 txq_data->wqe_s = 1 << txq_data->wqe_n; 1400 txq_data->wqe_m = txq_data->wqe_s - 1; 1401 txq_data->wqes = (struct mlx5_wqe *)txq_obj->sq_buf; 1402 txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s; 1403 txq_data->wqe_ci = 0; 1404 txq_data->wqe_pi = 0; 1405 txq_data->wqe_comp = 0; 1406 txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV; 1407 txq_data->qp_db = (volatile uint32_t *) 1408 (txq_obj->sq_dbrec_page->dbrs + 1409 txq_obj->sq_dbrec_offset + 1410 MLX5_SND_DBR * sizeof(uint32_t)); 1411 *txq_data->qp_db = 0; 1412 txq_data->qp_num_8s = txq_obj->sq_devx->id << 8; 1413 /* Change Send Queue state to Ready-to-Send. */ 1414 ret = mlx5_devx_modify_sq(txq_obj, MLX5_TXQ_MOD_RST2RDY, 0); 1415 if (ret) { 1416 rte_errno = errno; 1417 DRV_LOG(ERR, 1418 "Port %u Tx queue %u SQ state to SQC_STATE_RDY failed.", 1419 dev->data->port_id, idx); 1420 goto error; 1421 } 1422 #ifdef HAVE_IBV_FLOW_DV_SUPPORT 1423 /* 1424 * If using DevX need to query and store TIS transport domain value. 1425 * This is done once per port. 1426 * Will use this value on Rx, when creating matching TIR. 1427 */ 1428 if (!priv->sh->tdn) 1429 priv->sh->tdn = priv->sh->td->id; 1430 #endif 1431 MLX5_ASSERT(sh->tx_uar); 1432 reg_addr = mlx5_os_get_devx_uar_reg_addr(sh->tx_uar); 1433 MLX5_ASSERT(reg_addr); 1434 txq_ctrl->bf_reg = reg_addr; 1435 txq_ctrl->uar_mmap_offset = 1436 mlx5_os_get_devx_uar_mmap_offset(sh->tx_uar); 1437 txq_uar_init(txq_ctrl); 1438 dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED; 1439 return 0; 1440 error: 1441 ret = rte_errno; /* Save rte_errno before cleanup. */ 1442 mlx5_txq_release_devx_resources(txq_obj); 1443 rte_errno = ret; /* Restore rte_errno. */ 1444 return -rte_errno; 1445 #endif 1446 } 1447 1448 /** 1449 * Release an Tx DevX queue object. 1450 * 1451 * @param txq_obj 1452 * DevX Tx queue object. 1453 */ 1454 void 1455 mlx5_txq_devx_obj_release(struct mlx5_txq_obj *txq_obj) 1456 { 1457 MLX5_ASSERT(txq_obj); 1458 if (txq_obj->txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) { 1459 if (txq_obj->tis) 1460 claim_zero(mlx5_devx_cmd_destroy(txq_obj->tis)); 1461 #ifdef HAVE_MLX5DV_DEVX_UAR_OFFSET 1462 } else { 1463 mlx5_txq_release_devx_resources(txq_obj); 1464 #endif 1465 } 1466 } 1467 1468 struct mlx5_obj_ops devx_obj_ops = { 1469 .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_rq_vlan_strip, 1470 .rxq_obj_new = mlx5_rxq_devx_obj_new, 1471 .rxq_event_get = mlx5_rx_devx_get_event, 1472 .rxq_obj_modify = mlx5_devx_modify_rq, 1473 .rxq_obj_release = mlx5_rxq_devx_obj_release, 1474 .ind_table_new = mlx5_devx_ind_table_new, 1475 .ind_table_destroy = mlx5_devx_ind_table_destroy, 1476 .hrxq_new = mlx5_devx_hrxq_new, 1477 .hrxq_destroy = mlx5_devx_tir_destroy, 1478 .hrxq_modify = mlx5_devx_hrxq_modify, 1479 .drop_action_create = mlx5_devx_drop_action_create, 1480 .drop_action_destroy = mlx5_devx_drop_action_destroy, 1481 .txq_obj_new = mlx5_txq_devx_obj_new, 1482 .txq_obj_modify = mlx5_devx_modify_sq, 1483 .txq_obj_release = mlx5_txq_devx_obj_release, 1484 }; 1485