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