1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2019 Mellanox Technologies, Ltd 3 */ 4 5 #include <unistd.h> 6 #include <string.h> 7 #include <stdio.h> 8 9 #include <rte_errno.h> 10 #include <rte_mempool.h> 11 #include <rte_class.h> 12 #include <rte_malloc.h> 13 #include <rte_eal_paging.h> 14 15 #include "mlx5_common.h" 16 #include "mlx5_common_os.h" 17 #include "mlx5_common_mp.h" 18 #include "mlx5_common_log.h" 19 #include "mlx5_common_defs.h" 20 #include "mlx5_common_private.h" 21 22 uint8_t haswell_broadwell_cpu; 23 24 /* Driver type key for new device global syntax. */ 25 #define MLX5_DRIVER_KEY "driver" 26 27 /* Device parameter to get file descriptor for import device. */ 28 #define MLX5_DEVICE_FD "cmd_fd" 29 30 /* Device parameter to get PD number for import Protection Domain. */ 31 #define MLX5_PD_HANDLE "pd_handle" 32 33 /* Enable extending memsegs when creating a MR. */ 34 #define MLX5_MR_EXT_MEMSEG_EN "mr_ext_memseg_en" 35 36 /* Device parameter to configure implicit registration of mempool memory. */ 37 #define MLX5_MR_MEMPOOL_REG_EN "mr_mempool_reg_en" 38 39 /* The default memory allocator used in PMD. */ 40 #define MLX5_SYS_MEM_EN "sys_mem_en" 41 42 /* 43 * Device parameter to force doorbell register mapping 44 * to non-cached region eliminating the extra write memory barrier. 45 * Deprecated, ignored (Name changed to sq_db_nc). 46 */ 47 #define MLX5_TX_DB_NC "tx_db_nc" 48 49 /* 50 * Device parameter to force doorbell register mapping 51 * to non-cached region eliminating the extra write memory barrier. 52 */ 53 #define MLX5_SQ_DB_NC "sq_db_nc" 54 55 /* In case this is an x86_64 intel processor to check if 56 * we should use relaxed ordering. 57 */ 58 #ifdef RTE_ARCH_X86_64 59 /** 60 * This function returns processor identification and feature information 61 * into the registers. 62 * 63 * @param eax, ebx, ecx, edx 64 * Pointers to the registers that will hold cpu information. 65 * @param level 66 * The main category of information returned. 67 */ 68 static inline void mlx5_cpu_id(unsigned int level, 69 unsigned int *eax, unsigned int *ebx, 70 unsigned int *ecx, unsigned int *edx) 71 { 72 __asm__("cpuid\n\t" 73 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 74 : "0" (level)); 75 } 76 #endif 77 78 RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE) 79 80 /* Head of list of drivers. */ 81 static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list = 82 TAILQ_HEAD_INITIALIZER(drivers_list); 83 84 /* Head of devices. */ 85 static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list = 86 TAILQ_HEAD_INITIALIZER(devices_list); 87 static pthread_mutex_t devices_list_lock; 88 89 static const struct { 90 const char *name; 91 unsigned int drv_class; 92 } mlx5_classes[] = { 93 { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA }, 94 { .name = "eth", .drv_class = MLX5_CLASS_ETH }, 95 /* Keep class "net" for backward compatibility. */ 96 { .name = "net", .drv_class = MLX5_CLASS_ETH }, 97 { .name = "regex", .drv_class = MLX5_CLASS_REGEX }, 98 { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS }, 99 { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO }, 100 }; 101 102 static int 103 class_name_to_value(const char *class_name) 104 { 105 unsigned int i; 106 107 for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 108 if (strcmp(class_name, mlx5_classes[i].name) == 0) 109 return mlx5_classes[i].drv_class; 110 } 111 return -EINVAL; 112 } 113 114 static struct mlx5_class_driver * 115 driver_get(uint32_t class) 116 { 117 struct mlx5_class_driver *driver; 118 119 TAILQ_FOREACH(driver, &drivers_list, next) { 120 if ((uint32_t)driver->drv_class == class) 121 return driver; 122 } 123 return NULL; 124 } 125 126 int 127 mlx5_kvargs_process(struct mlx5_kvargs_ctrl *mkvlist, const char *const keys[], 128 arg_handler_t handler, void *opaque_arg) 129 { 130 const struct rte_kvargs_pair *pair; 131 uint32_t i, j; 132 133 MLX5_ASSERT(mkvlist && mkvlist->kvlist); 134 /* Process parameters. */ 135 for (i = 0; i < mkvlist->kvlist->count; i++) { 136 pair = &mkvlist->kvlist->pairs[i]; 137 for (j = 0; keys[j] != NULL; ++j) { 138 if (strcmp(pair->key, keys[j]) != 0) 139 continue; 140 if ((*handler)(pair->key, pair->value, opaque_arg) < 0) 141 return -1; 142 mkvlist->is_used[i] = true; 143 break; 144 } 145 } 146 return 0; 147 } 148 149 /** 150 * Prepare a mlx5 kvargs control. 151 * 152 * @param[out] mkvlist 153 * Pointer to mlx5 kvargs control. 154 * @param[in] devargs 155 * The input string containing the key/value associations. 156 * 157 * @return 158 * 0 on success, a negative errno value otherwise and rte_errno is set. 159 */ 160 static int 161 mlx5_kvargs_prepare(struct mlx5_kvargs_ctrl *mkvlist, 162 const struct rte_devargs *devargs) 163 { 164 struct rte_kvargs *kvlist; 165 uint32_t i; 166 167 if (devargs == NULL) 168 return 0; 169 kvlist = rte_kvargs_parse(devargs->args, NULL); 170 if (kvlist == NULL) { 171 rte_errno = EINVAL; 172 return -rte_errno; 173 } 174 /* 175 * rte_kvargs_parse enable key without value, in mlx5 PMDs we disable 176 * this syntax. 177 */ 178 for (i = 0; i < kvlist->count; i++) { 179 const struct rte_kvargs_pair *pair = &kvlist->pairs[i]; 180 if (pair->value == NULL || *(pair->value) == '\0') { 181 DRV_LOG(ERR, "Key %s is missing value.", pair->key); 182 rte_kvargs_free(kvlist); 183 rte_errno = EINVAL; 184 return -rte_errno; 185 } 186 } 187 /* Makes sure all devargs used array is false. */ 188 memset(mkvlist, 0, sizeof(*mkvlist)); 189 mkvlist->kvlist = kvlist; 190 DRV_LOG(DEBUG, "Parse successfully %u devargs.", 191 mkvlist->kvlist->count); 192 return 0; 193 } 194 195 /** 196 * Release a mlx5 kvargs control. 197 * 198 * @param[out] mkvlist 199 * Pointer to mlx5 kvargs control. 200 */ 201 static void 202 mlx5_kvargs_release(struct mlx5_kvargs_ctrl *mkvlist) 203 { 204 if (mkvlist == NULL) 205 return; 206 rte_kvargs_free(mkvlist->kvlist); 207 memset(mkvlist, 0, sizeof(*mkvlist)); 208 } 209 210 /** 211 * Validate device arguments list. 212 * It report about the first unknown parameter. 213 * 214 * @param[in] mkvlist 215 * Pointer to mlx5 kvargs control. 216 * 217 * @return 218 * 0 on success, a negative errno value otherwise and rte_errno is set. 219 */ 220 static int 221 mlx5_kvargs_validate(struct mlx5_kvargs_ctrl *mkvlist) 222 { 223 uint32_t i; 224 225 /* Secondary process should not handle devargs. */ 226 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 227 return 0; 228 if (mkvlist == NULL) 229 return 0; 230 for (i = 0; i < mkvlist->kvlist->count; i++) { 231 if (mkvlist->is_used[i] == 0) { 232 DRV_LOG(ERR, "Key \"%s\" " 233 "is unknown for the provided classes.", 234 mkvlist->kvlist->pairs[i].key); 235 rte_errno = EINVAL; 236 return -rte_errno; 237 } 238 } 239 return 0; 240 } 241 242 /** 243 * Verify and store value for devargs. 244 * 245 * @param[in] key 246 * Key argument to verify. 247 * @param[in] val 248 * Value associated with key. 249 * @param opaque 250 * User data. 251 * 252 * @return 253 * 0 on success, a negative errno value otherwise and rte_errno is set. 254 */ 255 static int 256 mlx5_common_args_check_handler(const char *key, const char *val, void *opaque) 257 { 258 struct mlx5_common_dev_config *config = opaque; 259 signed long tmp; 260 261 if (strcmp(MLX5_DRIVER_KEY, key) == 0 || 262 strcmp(RTE_DEVARGS_KEY_CLASS, key) == 0) 263 return 0; 264 errno = 0; 265 tmp = strtol(val, NULL, 0); 266 if (errno) { 267 rte_errno = errno; 268 DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val); 269 return -rte_errno; 270 } 271 if (strcmp(key, MLX5_TX_DB_NC) == 0) 272 DRV_LOG(WARNING, 273 "%s: deprecated parameter, converted to queue_db_nc", 274 key); 275 if (strcmp(key, MLX5_SQ_DB_NC) == 0 || 276 strcmp(key, MLX5_TX_DB_NC) == 0) { 277 if (tmp != MLX5_SQ_DB_CACHED && 278 tmp != MLX5_SQ_DB_NCACHED && 279 tmp != MLX5_SQ_DB_HEURISTIC) { 280 DRV_LOG(ERR, 281 "Invalid Send Queue doorbell mapping parameter."); 282 rte_errno = EINVAL; 283 return -rte_errno; 284 } 285 config->dbnc = tmp; 286 } else if (strcmp(key, MLX5_MR_EXT_MEMSEG_EN) == 0) { 287 config->mr_ext_memseg_en = !!tmp; 288 } else if (strcmp(key, MLX5_MR_MEMPOOL_REG_EN) == 0) { 289 config->mr_mempool_reg_en = !!tmp; 290 } else if (strcmp(key, MLX5_SYS_MEM_EN) == 0) { 291 config->sys_mem_en = !!tmp; 292 } else if (strcmp(key, MLX5_DEVICE_FD) == 0) { 293 config->device_fd = tmp; 294 } else if (strcmp(key, MLX5_PD_HANDLE) == 0) { 295 config->pd_handle = tmp; 296 } 297 return 0; 298 } 299 300 /** 301 * Parse common device parameters. 302 * 303 * @param devargs 304 * Device arguments structure. 305 * @param config 306 * Pointer to device configuration structure. 307 * 308 * @return 309 * 0 on success, a negative errno value otherwise and rte_errno is set. 310 */ 311 static int 312 mlx5_common_config_get(struct mlx5_kvargs_ctrl *mkvlist, 313 struct mlx5_common_dev_config *config) 314 { 315 const char **params = (const char *[]){ 316 RTE_DEVARGS_KEY_CLASS, 317 MLX5_DRIVER_KEY, 318 MLX5_TX_DB_NC, 319 MLX5_SQ_DB_NC, 320 MLX5_MR_EXT_MEMSEG_EN, 321 MLX5_SYS_MEM_EN, 322 MLX5_MR_MEMPOOL_REG_EN, 323 MLX5_DEVICE_FD, 324 MLX5_PD_HANDLE, 325 NULL, 326 }; 327 int ret = 0; 328 329 /* Set defaults. */ 330 config->mr_ext_memseg_en = 1; 331 config->mr_mempool_reg_en = 1; 332 config->sys_mem_en = 0; 333 config->dbnc = MLX5_ARG_UNSET; 334 config->device_fd = MLX5_ARG_UNSET; 335 config->pd_handle = MLX5_ARG_UNSET; 336 if (mkvlist == NULL) 337 return 0; 338 /* Process common parameters. */ 339 ret = mlx5_kvargs_process(mkvlist, params, 340 mlx5_common_args_check_handler, config); 341 if (ret) { 342 rte_errno = EINVAL; 343 return -rte_errno; 344 } 345 /* Validate user arguments for remote PD and CTX if it is given. */ 346 ret = mlx5_os_remote_pd_and_ctx_validate(config); 347 if (ret) 348 return ret; 349 DRV_LOG(DEBUG, "mr_ext_memseg_en is %u.", config->mr_ext_memseg_en); 350 DRV_LOG(DEBUG, "mr_mempool_reg_en is %u.", config->mr_mempool_reg_en); 351 DRV_LOG(DEBUG, "sys_mem_en is %u.", config->sys_mem_en); 352 DRV_LOG(DEBUG, "Send Queue doorbell mapping parameter is %d.", 353 config->dbnc); 354 return ret; 355 } 356 357 static int 358 devargs_class_handler(__rte_unused const char *key, 359 const char *class_names, void *opaque) 360 { 361 int *ret = opaque; 362 int class_val; 363 char *scratch; 364 char *found; 365 char *refstr = NULL; 366 367 *ret = 0; 368 scratch = strdup(class_names); 369 if (scratch == NULL) { 370 *ret = -ENOMEM; 371 return *ret; 372 } 373 found = strtok_r(scratch, ":", &refstr); 374 if (found == NULL) 375 /* Empty string. */ 376 goto err; 377 do { 378 /* Extract each individual class name. Multiple 379 * classes can be supplied as class=net:regex:foo:bar. 380 */ 381 class_val = class_name_to_value(found); 382 /* Check if its a valid class. */ 383 if (class_val < 0) { 384 *ret = -EINVAL; 385 goto err; 386 } 387 *ret |= class_val; 388 found = strtok_r(NULL, ":", &refstr); 389 } while (found != NULL); 390 err: 391 free(scratch); 392 if (*ret < 0) 393 DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names); 394 return *ret; 395 } 396 397 static int 398 parse_class_options(const struct rte_devargs *devargs, 399 struct mlx5_kvargs_ctrl *mkvlist) 400 { 401 int ret = 0; 402 403 if (devargs == NULL) 404 return 0; 405 if (devargs->cls != NULL && devargs->cls->name != NULL) 406 /* Global syntax, only one class type. */ 407 return class_name_to_value(devargs->cls->name); 408 /* Legacy devargs support multiple classes. */ 409 rte_kvargs_process(mkvlist->kvlist, RTE_DEVARGS_KEY_CLASS, 410 devargs_class_handler, &ret); 411 return ret; 412 } 413 414 static const unsigned int mlx5_class_invalid_combinations[] = { 415 MLX5_CLASS_ETH | MLX5_CLASS_VDPA, 416 /* New class combination should be added here. */ 417 }; 418 419 static int 420 is_valid_class_combination(uint32_t user_classes) 421 { 422 unsigned int i; 423 424 /* Verify if user specified unsupported combination. */ 425 for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) { 426 if ((mlx5_class_invalid_combinations[i] & user_classes) == 427 mlx5_class_invalid_combinations[i]) 428 return -EINVAL; 429 } 430 /* Not found any invalid class combination. */ 431 return 0; 432 } 433 434 static bool 435 mlx5_bus_match(const struct mlx5_class_driver *drv, 436 const struct rte_device *dev) 437 { 438 if (mlx5_dev_is_pci(dev)) 439 return mlx5_dev_pci_match(drv, dev); 440 return true; 441 } 442 443 static struct mlx5_common_device * 444 to_mlx5_device(const struct rte_device *rte_dev) 445 { 446 struct mlx5_common_device *cdev; 447 448 TAILQ_FOREACH(cdev, &devices_list, next) { 449 if (rte_dev == cdev->dev) 450 return cdev; 451 } 452 return NULL; 453 } 454 455 int 456 mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size) 457 { 458 struct rte_pci_addr pci_addr = { 0 }; 459 int ret; 460 461 if (mlx5_dev_is_pci(dev)) { 462 /* Input might be <BDF>, format PCI address to <DBDF>. */ 463 ret = rte_pci_addr_parse(dev->name, &pci_addr); 464 if (ret != 0) 465 return -ENODEV; 466 rte_pci_device_name(&pci_addr, addr, size); 467 return 0; 468 } 469 #ifdef RTE_EXEC_ENV_LINUX 470 return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev), 471 addr, size); 472 #else 473 rte_errno = ENODEV; 474 return -rte_errno; 475 #endif 476 } 477 478 /** 479 * Register the mempool for the protection domain. 480 * 481 * @param cdev 482 * Pointer to the mlx5 common device. 483 * @param mp 484 * Mempool being registered. 485 * 486 * @return 487 * 0 on success, (-1) on failure and rte_errno is set. 488 */ 489 static int 490 mlx5_dev_mempool_register(struct mlx5_common_device *cdev, 491 struct rte_mempool *mp, bool is_extmem) 492 { 493 return mlx5_mr_mempool_register(cdev, mp, is_extmem); 494 } 495 496 /** 497 * Unregister the mempool from the protection domain. 498 * 499 * @param cdev 500 * Pointer to the mlx5 common device. 501 * @param mp 502 * Mempool being unregistered. 503 */ 504 void 505 mlx5_dev_mempool_unregister(struct mlx5_common_device *cdev, 506 struct rte_mempool *mp) 507 { 508 if (mlx5_mr_mempool_unregister(cdev, mp) < 0) 509 DRV_LOG(WARNING, "Failed to unregister mempool %s for PD %p: %s", 510 mp->name, cdev->pd, rte_strerror(rte_errno)); 511 } 512 513 /** 514 * rte_mempool_walk() callback to register mempools for the protection domain. 515 * 516 * @param mp 517 * The mempool being walked. 518 * @param arg 519 * Pointer to the device shared context. 520 */ 521 static void 522 mlx5_dev_mempool_register_cb(struct rte_mempool *mp, void *arg) 523 { 524 struct mlx5_common_device *cdev = arg; 525 int ret; 526 527 ret = mlx5_dev_mempool_register(cdev, mp, false); 528 if (ret < 0 && rte_errno != EEXIST) 529 DRV_LOG(ERR, 530 "Failed to register existing mempool %s for PD %p: %s", 531 mp->name, cdev->pd, rte_strerror(rte_errno)); 532 } 533 534 /** 535 * rte_mempool_walk() callback to unregister mempools 536 * from the protection domain. 537 * 538 * @param mp 539 * The mempool being walked. 540 * @param arg 541 * Pointer to the device shared context. 542 */ 543 static void 544 mlx5_dev_mempool_unregister_cb(struct rte_mempool *mp, void *arg) 545 { 546 mlx5_dev_mempool_unregister((struct mlx5_common_device *)arg, mp); 547 } 548 549 /** 550 * Mempool life cycle callback for mlx5 common devices. 551 * 552 * @param event 553 * Mempool life cycle event. 554 * @param mp 555 * Associated mempool. 556 * @param arg 557 * Pointer to a device shared context. 558 */ 559 static void 560 mlx5_dev_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp, 561 void *arg) 562 { 563 struct mlx5_common_device *cdev = arg; 564 565 switch (event) { 566 case RTE_MEMPOOL_EVENT_READY: 567 if (mlx5_dev_mempool_register(cdev, mp, false) < 0) 568 DRV_LOG(ERR, 569 "Failed to register new mempool %s for PD %p: %s", 570 mp->name, cdev->pd, rte_strerror(rte_errno)); 571 break; 572 case RTE_MEMPOOL_EVENT_DESTROY: 573 mlx5_dev_mempool_unregister(cdev, mp); 574 break; 575 } 576 } 577 578 int 579 mlx5_dev_mempool_subscribe(struct mlx5_common_device *cdev) 580 { 581 int ret = 0; 582 583 if (!cdev->config.mr_mempool_reg_en) 584 return 0; 585 rte_rwlock_write_lock(&cdev->mr_scache.mprwlock); 586 /* Callback for this device may be already registered. */ 587 ret = rte_mempool_event_callback_register(mlx5_dev_mempool_event_cb, 588 cdev); 589 if (ret != 0 && rte_errno != EEXIST) 590 goto exit; 591 __atomic_add_fetch(&cdev->mr_scache.mempool_cb_reg_n, 1, 592 __ATOMIC_ACQUIRE); 593 /* Register mempools only once for this device. */ 594 if (rte_eal_process_type() == RTE_PROC_PRIMARY) 595 rte_mempool_walk(mlx5_dev_mempool_register_cb, cdev); 596 ret = 0; 597 exit: 598 rte_rwlock_write_unlock(&cdev->mr_scache.mprwlock); 599 return ret; 600 } 601 602 static void 603 mlx5_dev_mempool_unsubscribe(struct mlx5_common_device *cdev) 604 { 605 uint32_t mempool_cb_reg_n; 606 int ret; 607 608 if (!cdev->config.mr_mempool_reg_en) 609 return; 610 mempool_cb_reg_n = __atomic_sub_fetch(&cdev->mr_scache.mempool_cb_reg_n, 611 1, __ATOMIC_RELEASE); 612 if (mempool_cb_reg_n > 0) 613 return; 614 /* Stop watching for mempool events and unregister all mempools. */ 615 ret = rte_mempool_event_callback_unregister(mlx5_dev_mempool_event_cb, 616 cdev); 617 if (ret == 0) 618 rte_mempool_walk(mlx5_dev_mempool_unregister_cb, cdev); 619 } 620 621 /** 622 * Callback for memory event. 623 * 624 * @param event_type 625 * Memory event type. 626 * @param addr 627 * Address of memory. 628 * @param len 629 * Size of memory. 630 */ 631 static void 632 mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr, 633 size_t len, void *arg __rte_unused) 634 { 635 struct mlx5_common_device *cdev; 636 637 /* Must be called from the primary process. */ 638 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 639 switch (event_type) { 640 case RTE_MEM_EVENT_FREE: 641 pthread_mutex_lock(&devices_list_lock); 642 /* Iterate all the existing mlx5 devices. */ 643 TAILQ_FOREACH(cdev, &devices_list, next) 644 mlx5_free_mr_by_addr(&cdev->mr_scache, 645 mlx5_os_get_ctx_device_name 646 (cdev->ctx), 647 addr, len); 648 pthread_mutex_unlock(&devices_list_lock); 649 break; 650 case RTE_MEM_EVENT_ALLOC: 651 default: 652 break; 653 } 654 } 655 656 /** 657 * Uninitialize all HW global of device context. 658 * 659 * @param cdev 660 * Pointer to mlx5 device structure. 661 * 662 * @return 663 * 0 on success, a negative errno value otherwise and rte_errno is set. 664 */ 665 static void 666 mlx5_dev_hw_global_release(struct mlx5_common_device *cdev) 667 { 668 if (cdev->pd != NULL) { 669 claim_zero(mlx5_os_pd_release(cdev)); 670 cdev->pd = NULL; 671 } 672 if (cdev->ctx != NULL) { 673 claim_zero(mlx5_glue->close_device(cdev->ctx)); 674 cdev->ctx = NULL; 675 } 676 } 677 678 /** 679 * Initialize all HW global of device context. 680 * 681 * @param cdev 682 * Pointer to mlx5 device structure. 683 * @param classes 684 * Chosen classes come from user device arguments. 685 * 686 * @return 687 * 0 on success, a negative errno value otherwise and rte_errno is set. 688 */ 689 static int 690 mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes) 691 { 692 int ret; 693 694 /* Create context device */ 695 ret = mlx5_os_open_device(cdev, classes); 696 if (ret < 0) 697 return ret; 698 /* 699 * When CTX is created by Verbs, query HCA attribute is unsupported. 700 * When CTX is imported, we cannot know if it is created by DevX or 701 * Verbs. So, we use query HCA attribute function to check it. 702 */ 703 if (cdev->config.devx || cdev->config.device_fd != MLX5_ARG_UNSET) { 704 /* Query HCA attributes. */ 705 ret = mlx5_devx_cmd_query_hca_attr(cdev->ctx, 706 &cdev->config.hca_attr); 707 if (ret) { 708 DRV_LOG(ERR, "Unable to read HCA caps in DevX mode."); 709 rte_errno = ENOTSUP; 710 goto error; 711 } 712 cdev->config.devx = 1; 713 } 714 DRV_LOG(DEBUG, "DevX is %ssupported.", cdev->config.devx ? "" : "NOT "); 715 /* Prepare Protection Domain object and extract its pdn. */ 716 ret = mlx5_os_pd_prepare(cdev); 717 if (ret) 718 goto error; 719 return 0; 720 error: 721 mlx5_dev_hw_global_release(cdev); 722 return ret; 723 } 724 725 static void 726 mlx5_common_dev_release(struct mlx5_common_device *cdev) 727 { 728 pthread_mutex_lock(&devices_list_lock); 729 TAILQ_REMOVE(&devices_list, cdev, next); 730 pthread_mutex_unlock(&devices_list_lock); 731 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 732 if (TAILQ_EMPTY(&devices_list)) 733 rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB", 734 NULL); 735 mlx5_dev_mempool_unsubscribe(cdev); 736 mlx5_mr_release_cache(&cdev->mr_scache); 737 mlx5_dev_hw_global_release(cdev); 738 } 739 rte_free(cdev); 740 } 741 742 static struct mlx5_common_device * 743 mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes, 744 struct mlx5_kvargs_ctrl *mkvlist) 745 { 746 struct mlx5_common_device *cdev; 747 int ret; 748 749 cdev = rte_zmalloc("mlx5_common_device", sizeof(*cdev), 0); 750 if (!cdev) { 751 DRV_LOG(ERR, "Device allocation failure."); 752 rte_errno = ENOMEM; 753 return NULL; 754 } 755 cdev->dev = eal_dev; 756 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 757 goto exit; 758 /* Parse device parameters. */ 759 ret = mlx5_common_config_get(mkvlist, &cdev->config); 760 if (ret < 0) { 761 DRV_LOG(ERR, "Failed to process device arguments: %s", 762 strerror(rte_errno)); 763 rte_free(cdev); 764 return NULL; 765 } 766 mlx5_malloc_mem_select(cdev->config.sys_mem_en); 767 /* Initialize all HW global of device context. */ 768 ret = mlx5_dev_hw_global_prepare(cdev, classes); 769 if (ret) { 770 DRV_LOG(ERR, "Failed to initialize device context."); 771 rte_free(cdev); 772 return NULL; 773 } 774 /* Initialize global MR cache resources and update its functions. */ 775 ret = mlx5_mr_create_cache(&cdev->mr_scache, eal_dev->numa_node); 776 if (ret) { 777 DRV_LOG(ERR, "Failed to initialize global MR share cache."); 778 mlx5_dev_hw_global_release(cdev); 779 rte_free(cdev); 780 return NULL; 781 } 782 /* Register callback function for global shared MR cache management. */ 783 if (TAILQ_EMPTY(&devices_list)) 784 rte_mem_event_callback_register("MLX5_MEM_EVENT_CB", 785 mlx5_mr_mem_event_cb, NULL); 786 exit: 787 pthread_mutex_lock(&devices_list_lock); 788 TAILQ_INSERT_HEAD(&devices_list, cdev, next); 789 pthread_mutex_unlock(&devices_list_lock); 790 return cdev; 791 } 792 793 /** 794 * Validate common devargs when probing again. 795 * 796 * When common device probing again, it cannot change its configurations. 797 * If user ask non compatible configurations in devargs, it is error. 798 * This function checks the match between: 799 * - Common device configurations requested by probe again devargs. 800 * - Existing common device configurations. 801 * 802 * @param cdev 803 * Pointer to mlx5 device structure. 804 * @param mkvlist 805 * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. 806 * 807 * @return 808 * 0 on success, a negative errno value otherwise and rte_errno is set. 809 */ 810 static int 811 mlx5_common_probe_again_args_validate(struct mlx5_common_device *cdev, 812 struct mlx5_kvargs_ctrl *mkvlist) 813 { 814 struct mlx5_common_dev_config *config; 815 int ret; 816 817 /* Secondary process should not handle devargs. */ 818 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 819 return 0; 820 /* Probe again doesn't have to generate devargs. */ 821 if (mkvlist == NULL) 822 return 0; 823 config = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, 824 sizeof(struct mlx5_common_dev_config), 825 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 826 if (config == NULL) { 827 rte_errno = -ENOMEM; 828 return -rte_errno; 829 } 830 /* 831 * Creates a temporary common configure structure according to new 832 * devargs attached in probing again. 833 */ 834 ret = mlx5_common_config_get(mkvlist, config); 835 if (ret) { 836 DRV_LOG(ERR, "Failed to process device configure: %s", 837 strerror(rte_errno)); 838 mlx5_free(config); 839 return ret; 840 } 841 /* 842 * Checks the match between the temporary structure and the existing 843 * common device structure. 844 */ 845 if (cdev->config.mr_ext_memseg_en != config->mr_ext_memseg_en) { 846 DRV_LOG(ERR, "\"" MLX5_MR_EXT_MEMSEG_EN "\" " 847 "configuration mismatch for device %s.", 848 cdev->dev->name); 849 goto error; 850 } 851 if (cdev->config.mr_mempool_reg_en != config->mr_mempool_reg_en) { 852 DRV_LOG(ERR, "\"" MLX5_MR_MEMPOOL_REG_EN "\" " 853 "configuration mismatch for device %s.", 854 cdev->dev->name); 855 goto error; 856 } 857 if (cdev->config.device_fd != config->device_fd) { 858 DRV_LOG(ERR, "\"" MLX5_DEVICE_FD "\" " 859 "configuration mismatch for device %s.", 860 cdev->dev->name); 861 goto error; 862 } 863 if (cdev->config.pd_handle != config->pd_handle) { 864 DRV_LOG(ERR, "\"" MLX5_PD_HANDLE "\" " 865 "configuration mismatch for device %s.", 866 cdev->dev->name); 867 goto error; 868 } 869 if (cdev->config.sys_mem_en != config->sys_mem_en) { 870 DRV_LOG(ERR, "\"" MLX5_SYS_MEM_EN "\" " 871 "configuration mismatch for device %s.", 872 cdev->dev->name); 873 goto error; 874 } 875 if (cdev->config.dbnc != config->dbnc) { 876 DRV_LOG(ERR, "\"" MLX5_SQ_DB_NC "\" " 877 "configuration mismatch for device %s.", 878 cdev->dev->name); 879 goto error; 880 } 881 mlx5_free(config); 882 return 0; 883 error: 884 mlx5_free(config); 885 rte_errno = EINVAL; 886 return -rte_errno; 887 } 888 889 static int 890 drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes) 891 { 892 struct mlx5_class_driver *driver; 893 int local_ret = -ENODEV; 894 unsigned int i = 0; 895 int ret = 0; 896 897 while (enabled_classes) { 898 driver = driver_get(RTE_BIT64(i)); 899 if (driver != NULL) { 900 local_ret = driver->remove(cdev); 901 if (local_ret == 0) 902 cdev->classes_loaded &= ~RTE_BIT64(i); 903 else if (ret == 0) 904 ret = local_ret; 905 } 906 enabled_classes &= ~RTE_BIT64(i); 907 i++; 908 } 909 if (local_ret != 0 && ret == 0) 910 ret = local_ret; 911 return ret; 912 } 913 914 static int 915 drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes, 916 struct mlx5_kvargs_ctrl *mkvlist) 917 { 918 struct mlx5_class_driver *driver; 919 uint32_t enabled_classes = 0; 920 bool already_loaded; 921 int ret = -EINVAL; 922 923 TAILQ_FOREACH(driver, &drivers_list, next) { 924 if ((driver->drv_class & user_classes) == 0) 925 continue; 926 if (!mlx5_bus_match(driver, cdev->dev)) 927 continue; 928 already_loaded = cdev->classes_loaded & driver->drv_class; 929 if (already_loaded && driver->probe_again == 0) { 930 DRV_LOG(ERR, "Device %s is already probed", 931 cdev->dev->name); 932 ret = -EEXIST; 933 goto probe_err; 934 } 935 ret = driver->probe(cdev, mkvlist); 936 if (ret < 0) { 937 DRV_LOG(ERR, "Failed to load driver %s", 938 driver->name); 939 goto probe_err; 940 } 941 enabled_classes |= driver->drv_class; 942 } 943 if (!ret) { 944 cdev->classes_loaded |= enabled_classes; 945 return 0; 946 } 947 probe_err: 948 /* 949 * Need to remove only drivers which were not probed before this probe 950 * instance, but have already been probed before this failure. 951 */ 952 enabled_classes &= ~cdev->classes_loaded; 953 drivers_remove(cdev, enabled_classes); 954 return ret; 955 } 956 957 int 958 mlx5_common_dev_probe(struct rte_device *eal_dev) 959 { 960 struct mlx5_common_device *cdev; 961 struct mlx5_kvargs_ctrl mkvlist; 962 struct mlx5_kvargs_ctrl *mkvlist_p = NULL; 963 uint32_t classes = 0; 964 bool new_device = false; 965 int ret; 966 967 DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name); 968 if (eal_dev->devargs != NULL) 969 mkvlist_p = &mkvlist; 970 ret = mlx5_kvargs_prepare(mkvlist_p, eal_dev->devargs); 971 if (ret < 0) { 972 DRV_LOG(ERR, "Unsupported device arguments: %s", 973 eal_dev->devargs->args); 974 return ret; 975 } 976 ret = parse_class_options(eal_dev->devargs, mkvlist_p); 977 if (ret < 0) { 978 DRV_LOG(ERR, "Unsupported mlx5 class type: %s", 979 eal_dev->devargs->args); 980 goto class_err; 981 } 982 classes = ret; 983 if (classes == 0) 984 /* Default to net class. */ 985 classes = MLX5_CLASS_ETH; 986 /* 987 * MLX5 common driver supports probing again in two scenarios: 988 * - Add new driver under existing common device (regardless of the 989 * driver's own support in probing again). 990 * - Transfer the probing again support of the drivers themselves. 991 * 992 * In both scenarios it uses in the existing device. here it looks for 993 * device that match to rte device, if it exists, the request classes 994 * were probed with this device. 995 */ 996 cdev = to_mlx5_device(eal_dev); 997 if (!cdev) { 998 /* It isn't probing again, creates a new device. */ 999 cdev = mlx5_common_dev_create(eal_dev, classes, mkvlist_p); 1000 if (!cdev) { 1001 ret = -ENOMEM; 1002 goto class_err; 1003 } 1004 new_device = true; 1005 } else { 1006 /* It is probing again, validate common devargs match. */ 1007 ret = mlx5_common_probe_again_args_validate(cdev, mkvlist_p); 1008 if (ret) { 1009 DRV_LOG(ERR, 1010 "Probe again parameters aren't compatible : %s", 1011 strerror(rte_errno)); 1012 goto class_err; 1013 } 1014 } 1015 /* 1016 * Validate combination here. 1017 * For new device, the classes_loaded field is 0 and it check only 1018 * the classes given as user device arguments. 1019 */ 1020 ret = is_valid_class_combination(classes | cdev->classes_loaded); 1021 if (ret != 0) { 1022 DRV_LOG(ERR, "Unsupported mlx5 classes combination."); 1023 goto class_err; 1024 } 1025 ret = drivers_probe(cdev, classes, mkvlist_p); 1026 if (ret) 1027 goto class_err; 1028 /* 1029 * Validate that all devargs have been used, unused key -> unknown Key. 1030 * When probe again validate is failed, the added drivers aren't removed 1031 * here but when device is released. 1032 */ 1033 ret = mlx5_kvargs_validate(mkvlist_p); 1034 if (ret) 1035 goto class_err; 1036 mlx5_kvargs_release(mkvlist_p); 1037 return 0; 1038 class_err: 1039 if (new_device) { 1040 /* 1041 * For new device, classes_loaded is always 0 before 1042 * drivers_probe function. 1043 */ 1044 if (cdev->classes_loaded) 1045 drivers_remove(cdev, cdev->classes_loaded); 1046 mlx5_common_dev_release(cdev); 1047 } 1048 mlx5_kvargs_release(mkvlist_p); 1049 return ret; 1050 } 1051 1052 int 1053 mlx5_common_dev_remove(struct rte_device *eal_dev) 1054 { 1055 struct mlx5_common_device *cdev; 1056 int ret; 1057 1058 cdev = to_mlx5_device(eal_dev); 1059 if (!cdev) 1060 return -ENODEV; 1061 /* Matching device found, cleanup and unload drivers. */ 1062 ret = drivers_remove(cdev, cdev->classes_loaded); 1063 if (ret == 0) 1064 mlx5_common_dev_release(cdev); 1065 return ret; 1066 } 1067 1068 /** 1069 * Callback to DMA map external memory to a device. 1070 * 1071 * @param rte_dev 1072 * Pointer to the generic device. 1073 * @param addr 1074 * Starting virtual address of memory to be mapped. 1075 * @param iova 1076 * Starting IOVA address of memory to be mapped. 1077 * @param len 1078 * Length of memory segment being mapped. 1079 * 1080 * @return 1081 * 0 on success, negative value on error. 1082 */ 1083 int 1084 mlx5_common_dev_dma_map(struct rte_device *rte_dev, void *addr, 1085 uint64_t iova __rte_unused, size_t len) 1086 { 1087 struct mlx5_common_device *dev; 1088 struct mlx5_mr_btree *bt; 1089 struct mlx5_mr *mr; 1090 1091 dev = to_mlx5_device(rte_dev); 1092 if (!dev) { 1093 DRV_LOG(WARNING, 1094 "Unable to find matching mlx5 device to device %s", 1095 rte_dev->name); 1096 rte_errno = ENODEV; 1097 return -1; 1098 } 1099 mr = mlx5_create_mr_ext(dev->pd, (uintptr_t)addr, len, 1100 SOCKET_ID_ANY, dev->mr_scache.reg_mr_cb); 1101 if (!mr) { 1102 DRV_LOG(WARNING, "Device %s unable to DMA map", rte_dev->name); 1103 rte_errno = EINVAL; 1104 return -1; 1105 } 1106 try_insert: 1107 rte_rwlock_write_lock(&dev->mr_scache.rwlock); 1108 bt = &dev->mr_scache.cache; 1109 if (bt->len == bt->size) { 1110 uint32_t size; 1111 int ret; 1112 1113 size = bt->size + 1; 1114 MLX5_ASSERT(size > bt->size); 1115 /* 1116 * Avoid deadlock (numbers show the sequence of events): 1117 * mlx5_mr_create_primary(): 1118 * 1) take EAL memory lock 1119 * 3) take MR lock 1120 * this function: 1121 * 2) take MR lock 1122 * 4) take EAL memory lock while allocating the new cache 1123 * Releasing the MR lock before step 4 1124 * allows another thread to execute step 3. 1125 */ 1126 rte_rwlock_write_unlock(&dev->mr_scache.rwlock); 1127 ret = mlx5_mr_expand_cache(&dev->mr_scache, size, 1128 rte_dev->numa_node); 1129 if (ret < 0) { 1130 mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb); 1131 rte_errno = ret; 1132 return -1; 1133 } 1134 goto try_insert; 1135 } 1136 LIST_INSERT_HEAD(&dev->mr_scache.mr_list, mr, mr); 1137 /* Insert to the global cache table. */ 1138 mlx5_mr_insert_cache(&dev->mr_scache, mr); 1139 rte_rwlock_write_unlock(&dev->mr_scache.rwlock); 1140 return 0; 1141 } 1142 1143 /** 1144 * Callback to DMA unmap external memory to a device. 1145 * 1146 * @param rte_dev 1147 * Pointer to the generic device. 1148 * @param addr 1149 * Starting virtual address of memory to be unmapped. 1150 * @param iova 1151 * Starting IOVA address of memory to be unmapped. 1152 * @param len 1153 * Length of memory segment being unmapped. 1154 * 1155 * @return 1156 * 0 on success, negative value on error. 1157 */ 1158 int 1159 mlx5_common_dev_dma_unmap(struct rte_device *rte_dev, void *addr, 1160 uint64_t iova __rte_unused, size_t len __rte_unused) 1161 { 1162 struct mlx5_common_device *dev; 1163 struct mr_cache_entry entry; 1164 struct mlx5_mr *mr; 1165 1166 dev = to_mlx5_device(rte_dev); 1167 if (!dev) { 1168 DRV_LOG(WARNING, 1169 "Unable to find matching mlx5 device to device %s.", 1170 rte_dev->name); 1171 rte_errno = ENODEV; 1172 return -1; 1173 } 1174 rte_rwlock_read_lock(&dev->mr_scache.rwlock); 1175 mr = mlx5_mr_lookup_list(&dev->mr_scache, &entry, (uintptr_t)addr); 1176 if (!mr) { 1177 rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1178 DRV_LOG(WARNING, 1179 "Address 0x%" PRIxPTR " wasn't registered to device %s", 1180 (uintptr_t)addr, rte_dev->name); 1181 rte_errno = EINVAL; 1182 return -1; 1183 } 1184 LIST_REMOVE(mr, mr); 1185 DRV_LOG(DEBUG, "MR(%p) is removed from list.", (void *)mr); 1186 mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb); 1187 mlx5_mr_rebuild_cache(&dev->mr_scache); 1188 /* 1189 * No explicit wmb is needed after updating dev_gen due to 1190 * store-release ordering in unlock that provides the 1191 * implicit barrier at the software visible level. 1192 */ 1193 ++dev->mr_scache.dev_gen; 1194 DRV_LOG(DEBUG, "Broadcasting local cache flush, gen=%d.", 1195 dev->mr_scache.dev_gen); 1196 rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1197 return 0; 1198 } 1199 1200 void 1201 mlx5_class_driver_register(struct mlx5_class_driver *driver) 1202 { 1203 mlx5_common_driver_on_register_pci(driver); 1204 TAILQ_INSERT_TAIL(&drivers_list, driver, next); 1205 } 1206 1207 static void mlx5_common_driver_init(void) 1208 { 1209 mlx5_common_pci_init(); 1210 #ifdef RTE_EXEC_ENV_LINUX 1211 mlx5_common_auxiliary_init(); 1212 #endif 1213 } 1214 1215 static bool mlx5_common_initialized; 1216 1217 /** 1218 * One time initialization routine for run-time dependency on glue library 1219 * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 1220 * must invoke in its constructor. 1221 */ 1222 void 1223 mlx5_common_init(void) 1224 { 1225 if (mlx5_common_initialized) 1226 return; 1227 1228 pthread_mutex_init(&devices_list_lock, NULL); 1229 mlx5_glue_constructor(); 1230 mlx5_common_driver_init(); 1231 mlx5_common_initialized = true; 1232 } 1233 1234 /** 1235 * This function is responsible of initializing the variable 1236 * haswell_broadwell_cpu by checking if the cpu is intel 1237 * and reading the data returned from mlx5_cpu_id(). 1238 * since haswell and broadwell cpus don't have improved performance 1239 * when using relaxed ordering we want to check the cpu type before 1240 * before deciding whether to enable RO or not. 1241 * if the cpu is haswell or broadwell the variable will be set to 1 1242 * otherwise it will be 0. 1243 */ 1244 RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 1245 { 1246 #ifdef RTE_ARCH_X86_64 1247 unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 1248 unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 1249 unsigned int i, model, family, brand_id, vendor; 1250 unsigned int signature_intel_ebx = 0x756e6547; 1251 unsigned int extended_model; 1252 unsigned int eax = 0; 1253 unsigned int ebx = 0; 1254 unsigned int ecx = 0; 1255 unsigned int edx = 0; 1256 int max_level; 1257 1258 mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 1259 vendor = ebx; 1260 max_level = eax; 1261 if (max_level < 1) { 1262 haswell_broadwell_cpu = 0; 1263 return; 1264 } 1265 mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 1266 model = (eax >> 4) & 0x0f; 1267 family = (eax >> 8) & 0x0f; 1268 brand_id = ebx & 0xff; 1269 extended_model = (eax >> 12) & 0xf0; 1270 /* Check if the processor is Haswell or Broadwell */ 1271 if (vendor == signature_intel_ebx) { 1272 if (family == 0x06) 1273 model += extended_model; 1274 if (brand_id == 0 && family == 0x6) { 1275 for (i = 0; i < RTE_DIM(broadwell_models); i++) 1276 if (model == broadwell_models[i]) { 1277 haswell_broadwell_cpu = 1; 1278 return; 1279 } 1280 for (i = 0; i < RTE_DIM(haswell_models); i++) 1281 if (model == haswell_models[i]) { 1282 haswell_broadwell_cpu = 1; 1283 return; 1284 } 1285 } 1286 } 1287 #endif 1288 haswell_broadwell_cpu = 0; 1289 } 1290 1291 /** 1292 * Allocate the User Access Region with DevX on specified device. 1293 * This routine handles the following UAR allocation issues: 1294 * 1295 * - Try to allocate the UAR with the most appropriate memory mapping 1296 * type from the ones supported by the host. 1297 * 1298 * - Try to allocate the UAR with non-NULL base address OFED 5.0.x and 1299 * Upstream rdma_core before v29 returned the NULL as UAR base address 1300 * if UAR was not the first object in the UAR page. 1301 * It caused the PMD failure and we should try to get another UAR till 1302 * we get the first one with non-NULL base address returned. 1303 * 1304 * @param [in] cdev 1305 * Pointer to mlx5 device structure to perform allocation on its context. 1306 * 1307 * @return 1308 * UAR object pointer on success, NULL otherwise and rte_errno is set. 1309 */ 1310 static void * 1311 mlx5_devx_alloc_uar(struct mlx5_common_device *cdev) 1312 { 1313 void *uar; 1314 uint32_t retry, uar_mapping; 1315 void *base_addr; 1316 1317 for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 1318 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1319 /* Control the mapping type according to the settings. */ 1320 uar_mapping = (cdev->config.dbnc == MLX5_SQ_DB_NCACHED) ? 1321 MLX5DV_UAR_ALLOC_TYPE_NC : MLX5DV_UAR_ALLOC_TYPE_BF; 1322 #else 1323 /* 1324 * It seems we have no way to control the memory mapping type 1325 * for the UAR, the default "Write-Combining" type is supposed. 1326 */ 1327 uar_mapping = 0; 1328 #endif 1329 uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 1330 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1331 if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 1332 /* 1333 * In some environments like virtual machine the 1334 * Write Combining mapped might be not supported and 1335 * UAR allocation fails. We tried "Non-Cached" mapping 1336 * for the case. 1337 */ 1338 DRV_LOG(DEBUG, "Failed to allocate DevX UAR (BF)"); 1339 uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 1340 uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 1341 } else if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 1342 /* 1343 * If Verbs/kernel does not support "Non-Cached" 1344 * try the "Write-Combining". 1345 */ 1346 DRV_LOG(DEBUG, "Failed to allocate DevX UAR (NC)"); 1347 uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 1348 uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 1349 } 1350 #endif 1351 if (!uar) { 1352 DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 1353 rte_errno = ENOMEM; 1354 goto exit; 1355 } 1356 base_addr = mlx5_os_get_devx_uar_base_addr(uar); 1357 if (base_addr) 1358 break; 1359 /* 1360 * The UARs are allocated by rdma_core within the 1361 * IB device context, on context closure all UARs 1362 * will be freed, should be no memory/object leakage. 1363 */ 1364 DRV_LOG(DEBUG, "Retrying to allocate DevX UAR"); 1365 uar = NULL; 1366 } 1367 /* Check whether we finally succeeded with valid UAR allocation. */ 1368 if (!uar) { 1369 DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 1370 rte_errno = ENOMEM; 1371 } 1372 /* 1373 * Return void * instead of struct mlx5dv_devx_uar * 1374 * is for compatibility with older rdma-core library headers. 1375 */ 1376 exit: 1377 return uar; 1378 } 1379 1380 void 1381 mlx5_devx_uar_release(struct mlx5_uar *uar) 1382 { 1383 if (uar->obj != NULL) 1384 mlx5_glue->devx_free_uar(uar->obj); 1385 memset(uar, 0, sizeof(*uar)); 1386 } 1387 1388 int 1389 mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar) 1390 { 1391 off_t uar_mmap_offset; 1392 const size_t page_size = rte_mem_page_size(); 1393 void *base_addr; 1394 void *uar_obj; 1395 1396 if (page_size == (size_t)-1) { 1397 DRV_LOG(ERR, "Failed to get mem page size"); 1398 rte_errno = ENOMEM; 1399 return -1; 1400 } 1401 uar_obj = mlx5_devx_alloc_uar(cdev); 1402 if (uar_obj == NULL || mlx5_os_get_devx_uar_reg_addr(uar_obj) == NULL) { 1403 rte_errno = errno; 1404 DRV_LOG(ERR, "Failed to allocate UAR."); 1405 return -1; 1406 } 1407 uar->obj = uar_obj; 1408 uar_mmap_offset = mlx5_os_get_devx_uar_mmap_offset(uar_obj); 1409 base_addr = mlx5_os_get_devx_uar_base_addr(uar_obj); 1410 uar->dbnc = mlx5_db_map_type_get(uar_mmap_offset, page_size); 1411 uar->bf_db.db = mlx5_os_get_devx_uar_reg_addr(uar_obj); 1412 uar->cq_db.db = RTE_PTR_ADD(base_addr, MLX5_CQ_DOORBELL); 1413 #ifndef RTE_ARCH_64 1414 rte_spinlock_init(&uar->bf_sl); 1415 rte_spinlock_init(&uar->cq_sl); 1416 uar->bf_db.sl_p = &uar->bf_sl; 1417 uar->cq_db.sl_p = &uar->cq_sl; 1418 #endif /* RTE_ARCH_64 */ 1419 return 0; 1420 } 1421 1422 RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__); 1423