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