17b4f1e6bSMatan Azrad /* SPDX-License-Identifier: BSD-3-Clause 27b4f1e6bSMatan Azrad * Copyright 2019 Mellanox Technologies, Ltd 37b4f1e6bSMatan Azrad */ 47b4f1e6bSMatan Azrad 57b4f1e6bSMatan Azrad #include <unistd.h> 67b4f1e6bSMatan Azrad #include <string.h> 793e30982SMatan Azrad #include <stdio.h> 87b4f1e6bSMatan Azrad 97b4f1e6bSMatan Azrad #include <rte_errno.h> 10262c7ad0SOri Kam #include <rte_mempool.h> 11ad435d32SXueming Li #include <rte_class.h> 12ad435d32SXueming Li #include <rte_malloc.h> 135dfa003dSMichael Baum #include <rte_eal_paging.h> 147b4f1e6bSMatan Azrad 157b4f1e6bSMatan Azrad #include "mlx5_common.h" 16262c7ad0SOri Kam #include "mlx5_common_os.h" 17fc59a1ecSMichael Baum #include "mlx5_common_mp.h" 1825245d5dSShiri Kuzin #include "mlx5_common_log.h" 19a77bedf2SMichael Baum #include "mlx5_common_defs.h" 20ad435d32SXueming Li #include "mlx5_common_private.h" 217b4f1e6bSMatan Azrad 224c204fe5SShiri Kuzin uint8_t haswell_broadwell_cpu; 234c204fe5SShiri Kuzin 244c204fe5SShiri Kuzin /* In case this is an x86_64 intel processor to check if 254c204fe5SShiri Kuzin * we should use relaxed ordering. 264c204fe5SShiri Kuzin */ 274c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 284c204fe5SShiri Kuzin /** 294c204fe5SShiri Kuzin * This function returns processor identification and feature information 304c204fe5SShiri Kuzin * into the registers. 314c204fe5SShiri Kuzin * 324c204fe5SShiri Kuzin * @param eax, ebx, ecx, edx 334c204fe5SShiri Kuzin * Pointers to the registers that will hold cpu information. 344c204fe5SShiri Kuzin * @param level 354c204fe5SShiri Kuzin * The main category of information returned. 364c204fe5SShiri Kuzin */ 374c204fe5SShiri Kuzin static inline void mlx5_cpu_id(unsigned int level, 384c204fe5SShiri Kuzin unsigned int *eax, unsigned int *ebx, 394c204fe5SShiri Kuzin unsigned int *ecx, unsigned int *edx) 404c204fe5SShiri Kuzin { 414c204fe5SShiri Kuzin __asm__("cpuid\n\t" 424c204fe5SShiri Kuzin : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 434c204fe5SShiri Kuzin : "0" (level)); 444c204fe5SShiri Kuzin } 454c204fe5SShiri Kuzin #endif 464c204fe5SShiri Kuzin 47eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE) 4883c99c36SThomas Monjalon 49ad435d32SXueming Li /* Head of list of drivers. */ 50ad435d32SXueming Li static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list = 51ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(drivers_list); 52ad435d32SXueming Li 53ad435d32SXueming Li /* Head of devices. */ 54ad435d32SXueming Li static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list = 55ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(devices_list); 56dc26c9c2SMichael Baum static pthread_mutex_t devices_list_lock; 57ad435d32SXueming Li 58ad435d32SXueming Li static const struct { 59ad435d32SXueming Li const char *name; 60ad435d32SXueming Li unsigned int drv_class; 61ad435d32SXueming Li } mlx5_classes[] = { 62ad435d32SXueming Li { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA }, 63ad435d32SXueming Li { .name = "eth", .drv_class = MLX5_CLASS_ETH }, 64ad435d32SXueming Li /* Keep class "net" for backward compatibility. */ 65ad435d32SXueming Li { .name = "net", .drv_class = MLX5_CLASS_ETH }, 66ad435d32SXueming Li { .name = "regex", .drv_class = MLX5_CLASS_REGEX }, 67ad435d32SXueming Li { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS }, 68ad435d32SXueming Li { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO }, 69ad435d32SXueming Li }; 70ad435d32SXueming Li 71ad435d32SXueming Li static int 72ad435d32SXueming Li class_name_to_value(const char *class_name) 73ad435d32SXueming Li { 74ad435d32SXueming Li unsigned int i; 75ad435d32SXueming Li 76ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 77ad435d32SXueming Li if (strcmp(class_name, mlx5_classes[i].name) == 0) 78ad435d32SXueming Li return mlx5_classes[i].drv_class; 79ad435d32SXueming Li } 80ad435d32SXueming Li return -EINVAL; 81ad435d32SXueming Li } 82ad435d32SXueming Li 83ad435d32SXueming Li static struct mlx5_class_driver * 84ad435d32SXueming Li driver_get(uint32_t class) 85ad435d32SXueming Li { 86ad435d32SXueming Li struct mlx5_class_driver *driver; 87ad435d32SXueming Li 88ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 89ad435d32SXueming Li if ((uint32_t)driver->drv_class == class) 90ad435d32SXueming Li return driver; 91ad435d32SXueming Li } 92ad435d32SXueming Li return NULL; 93ad435d32SXueming Li } 94ad435d32SXueming Li 9585209924SMichael Baum /** 9685209924SMichael Baum * Verify and store value for devargs. 9785209924SMichael Baum * 9885209924SMichael Baum * @param[in] key 9985209924SMichael Baum * Key argument to verify. 10085209924SMichael Baum * @param[in] val 10185209924SMichael Baum * Value associated with key. 10285209924SMichael Baum * @param opaque 10385209924SMichael Baum * User data. 10485209924SMichael Baum * 10585209924SMichael Baum * @return 10685209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 10785209924SMichael Baum */ 10885209924SMichael Baum static int 10985209924SMichael Baum mlx5_common_args_check_handler(const char *key, const char *val, void *opaque) 11085209924SMichael Baum { 11185209924SMichael Baum struct mlx5_common_dev_config *config = opaque; 11285209924SMichael Baum signed long tmp; 11385209924SMichael Baum 114a1d59091SMichael Baum if (val == NULL || *val == '\0') { 115a1d59091SMichael Baum DRV_LOG(ERR, "Key %s is missing value.", key); 116a1d59091SMichael Baum rte_errno = EINVAL; 117a1d59091SMichael Baum return -rte_errno; 118a1d59091SMichael Baum } 11985209924SMichael Baum errno = 0; 12085209924SMichael Baum tmp = strtol(val, NULL, 0); 12185209924SMichael Baum if (errno) { 12285209924SMichael Baum rte_errno = errno; 12385209924SMichael Baum DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val); 12485209924SMichael Baum return -rte_errno; 12585209924SMichael Baum } 12685209924SMichael Baum if (strcmp(key, "tx_db_nc") == 0) { 12785209924SMichael Baum if (tmp != MLX5_TXDB_CACHED && 12885209924SMichael Baum tmp != MLX5_TXDB_NCACHED && 12985209924SMichael Baum tmp != MLX5_TXDB_HEURISTIC) { 13085209924SMichael Baum DRV_LOG(ERR, "Invalid Tx doorbell mapping parameter."); 13185209924SMichael Baum rte_errno = EINVAL; 13285209924SMichael Baum return -rte_errno; 13385209924SMichael Baum } 13485209924SMichael Baum config->dbnc = tmp; 13585209924SMichael Baum } else if (strcmp(key, "mr_ext_memseg_en") == 0) { 13685209924SMichael Baum config->mr_ext_memseg_en = !!tmp; 13785209924SMichael Baum } else if (strcmp(key, "mr_mempool_reg_en") == 0) { 13885209924SMichael Baum config->mr_mempool_reg_en = !!tmp; 13985209924SMichael Baum } else if (strcmp(key, "sys_mem_en") == 0) { 14085209924SMichael Baum config->sys_mem_en = !!tmp; 14185209924SMichael Baum } 14285209924SMichael Baum return 0; 14385209924SMichael Baum } 14485209924SMichael Baum 14585209924SMichael Baum /** 14685209924SMichael Baum * Parse common device parameters. 14785209924SMichael Baum * 14885209924SMichael Baum * @param devargs 14985209924SMichael Baum * Device arguments structure. 15085209924SMichael Baum * @param config 15185209924SMichael Baum * Pointer to device configuration structure. 15285209924SMichael Baum * 15385209924SMichael Baum * @return 15485209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 15585209924SMichael Baum */ 15685209924SMichael Baum static int 15785209924SMichael Baum mlx5_common_config_get(struct rte_devargs *devargs, 15885209924SMichael Baum struct mlx5_common_dev_config *config) 15985209924SMichael Baum { 16085209924SMichael Baum struct rte_kvargs *kvlist; 16185209924SMichael Baum int ret = 0; 16285209924SMichael Baum 16385209924SMichael Baum /* Set defaults. */ 16485209924SMichael Baum config->mr_ext_memseg_en = 1; 16585209924SMichael Baum config->mr_mempool_reg_en = 1; 16685209924SMichael Baum config->sys_mem_en = 0; 16785209924SMichael Baum config->dbnc = MLX5_ARG_UNSET; 16885209924SMichael Baum if (devargs == NULL) 16985209924SMichael Baum return 0; 17085209924SMichael Baum kvlist = rte_kvargs_parse(devargs->args, NULL); 17185209924SMichael Baum if (kvlist == NULL) { 17285209924SMichael Baum rte_errno = EINVAL; 17385209924SMichael Baum return -rte_errno; 17485209924SMichael Baum } 17585209924SMichael Baum ret = rte_kvargs_process(kvlist, NULL, mlx5_common_args_check_handler, 17685209924SMichael Baum config); 17785209924SMichael Baum if (ret) 17885209924SMichael Baum ret = -rte_errno; 17985209924SMichael Baum rte_kvargs_free(kvlist); 18085209924SMichael Baum DRV_LOG(DEBUG, "mr_ext_memseg_en is %u.", config->mr_ext_memseg_en); 18185209924SMichael Baum DRV_LOG(DEBUG, "mr_mempool_reg_en is %u.", config->mr_mempool_reg_en); 18285209924SMichael Baum DRV_LOG(DEBUG, "sys_mem_en is %u.", config->sys_mem_en); 18385209924SMichael Baum DRV_LOG(DEBUG, "Tx doorbell mapping parameter is %d.", config->dbnc); 18485209924SMichael Baum return ret; 18585209924SMichael Baum } 18685209924SMichael Baum 187ad435d32SXueming Li static int 188ad435d32SXueming Li devargs_class_handler(__rte_unused const char *key, 189ad435d32SXueming Li const char *class_names, void *opaque) 190ad435d32SXueming Li { 191ad435d32SXueming Li int *ret = opaque; 192ad435d32SXueming Li int class_val; 193ad435d32SXueming Li char *scratch; 194ad435d32SXueming Li char *found; 195ad435d32SXueming Li char *refstr = NULL; 196ad435d32SXueming Li 197ad435d32SXueming Li *ret = 0; 198ad435d32SXueming Li scratch = strdup(class_names); 199ad435d32SXueming Li if (scratch == NULL) { 200ad435d32SXueming Li *ret = -ENOMEM; 201ad435d32SXueming Li return *ret; 202ad435d32SXueming Li } 203ad435d32SXueming Li found = strtok_r(scratch, ":", &refstr); 204ad435d32SXueming Li if (found == NULL) 205ad435d32SXueming Li /* Empty string. */ 206ad435d32SXueming Li goto err; 207ad435d32SXueming Li do { 208ad435d32SXueming Li /* Extract each individual class name. Multiple 209ad435d32SXueming Li * classes can be supplied as class=net:regex:foo:bar. 210ad435d32SXueming Li */ 211ad435d32SXueming Li class_val = class_name_to_value(found); 212ad435d32SXueming Li /* Check if its a valid class. */ 213ad435d32SXueming Li if (class_val < 0) { 214ad435d32SXueming Li *ret = -EINVAL; 215ad435d32SXueming Li goto err; 216ad435d32SXueming Li } 217ad435d32SXueming Li *ret |= class_val; 218ad435d32SXueming Li found = strtok_r(NULL, ":", &refstr); 219ad435d32SXueming Li } while (found != NULL); 220ad435d32SXueming Li err: 221ad435d32SXueming Li free(scratch); 222ad435d32SXueming Li if (*ret < 0) 223ad435d32SXueming Li DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names); 224ad435d32SXueming Li return *ret; 225ad435d32SXueming Li } 226ad435d32SXueming Li 227ad435d32SXueming Li static int 228ad435d32SXueming Li parse_class_options(const struct rte_devargs *devargs) 229ad435d32SXueming Li { 230ad435d32SXueming Li struct rte_kvargs *kvlist; 231ad435d32SXueming Li int ret = 0; 232ad435d32SXueming Li 233ad435d32SXueming Li if (devargs == NULL) 234ad435d32SXueming Li return 0; 235ad435d32SXueming Li if (devargs->cls != NULL && devargs->cls->name != NULL) 236ad435d32SXueming Li /* Global syntax, only one class type. */ 237ad435d32SXueming Li return class_name_to_value(devargs->cls->name); 238ad435d32SXueming Li /* Legacy devargs support multiple classes. */ 239ad435d32SXueming Li kvlist = rte_kvargs_parse(devargs->args, NULL); 240ad435d32SXueming Li if (kvlist == NULL) 241ad435d32SXueming Li return 0; 242ad435d32SXueming Li rte_kvargs_process(kvlist, RTE_DEVARGS_KEY_CLASS, 243ad435d32SXueming Li devargs_class_handler, &ret); 244ad435d32SXueming Li rte_kvargs_free(kvlist); 245ad435d32SXueming Li return ret; 246ad435d32SXueming Li } 247ad435d32SXueming Li 248ad435d32SXueming Li static const unsigned int mlx5_class_invalid_combinations[] = { 249ad435d32SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_VDPA, 250ad435d32SXueming Li /* New class combination should be added here. */ 251ad435d32SXueming Li }; 252ad435d32SXueming Li 253ad435d32SXueming Li static int 254ad435d32SXueming Li is_valid_class_combination(uint32_t user_classes) 255ad435d32SXueming Li { 256ad435d32SXueming Li unsigned int i; 257ad435d32SXueming Li 258ad435d32SXueming Li /* Verify if user specified unsupported combination. */ 259ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) { 260ad435d32SXueming Li if ((mlx5_class_invalid_combinations[i] & user_classes) == 261ad435d32SXueming Li mlx5_class_invalid_combinations[i]) 262ad435d32SXueming Li return -EINVAL; 263ad435d32SXueming Li } 264ad435d32SXueming Li /* Not found any invalid class combination. */ 265ad435d32SXueming Li return 0; 266ad435d32SXueming Li } 267ad435d32SXueming Li 268ad435d32SXueming Li static bool 269ad435d32SXueming Li mlx5_bus_match(const struct mlx5_class_driver *drv, 270ad435d32SXueming Li const struct rte_device *dev) 271ad435d32SXueming Li { 272ad435d32SXueming Li if (mlx5_dev_is_pci(dev)) 273ad435d32SXueming Li return mlx5_dev_pci_match(drv, dev); 274ad435d32SXueming Li return true; 275ad435d32SXueming Li } 276ad435d32SXueming Li 277ad435d32SXueming Li static struct mlx5_common_device * 278ad435d32SXueming Li to_mlx5_device(const struct rte_device *rte_dev) 279ad435d32SXueming Li { 28085209924SMichael Baum struct mlx5_common_device *cdev; 281ad435d32SXueming Li 28285209924SMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) { 28385209924SMichael Baum if (rte_dev == cdev->dev) 28485209924SMichael Baum return cdev; 285ad435d32SXueming Li } 286ad435d32SXueming Li return NULL; 287ad435d32SXueming Li } 288ad435d32SXueming Li 2894d567938SThomas Monjalon int 2904d567938SThomas Monjalon mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size) 2914d567938SThomas Monjalon { 2924d567938SThomas Monjalon struct rte_pci_addr pci_addr = { 0 }; 2934d567938SThomas Monjalon int ret; 2944d567938SThomas Monjalon 2954d567938SThomas Monjalon if (mlx5_dev_is_pci(dev)) { 2964d567938SThomas Monjalon /* Input might be <BDF>, format PCI address to <DBDF>. */ 2974d567938SThomas Monjalon ret = rte_pci_addr_parse(dev->name, &pci_addr); 2984d567938SThomas Monjalon if (ret != 0) 2994d567938SThomas Monjalon return -ENODEV; 3004d567938SThomas Monjalon rte_pci_device_name(&pci_addr, addr, size); 3014d567938SThomas Monjalon return 0; 3024d567938SThomas Monjalon } 3034d567938SThomas Monjalon #ifdef RTE_EXEC_ENV_LINUX 3044d567938SThomas Monjalon return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev), 3054d567938SThomas Monjalon addr, size); 3064d567938SThomas Monjalon #else 3074d567938SThomas Monjalon rte_errno = ENODEV; 3084d567938SThomas Monjalon return -rte_errno; 3094d567938SThomas Monjalon #endif 3104d567938SThomas Monjalon } 3114d567938SThomas Monjalon 312ca1418ceSMichael Baum /** 313fc59a1ecSMichael Baum * Register the mempool for the protection domain. 314fc59a1ecSMichael Baum * 315fc59a1ecSMichael Baum * @param cdev 316fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 317fc59a1ecSMichael Baum * @param mp 318fc59a1ecSMichael Baum * Mempool being registered. 319fc59a1ecSMichael Baum * 320fc59a1ecSMichael Baum * @return 321fc59a1ecSMichael Baum * 0 on success, (-1) on failure and rte_errno is set. 322fc59a1ecSMichael Baum */ 323fc59a1ecSMichael Baum static int 324fc59a1ecSMichael Baum mlx5_dev_mempool_register(struct mlx5_common_device *cdev, 32508ac0358SDmitry Kozlyuk struct rte_mempool *mp, bool is_extmem) 326fc59a1ecSMichael Baum { 32708ac0358SDmitry Kozlyuk return mlx5_mr_mempool_register(cdev, mp, is_extmem); 328fc59a1ecSMichael Baum } 329fc59a1ecSMichael Baum 330fc59a1ecSMichael Baum /** 331fc59a1ecSMichael Baum * Unregister the mempool from the protection domain. 332fc59a1ecSMichael Baum * 333fc59a1ecSMichael Baum * @param cdev 334fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 335fc59a1ecSMichael Baum * @param mp 336fc59a1ecSMichael Baum * Mempool being unregistered. 337fc59a1ecSMichael Baum */ 338fc59a1ecSMichael Baum void 339fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(struct mlx5_common_device *cdev, 340fc59a1ecSMichael Baum struct rte_mempool *mp) 341fc59a1ecSMichael Baum { 34220489176SMichael Baum if (mlx5_mr_mempool_unregister(cdev, mp) < 0) 343fc59a1ecSMichael Baum DRV_LOG(WARNING, "Failed to unregister mempool %s for PD %p: %s", 344fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 345fc59a1ecSMichael Baum } 346fc59a1ecSMichael Baum 347fc59a1ecSMichael Baum /** 348fc59a1ecSMichael Baum * rte_mempool_walk() callback to register mempools for the protection domain. 349fc59a1ecSMichael Baum * 350fc59a1ecSMichael Baum * @param mp 351fc59a1ecSMichael Baum * The mempool being walked. 352fc59a1ecSMichael Baum * @param arg 353fc59a1ecSMichael Baum * Pointer to the device shared context. 354fc59a1ecSMichael Baum */ 355fc59a1ecSMichael Baum static void 356fc59a1ecSMichael Baum mlx5_dev_mempool_register_cb(struct rte_mempool *mp, void *arg) 357fc59a1ecSMichael Baum { 358fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 359fc59a1ecSMichael Baum int ret; 360fc59a1ecSMichael Baum 36108ac0358SDmitry Kozlyuk ret = mlx5_dev_mempool_register(cdev, mp, false); 362fc59a1ecSMichael Baum if (ret < 0 && rte_errno != EEXIST) 363fc59a1ecSMichael Baum DRV_LOG(ERR, 364fc59a1ecSMichael Baum "Failed to register existing mempool %s for PD %p: %s", 365fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 366fc59a1ecSMichael Baum } 367fc59a1ecSMichael Baum 368fc59a1ecSMichael Baum /** 369fc59a1ecSMichael Baum * rte_mempool_walk() callback to unregister mempools 370fc59a1ecSMichael Baum * from the protection domain. 371fc59a1ecSMichael Baum * 372fc59a1ecSMichael Baum * @param mp 373fc59a1ecSMichael Baum * The mempool being walked. 374fc59a1ecSMichael Baum * @param arg 375fc59a1ecSMichael Baum * Pointer to the device shared context. 376fc59a1ecSMichael Baum */ 377fc59a1ecSMichael Baum static void 378fc59a1ecSMichael Baum mlx5_dev_mempool_unregister_cb(struct rte_mempool *mp, void *arg) 379fc59a1ecSMichael Baum { 380fc59a1ecSMichael Baum mlx5_dev_mempool_unregister((struct mlx5_common_device *)arg, mp); 381fc59a1ecSMichael Baum } 382fc59a1ecSMichael Baum 383fc59a1ecSMichael Baum /** 384fc59a1ecSMichael Baum * Mempool life cycle callback for mlx5 common devices. 385fc59a1ecSMichael Baum * 386fc59a1ecSMichael Baum * @param event 387fc59a1ecSMichael Baum * Mempool life cycle event. 388fc59a1ecSMichael Baum * @param mp 389fc59a1ecSMichael Baum * Associated mempool. 390fc59a1ecSMichael Baum * @param arg 391fc59a1ecSMichael Baum * Pointer to a device shared context. 392fc59a1ecSMichael Baum */ 393fc59a1ecSMichael Baum static void 394fc59a1ecSMichael Baum mlx5_dev_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp, 395fc59a1ecSMichael Baum void *arg) 396fc59a1ecSMichael Baum { 397fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 398fc59a1ecSMichael Baum 399fc59a1ecSMichael Baum switch (event) { 400fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_READY: 40108ac0358SDmitry Kozlyuk if (mlx5_dev_mempool_register(cdev, mp, false) < 0) 402fc59a1ecSMichael Baum DRV_LOG(ERR, 403fc59a1ecSMichael Baum "Failed to register new mempool %s for PD %p: %s", 404fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 405fc59a1ecSMichael Baum break; 406fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_DESTROY: 407fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(cdev, mp); 408fc59a1ecSMichael Baum break; 409fc59a1ecSMichael Baum } 410fc59a1ecSMichael Baum } 411fc59a1ecSMichael Baum 412fc59a1ecSMichael Baum int 413fc59a1ecSMichael Baum mlx5_dev_mempool_subscribe(struct mlx5_common_device *cdev) 414fc59a1ecSMichael Baum { 415fc59a1ecSMichael Baum int ret = 0; 416fc59a1ecSMichael Baum 417fc59a1ecSMichael Baum if (!cdev->config.mr_mempool_reg_en) 418fc59a1ecSMichael Baum return 0; 419fc59a1ecSMichael Baum rte_rwlock_write_lock(&cdev->mr_scache.mprwlock); 420fc59a1ecSMichael Baum if (cdev->mr_scache.mp_cb_registered) 421fc59a1ecSMichael Baum goto exit; 422fc59a1ecSMichael Baum /* Callback for this device may be already registered. */ 423fc59a1ecSMichael Baum ret = rte_mempool_event_callback_register(mlx5_dev_mempool_event_cb, 424fc59a1ecSMichael Baum cdev); 425fc59a1ecSMichael Baum if (ret != 0 && rte_errno != EEXIST) 426fc59a1ecSMichael Baum goto exit; 427fc59a1ecSMichael Baum /* Register mempools only once for this device. */ 428fc59a1ecSMichael Baum if (ret == 0) 429fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_register_cb, cdev); 430fc59a1ecSMichael Baum ret = 0; 431fc59a1ecSMichael Baum cdev->mr_scache.mp_cb_registered = 1; 432fc59a1ecSMichael Baum exit: 433fc59a1ecSMichael Baum rte_rwlock_write_unlock(&cdev->mr_scache.mprwlock); 434fc59a1ecSMichael Baum return ret; 435fc59a1ecSMichael Baum } 436fc59a1ecSMichael Baum 437fc59a1ecSMichael Baum static void 438fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(struct mlx5_common_device *cdev) 439fc59a1ecSMichael Baum { 440fc59a1ecSMichael Baum int ret; 441fc59a1ecSMichael Baum 442fc59a1ecSMichael Baum if (!cdev->mr_scache.mp_cb_registered || 443fc59a1ecSMichael Baum !cdev->config.mr_mempool_reg_en) 444fc59a1ecSMichael Baum return; 445fc59a1ecSMichael Baum /* Stop watching for mempool events and unregister all mempools. */ 446fc59a1ecSMichael Baum ret = rte_mempool_event_callback_unregister(mlx5_dev_mempool_event_cb, 447fc59a1ecSMichael Baum cdev); 448fc59a1ecSMichael Baum if (ret == 0) 449fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_unregister_cb, cdev); 450fc59a1ecSMichael Baum } 451fc59a1ecSMichael Baum 452fc59a1ecSMichael Baum /** 4539f1d636fSMichael Baum * Callback for memory event. 4549f1d636fSMichael Baum * 4559f1d636fSMichael Baum * @param event_type 4569f1d636fSMichael Baum * Memory event type. 4579f1d636fSMichael Baum * @param addr 4589f1d636fSMichael Baum * Address of memory. 4599f1d636fSMichael Baum * @param len 4609f1d636fSMichael Baum * Size of memory. 4619f1d636fSMichael Baum */ 4629f1d636fSMichael Baum static void 4639f1d636fSMichael Baum mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr, 4649f1d636fSMichael Baum size_t len, void *arg __rte_unused) 4659f1d636fSMichael Baum { 4669f1d636fSMichael Baum struct mlx5_common_device *cdev; 4679f1d636fSMichael Baum 4689f1d636fSMichael Baum /* Must be called from the primary process. */ 4699f1d636fSMichael Baum MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 4709f1d636fSMichael Baum switch (event_type) { 4719f1d636fSMichael Baum case RTE_MEM_EVENT_FREE: 4729f1d636fSMichael Baum pthread_mutex_lock(&devices_list_lock); 4739f1d636fSMichael Baum /* Iterate all the existing mlx5 devices. */ 4749f1d636fSMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) 4759f1d636fSMichael Baum mlx5_free_mr_by_addr(&cdev->mr_scache, 4769f1d636fSMichael Baum mlx5_os_get_ctx_device_name 4779f1d636fSMichael Baum (cdev->ctx), 4789f1d636fSMichael Baum addr, len); 4799f1d636fSMichael Baum pthread_mutex_unlock(&devices_list_lock); 4809f1d636fSMichael Baum break; 4819f1d636fSMichael Baum case RTE_MEM_EVENT_ALLOC: 4829f1d636fSMichael Baum default: 4839f1d636fSMichael Baum break; 4849f1d636fSMichael Baum } 4859f1d636fSMichael Baum } 4869f1d636fSMichael Baum 4879f1d636fSMichael Baum /** 488ca1418ceSMichael Baum * Uninitialize all HW global of device context. 489ca1418ceSMichael Baum * 490ca1418ceSMichael Baum * @param cdev 491ca1418ceSMichael Baum * Pointer to mlx5 device structure. 492ca1418ceSMichael Baum * 493ca1418ceSMichael Baum * @return 494ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 495ca1418ceSMichael Baum */ 496ca1418ceSMichael Baum static void 497ca1418ceSMichael Baum mlx5_dev_hw_global_release(struct mlx5_common_device *cdev) 498ca1418ceSMichael Baum { 499e35ccf24SMichael Baum if (cdev->pd != NULL) { 500e35ccf24SMichael Baum claim_zero(mlx5_os_dealloc_pd(cdev->pd)); 501e35ccf24SMichael Baum cdev->pd = NULL; 502e35ccf24SMichael Baum } 503ca1418ceSMichael Baum if (cdev->ctx != NULL) { 504ca1418ceSMichael Baum claim_zero(mlx5_glue->close_device(cdev->ctx)); 505ca1418ceSMichael Baum cdev->ctx = NULL; 506ca1418ceSMichael Baum } 507ca1418ceSMichael Baum } 508ca1418ceSMichael Baum 509ca1418ceSMichael Baum /** 510ca1418ceSMichael Baum * Initialize all HW global of device context. 511ca1418ceSMichael Baum * 512ca1418ceSMichael Baum * @param cdev 513ca1418ceSMichael Baum * Pointer to mlx5 device structure. 514ca1418ceSMichael Baum * @param classes 515ca1418ceSMichael Baum * Chosen classes come from user device arguments. 516ca1418ceSMichael Baum * 517ca1418ceSMichael Baum * @return 518ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 519ca1418ceSMichael Baum */ 520ca1418ceSMichael Baum static int 521ca1418ceSMichael Baum mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes) 522ca1418ceSMichael Baum { 523ca1418ceSMichael Baum int ret; 524ca1418ceSMichael Baum 525ca1418ceSMichael Baum /* Create context device */ 526ca1418ceSMichael Baum ret = mlx5_os_open_device(cdev, classes); 527ca1418ceSMichael Baum if (ret < 0) 528ca1418ceSMichael Baum return ret; 529e35ccf24SMichael Baum /* Allocate Protection Domain object and extract its pdn. */ 530e35ccf24SMichael Baum ret = mlx5_os_pd_create(cdev); 531e35ccf24SMichael Baum if (ret) 532e35ccf24SMichael Baum goto error; 533fe46b20cSMichael Baum /* All actions taken below are relevant only when DevX is supported */ 534fe46b20cSMichael Baum if (cdev->config.devx == 0) 535fe46b20cSMichael Baum return 0; 536fe46b20cSMichael Baum /* Query HCA attributes. */ 537fe46b20cSMichael Baum ret = mlx5_devx_cmd_query_hca_attr(cdev->ctx, &cdev->config.hca_attr); 538fe46b20cSMichael Baum if (ret) { 539fe46b20cSMichael Baum DRV_LOG(ERR, "Unable to read HCA capabilities."); 540fe46b20cSMichael Baum rte_errno = ENOTSUP; 541fe46b20cSMichael Baum goto error; 542fe46b20cSMichael Baum } 543ca1418ceSMichael Baum return 0; 544e35ccf24SMichael Baum error: 545e35ccf24SMichael Baum mlx5_dev_hw_global_release(cdev); 546e35ccf24SMichael Baum return ret; 547ca1418ceSMichael Baum } 548ca1418ceSMichael Baum 549ad435d32SXueming Li static void 55085209924SMichael Baum mlx5_common_dev_release(struct mlx5_common_device *cdev) 551ad435d32SXueming Li { 552dc26c9c2SMichael Baum pthread_mutex_lock(&devices_list_lock); 55385209924SMichael Baum TAILQ_REMOVE(&devices_list, cdev, next); 554dc26c9c2SMichael Baum pthread_mutex_unlock(&devices_list_lock); 5559f1d636fSMichael Baum if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 5569f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 5579f1d636fSMichael Baum rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB", 5589f1d636fSMichael Baum NULL); 559fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(cdev); 5609f1d636fSMichael Baum mlx5_mr_release_cache(&cdev->mr_scache); 561ca1418ceSMichael Baum mlx5_dev_hw_global_release(cdev); 5629f1d636fSMichael Baum } 56385209924SMichael Baum rte_free(cdev); 56485209924SMichael Baum } 56585209924SMichael Baum 56685209924SMichael Baum static struct mlx5_common_device * 567ca1418ceSMichael Baum mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes) 56885209924SMichael Baum { 56985209924SMichael Baum struct mlx5_common_device *cdev; 57085209924SMichael Baum int ret; 57185209924SMichael Baum 57285209924SMichael Baum cdev = rte_zmalloc("mlx5_common_device", sizeof(*cdev), 0); 57385209924SMichael Baum if (!cdev) { 57485209924SMichael Baum DRV_LOG(ERR, "Device allocation failure."); 57585209924SMichael Baum rte_errno = ENOMEM; 57685209924SMichael Baum return NULL; 57785209924SMichael Baum } 57885209924SMichael Baum cdev->dev = eal_dev; 57985209924SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 58085209924SMichael Baum goto exit; 58185209924SMichael Baum /* Parse device parameters. */ 58285209924SMichael Baum ret = mlx5_common_config_get(eal_dev->devargs, &cdev->config); 58385209924SMichael Baum if (ret < 0) { 58485209924SMichael Baum DRV_LOG(ERR, "Failed to process device arguments: %s", 58585209924SMichael Baum strerror(rte_errno)); 58685209924SMichael Baum rte_free(cdev); 58785209924SMichael Baum return NULL; 58885209924SMichael Baum } 58985209924SMichael Baum mlx5_malloc_mem_select(cdev->config.sys_mem_en); 590ca1418ceSMichael Baum /* Initialize all HW global of device context. */ 591ca1418ceSMichael Baum ret = mlx5_dev_hw_global_prepare(cdev, classes); 592ca1418ceSMichael Baum if (ret) { 593ca1418ceSMichael Baum DRV_LOG(ERR, "Failed to initialize device context."); 594ca1418ceSMichael Baum rte_free(cdev); 595ca1418ceSMichael Baum return NULL; 596ca1418ceSMichael Baum } 5979f1d636fSMichael Baum /* Initialize global MR cache resources and update its functions. */ 5989f1d636fSMichael Baum ret = mlx5_mr_create_cache(&cdev->mr_scache, eal_dev->numa_node); 5999f1d636fSMichael Baum if (ret) { 6009f1d636fSMichael Baum DRV_LOG(ERR, "Failed to initialize global MR share cache."); 6019f1d636fSMichael Baum mlx5_dev_hw_global_release(cdev); 6029f1d636fSMichael Baum rte_free(cdev); 6039f1d636fSMichael Baum return NULL; 6049f1d636fSMichael Baum } 6059f1d636fSMichael Baum /* Register callback function for global shared MR cache management. */ 6069f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 6079f1d636fSMichael Baum rte_mem_event_callback_register("MLX5_MEM_EVENT_CB", 6089f1d636fSMichael Baum mlx5_mr_mem_event_cb, NULL); 60985209924SMichael Baum exit: 61085209924SMichael Baum pthread_mutex_lock(&devices_list_lock); 61185209924SMichael Baum TAILQ_INSERT_HEAD(&devices_list, cdev, next); 61285209924SMichael Baum pthread_mutex_unlock(&devices_list_lock); 61385209924SMichael Baum return cdev; 614ad435d32SXueming Li } 615ad435d32SXueming Li 616ad435d32SXueming Li static int 61785209924SMichael Baum drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes) 618ad435d32SXueming Li { 619ad435d32SXueming Li struct mlx5_class_driver *driver; 620ad435d32SXueming Li int local_ret = -ENODEV; 621ad435d32SXueming Li unsigned int i = 0; 622ad435d32SXueming Li int ret = 0; 623ad435d32SXueming Li 624ad435d32SXueming Li while (enabled_classes) { 625ad435d32SXueming Li driver = driver_get(RTE_BIT64(i)); 626ad435d32SXueming Li if (driver != NULL) { 62785209924SMichael Baum local_ret = driver->remove(cdev); 628ad435d32SXueming Li if (local_ret == 0) 62985209924SMichael Baum cdev->classes_loaded &= ~RTE_BIT64(i); 630ad435d32SXueming Li else if (ret == 0) 631ad435d32SXueming Li ret = local_ret; 632ad435d32SXueming Li } 633ad435d32SXueming Li enabled_classes &= ~RTE_BIT64(i); 634ad435d32SXueming Li i++; 635ad435d32SXueming Li } 636ad435d32SXueming Li if (local_ret != 0 && ret == 0) 637ad435d32SXueming Li ret = local_ret; 638ad435d32SXueming Li return ret; 639ad435d32SXueming Li } 640ad435d32SXueming Li 641ad435d32SXueming Li static int 64285209924SMichael Baum drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes) 643ad435d32SXueming Li { 644ad435d32SXueming Li struct mlx5_class_driver *driver; 645ad435d32SXueming Li uint32_t enabled_classes = 0; 646ad435d32SXueming Li bool already_loaded; 647*b4a4159dSBing Zhao int ret = -EINVAL; 648ad435d32SXueming Li 649ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 650ad435d32SXueming Li if ((driver->drv_class & user_classes) == 0) 651ad435d32SXueming Li continue; 65285209924SMichael Baum if (!mlx5_bus_match(driver, cdev->dev)) 653ad435d32SXueming Li continue; 65485209924SMichael Baum already_loaded = cdev->classes_loaded & driver->drv_class; 655ad435d32SXueming Li if (already_loaded && driver->probe_again == 0) { 656ad435d32SXueming Li DRV_LOG(ERR, "Device %s is already probed", 65785209924SMichael Baum cdev->dev->name); 658ad435d32SXueming Li ret = -EEXIST; 659ad435d32SXueming Li goto probe_err; 660ad435d32SXueming Li } 66185209924SMichael Baum ret = driver->probe(cdev); 662ad435d32SXueming Li if (ret < 0) { 663ad435d32SXueming Li DRV_LOG(ERR, "Failed to load driver %s", 664ad435d32SXueming Li driver->name); 665ad435d32SXueming Li goto probe_err; 666ad435d32SXueming Li } 667ad435d32SXueming Li enabled_classes |= driver->drv_class; 668ad435d32SXueming Li } 669*b4a4159dSBing Zhao if (!ret) { 67085209924SMichael Baum cdev->classes_loaded |= enabled_classes; 671ad435d32SXueming Li return 0; 672*b4a4159dSBing Zhao } 673ad435d32SXueming Li probe_err: 6748928997aSMichael Baum /* 6758928997aSMichael Baum * Need to remove only drivers which were not probed before this probe 6768928997aSMichael Baum * instance, but have already been probed before this failure. 677ad435d32SXueming Li */ 6788928997aSMichael Baum enabled_classes &= ~cdev->classes_loaded; 67985209924SMichael Baum drivers_remove(cdev, enabled_classes); 680ad435d32SXueming Li return ret; 681ad435d32SXueming Li } 682ad435d32SXueming Li 683ad435d32SXueming Li int 684ad435d32SXueming Li mlx5_common_dev_probe(struct rte_device *eal_dev) 685ad435d32SXueming Li { 68685209924SMichael Baum struct mlx5_common_device *cdev; 687ad435d32SXueming Li uint32_t classes = 0; 688ad435d32SXueming Li bool new_device = false; 689ad435d32SXueming Li int ret; 690ad435d32SXueming Li 691ad435d32SXueming Li DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name); 692ad435d32SXueming Li ret = parse_class_options(eal_dev->devargs); 693ad435d32SXueming Li if (ret < 0) { 694ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 class type: %s", 695ad435d32SXueming Li eal_dev->devargs->args); 696ad435d32SXueming Li return ret; 697ad435d32SXueming Li } 698ad435d32SXueming Li classes = ret; 699ad435d32SXueming Li if (classes == 0) 700ad435d32SXueming Li /* Default to net class. */ 701ad435d32SXueming Li classes = MLX5_CLASS_ETH; 70285209924SMichael Baum cdev = to_mlx5_device(eal_dev); 70385209924SMichael Baum if (!cdev) { 704ca1418ceSMichael Baum cdev = mlx5_common_dev_create(eal_dev, classes); 70585209924SMichael Baum if (!cdev) 706ad435d32SXueming Li return -ENOMEM; 707ad435d32SXueming Li new_device = true; 708288d7c3fSMichael Baum } 709288d7c3fSMichael Baum /* 710288d7c3fSMichael Baum * Validate combination here. 711288d7c3fSMichael Baum * For new device, the classes_loaded field is 0 and it check only 712288d7c3fSMichael Baum * the classes given as user device arguments. 713288d7c3fSMichael Baum */ 71485209924SMichael Baum ret = is_valid_class_combination(classes | cdev->classes_loaded); 715ad435d32SXueming Li if (ret != 0) { 716ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 classes combination."); 717288d7c3fSMichael Baum goto class_err; 718ad435d32SXueming Li } 71985209924SMichael Baum ret = drivers_probe(cdev, classes); 720ad435d32SXueming Li if (ret) 721ad435d32SXueming Li goto class_err; 722ad435d32SXueming Li return 0; 723ad435d32SXueming Li class_err: 724ad435d32SXueming Li if (new_device) 72585209924SMichael Baum mlx5_common_dev_release(cdev); 726ad435d32SXueming Li return ret; 727ad435d32SXueming Li } 728ad435d32SXueming Li 729ad435d32SXueming Li int 730ad435d32SXueming Li mlx5_common_dev_remove(struct rte_device *eal_dev) 731ad435d32SXueming Li { 73285209924SMichael Baum struct mlx5_common_device *cdev; 733ad435d32SXueming Li int ret; 734ad435d32SXueming Li 73585209924SMichael Baum cdev = to_mlx5_device(eal_dev); 73685209924SMichael Baum if (!cdev) 737ad435d32SXueming Li return -ENODEV; 738ad435d32SXueming Li /* Matching device found, cleanup and unload drivers. */ 73985209924SMichael Baum ret = drivers_remove(cdev, cdev->classes_loaded); 740dffae63dSMichael Baum if (ret == 0) 74185209924SMichael Baum mlx5_common_dev_release(cdev); 742ad435d32SXueming Li return ret; 743ad435d32SXueming Li } 744ad435d32SXueming Li 745a5d06c90SMichael Baum /** 746a5d06c90SMichael Baum * Callback to DMA map external memory to a device. 747a5d06c90SMichael Baum * 748a5d06c90SMichael Baum * @param rte_dev 749a5d06c90SMichael Baum * Pointer to the generic device. 750a5d06c90SMichael Baum * @param addr 751a5d06c90SMichael Baum * Starting virtual address of memory to be mapped. 752a5d06c90SMichael Baum * @param iova 753a5d06c90SMichael Baum * Starting IOVA address of memory to be mapped. 754a5d06c90SMichael Baum * @param len 755a5d06c90SMichael Baum * Length of memory segment being mapped. 756a5d06c90SMichael Baum * 757a5d06c90SMichael Baum * @return 758a5d06c90SMichael Baum * 0 on success, negative value on error. 759a5d06c90SMichael Baum */ 760ad435d32SXueming Li int 761a5d06c90SMichael Baum mlx5_common_dev_dma_map(struct rte_device *rte_dev, void *addr, 762a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len) 763ad435d32SXueming Li { 764a5d06c90SMichael Baum struct mlx5_common_device *dev; 765a5d06c90SMichael Baum struct mlx5_mr *mr; 766ad435d32SXueming Li 767a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 768a5d06c90SMichael Baum if (!dev) { 769a5d06c90SMichael Baum DRV_LOG(WARNING, 770a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s", 771a5d06c90SMichael Baum rte_dev->name); 772a5d06c90SMichael Baum rte_errno = ENODEV; 773a5d06c90SMichael Baum return -1; 774ad435d32SXueming Li } 775a5d06c90SMichael Baum mr = mlx5_create_mr_ext(dev->pd, (uintptr_t)addr, len, 776a5d06c90SMichael Baum SOCKET_ID_ANY, dev->mr_scache.reg_mr_cb); 777a5d06c90SMichael Baum if (!mr) { 778a5d06c90SMichael Baum DRV_LOG(WARNING, "Device %s unable to DMA map", rte_dev->name); 779a5d06c90SMichael Baum rte_errno = EINVAL; 780a5d06c90SMichael Baum return -1; 781ad435d32SXueming Li } 782a5d06c90SMichael Baum rte_rwlock_write_lock(&dev->mr_scache.rwlock); 783a5d06c90SMichael Baum LIST_INSERT_HEAD(&dev->mr_scache.mr_list, mr, mr); 784a5d06c90SMichael Baum /* Insert to the global cache table. */ 785a5d06c90SMichael Baum mlx5_mr_insert_cache(&dev->mr_scache, mr); 786a5d06c90SMichael Baum rte_rwlock_write_unlock(&dev->mr_scache.rwlock); 787a5d06c90SMichael Baum return 0; 788ad435d32SXueming Li } 789ad435d32SXueming Li 790a5d06c90SMichael Baum /** 791a5d06c90SMichael Baum * Callback to DMA unmap external memory to a device. 792a5d06c90SMichael Baum * 793a5d06c90SMichael Baum * @param rte_dev 794a5d06c90SMichael Baum * Pointer to the generic device. 795a5d06c90SMichael Baum * @param addr 796a5d06c90SMichael Baum * Starting virtual address of memory to be unmapped. 797a5d06c90SMichael Baum * @param iova 798a5d06c90SMichael Baum * Starting IOVA address of memory to be unmapped. 799a5d06c90SMichael Baum * @param len 800a5d06c90SMichael Baum * Length of memory segment being unmapped. 801a5d06c90SMichael Baum * 802a5d06c90SMichael Baum * @return 803a5d06c90SMichael Baum * 0 on success, negative value on error. 804a5d06c90SMichael Baum */ 805ad435d32SXueming Li int 806a5d06c90SMichael Baum mlx5_common_dev_dma_unmap(struct rte_device *rte_dev, void *addr, 807a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len __rte_unused) 808ad435d32SXueming Li { 809a5d06c90SMichael Baum struct mlx5_common_device *dev; 810a5d06c90SMichael Baum struct mr_cache_entry entry; 811a5d06c90SMichael Baum struct mlx5_mr *mr; 812ad435d32SXueming Li 813a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 814a5d06c90SMichael Baum if (!dev) { 815a5d06c90SMichael Baum DRV_LOG(WARNING, 816a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s.", 817a5d06c90SMichael Baum rte_dev->name); 818a5d06c90SMichael Baum rte_errno = ENODEV; 819a5d06c90SMichael Baum return -1; 820ad435d32SXueming Li } 821a5d06c90SMichael Baum rte_rwlock_read_lock(&dev->mr_scache.rwlock); 822a5d06c90SMichael Baum mr = mlx5_mr_lookup_list(&dev->mr_scache, &entry, (uintptr_t)addr); 823a5d06c90SMichael Baum if (!mr) { 824a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 825a5d06c90SMichael Baum DRV_LOG(WARNING, 826a5d06c90SMichael Baum "Address 0x%" PRIxPTR " wasn't registered to device %s", 827a5d06c90SMichael Baum (uintptr_t)addr, rte_dev->name); 828a5d06c90SMichael Baum rte_errno = EINVAL; 829a5d06c90SMichael Baum return -1; 830a5d06c90SMichael Baum } 831a5d06c90SMichael Baum LIST_REMOVE(mr, mr); 832a5d06c90SMichael Baum DRV_LOG(DEBUG, "MR(%p) is removed from list.", (void *)mr); 833a5d06c90SMichael Baum mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb); 834a5d06c90SMichael Baum mlx5_mr_rebuild_cache(&dev->mr_scache); 835a5d06c90SMichael Baum /* 836a5d06c90SMichael Baum * No explicit wmb is needed after updating dev_gen due to 837a5d06c90SMichael Baum * store-release ordering in unlock that provides the 838a5d06c90SMichael Baum * implicit barrier at the software visible level. 839a5d06c90SMichael Baum */ 840a5d06c90SMichael Baum ++dev->mr_scache.dev_gen; 841a5d06c90SMichael Baum DRV_LOG(DEBUG, "Broadcasting local cache flush, gen=%d.", 842a5d06c90SMichael Baum dev->mr_scache.dev_gen); 843a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 844a5d06c90SMichael Baum return 0; 845ad435d32SXueming Li } 846ad435d32SXueming Li 847ad435d32SXueming Li void 848ad435d32SXueming Li mlx5_class_driver_register(struct mlx5_class_driver *driver) 849ad435d32SXueming Li { 850ad435d32SXueming Li mlx5_common_driver_on_register_pci(driver); 851ad435d32SXueming Li TAILQ_INSERT_TAIL(&drivers_list, driver, next); 852ad435d32SXueming Li } 853ad435d32SXueming Li 854ad435d32SXueming Li static void mlx5_common_driver_init(void) 855ad435d32SXueming Li { 856ad435d32SXueming Li mlx5_common_pci_init(); 857777b72a9SXueming Li #ifdef RTE_EXEC_ENV_LINUX 858777b72a9SXueming Li mlx5_common_auxiliary_init(); 859777b72a9SXueming Li #endif 860ad435d32SXueming Li } 861ad435d32SXueming Li 86282088001SParav Pandit static bool mlx5_common_initialized; 86382088001SParav Pandit 86483c99c36SThomas Monjalon /** 8657be78d02SJosh Soref * One time initialization routine for run-time dependency on glue library 86682088001SParav Pandit * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 86782088001SParav Pandit * must invoke in its constructor. 86883c99c36SThomas Monjalon */ 86982088001SParav Pandit void 87082088001SParav Pandit mlx5_common_init(void) 87183c99c36SThomas Monjalon { 87282088001SParav Pandit if (mlx5_common_initialized) 87382088001SParav Pandit return; 87482088001SParav Pandit 875dc26c9c2SMichael Baum pthread_mutex_init(&devices_list_lock, NULL); 87679aa4307SOphir Munk mlx5_glue_constructor(); 877ad435d32SXueming Li mlx5_common_driver_init(); 87882088001SParav Pandit mlx5_common_initialized = true; 8797b4f1e6bSMatan Azrad } 8804c204fe5SShiri Kuzin 8814c204fe5SShiri Kuzin /** 8824c204fe5SShiri Kuzin * This function is responsible of initializing the variable 8834c204fe5SShiri Kuzin * haswell_broadwell_cpu by checking if the cpu is intel 8844c204fe5SShiri Kuzin * and reading the data returned from mlx5_cpu_id(). 8854c204fe5SShiri Kuzin * since haswell and broadwell cpus don't have improved performance 8864c204fe5SShiri Kuzin * when using relaxed ordering we want to check the cpu type before 8874c204fe5SShiri Kuzin * before deciding whether to enable RO or not. 8884c204fe5SShiri Kuzin * if the cpu is haswell or broadwell the variable will be set to 1 8894c204fe5SShiri Kuzin * otherwise it will be 0. 8904c204fe5SShiri Kuzin */ 8914c204fe5SShiri Kuzin RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 8924c204fe5SShiri Kuzin { 8934c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 8944c204fe5SShiri Kuzin unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 8954c204fe5SShiri Kuzin unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 8964c204fe5SShiri Kuzin unsigned int i, model, family, brand_id, vendor; 8974c204fe5SShiri Kuzin unsigned int signature_intel_ebx = 0x756e6547; 8984c204fe5SShiri Kuzin unsigned int extended_model; 8994c204fe5SShiri Kuzin unsigned int eax = 0; 9004c204fe5SShiri Kuzin unsigned int ebx = 0; 9014c204fe5SShiri Kuzin unsigned int ecx = 0; 9024c204fe5SShiri Kuzin unsigned int edx = 0; 9034c204fe5SShiri Kuzin int max_level; 9044c204fe5SShiri Kuzin 9054c204fe5SShiri Kuzin mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 9064c204fe5SShiri Kuzin vendor = ebx; 9074c204fe5SShiri Kuzin max_level = eax; 9084c204fe5SShiri Kuzin if (max_level < 1) { 9094c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 9104c204fe5SShiri Kuzin return; 9114c204fe5SShiri Kuzin } 9124c204fe5SShiri Kuzin mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 9134c204fe5SShiri Kuzin model = (eax >> 4) & 0x0f; 9144c204fe5SShiri Kuzin family = (eax >> 8) & 0x0f; 9154c204fe5SShiri Kuzin brand_id = ebx & 0xff; 9164c204fe5SShiri Kuzin extended_model = (eax >> 12) & 0xf0; 9174c204fe5SShiri Kuzin /* Check if the processor is Haswell or Broadwell */ 9184c204fe5SShiri Kuzin if (vendor == signature_intel_ebx) { 9194c204fe5SShiri Kuzin if (family == 0x06) 9204c204fe5SShiri Kuzin model += extended_model; 9214c204fe5SShiri Kuzin if (brand_id == 0 && family == 0x6) { 9224c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(broadwell_models); i++) 9234c204fe5SShiri Kuzin if (model == broadwell_models[i]) { 9244c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 9254c204fe5SShiri Kuzin return; 9264c204fe5SShiri Kuzin } 9274c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(haswell_models); i++) 9284c204fe5SShiri Kuzin if (model == haswell_models[i]) { 9294c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 9304c204fe5SShiri Kuzin return; 9314c204fe5SShiri Kuzin } 9324c204fe5SShiri Kuzin } 9334c204fe5SShiri Kuzin } 9344c204fe5SShiri Kuzin #endif 9354c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 9364c204fe5SShiri Kuzin } 937262c7ad0SOri Kam 938262c7ad0SOri Kam /** 9399cc0e99cSViacheslav Ovsiienko * Allocate the User Access Region with DevX on specified device. 940b4371d3dSMichael Baum * This routine handles the following UAR allocation issues: 9419cc0e99cSViacheslav Ovsiienko * 9425dfa003dSMichael Baum * - Try to allocate the UAR with the most appropriate memory mapping 943b4371d3dSMichael Baum * type from the ones supported by the host. 944b4371d3dSMichael Baum * 9455dfa003dSMichael Baum * - Try to allocate the UAR with non-NULL base address OFED 5.0.x and 946b4371d3dSMichael Baum * Upstream rdma_core before v29 returned the NULL as UAR base address 947b4371d3dSMichael Baum * if UAR was not the first object in the UAR page. 948b4371d3dSMichael Baum * It caused the PMD failure and we should try to get another UAR till 949b4371d3dSMichael Baum * we get the first one with non-NULL base address returned. 950b4371d3dSMichael Baum * 951b4371d3dSMichael Baum * @param [in] cdev 952b4371d3dSMichael Baum * Pointer to mlx5 device structure to perform allocation on its context. 9539cc0e99cSViacheslav Ovsiienko * 9549cc0e99cSViacheslav Ovsiienko * @return 9559cc0e99cSViacheslav Ovsiienko * UAR object pointer on success, NULL otherwise and rte_errno is set. 9569cc0e99cSViacheslav Ovsiienko */ 9575dfa003dSMichael Baum static void * 958b4371d3dSMichael Baum mlx5_devx_alloc_uar(struct mlx5_common_device *cdev) 9599cc0e99cSViacheslav Ovsiienko { 9609cc0e99cSViacheslav Ovsiienko void *uar; 9619cc0e99cSViacheslav Ovsiienko uint32_t retry, uar_mapping; 9629cc0e99cSViacheslav Ovsiienko void *base_addr; 9639cc0e99cSViacheslav Ovsiienko 9649cc0e99cSViacheslav Ovsiienko for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 9659cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 9669cc0e99cSViacheslav Ovsiienko /* Control the mapping type according to the settings. */ 967b4371d3dSMichael Baum uar_mapping = (cdev->config.dbnc == MLX5_TXDB_NCACHED) ? 968b4371d3dSMichael Baum MLX5DV_UAR_ALLOC_TYPE_NC : MLX5DV_UAR_ALLOC_TYPE_BF; 9699cc0e99cSViacheslav Ovsiienko #else 9709cc0e99cSViacheslav Ovsiienko /* 9719cc0e99cSViacheslav Ovsiienko * It seems we have no way to control the memory mapping type 9729cc0e99cSViacheslav Ovsiienko * for the UAR, the default "Write-Combining" type is supposed. 9739cc0e99cSViacheslav Ovsiienko */ 9749cc0e99cSViacheslav Ovsiienko uar_mapping = 0; 9759cc0e99cSViacheslav Ovsiienko #endif 976b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 9779cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 978b4371d3dSMichael Baum if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 979b4371d3dSMichael Baum /* 980b4371d3dSMichael Baum * In some environments like virtual machine the 981b4371d3dSMichael Baum * Write Combining mapped might be not supported and 982b4371d3dSMichael Baum * UAR allocation fails. We tried "Non-Cached" mapping 983b4371d3dSMichael Baum * for the case. 984b4371d3dSMichael Baum */ 985b4371d3dSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (BF)"); 986b4371d3dSMichael Baum uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 987b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 988b4371d3dSMichael Baum } else if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 9899cc0e99cSViacheslav Ovsiienko /* 9909cc0e99cSViacheslav Ovsiienko * If Verbs/kernel does not support "Non-Cached" 9919cc0e99cSViacheslav Ovsiienko * try the "Write-Combining". 9929cc0e99cSViacheslav Ovsiienko */ 9933f0e54feSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (NC)"); 9949cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 995b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 9969cc0e99cSViacheslav Ovsiienko } 9979cc0e99cSViacheslav Ovsiienko #endif 9989cc0e99cSViacheslav Ovsiienko if (!uar) { 9999cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 10009cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 10019cc0e99cSViacheslav Ovsiienko goto exit; 10029cc0e99cSViacheslav Ovsiienko } 10039cc0e99cSViacheslav Ovsiienko base_addr = mlx5_os_get_devx_uar_base_addr(uar); 10049cc0e99cSViacheslav Ovsiienko if (base_addr) 10059cc0e99cSViacheslav Ovsiienko break; 10069cc0e99cSViacheslav Ovsiienko /* 10079cc0e99cSViacheslav Ovsiienko * The UARs are allocated by rdma_core within the 10089cc0e99cSViacheslav Ovsiienko * IB device context, on context closure all UARs 10099cc0e99cSViacheslav Ovsiienko * will be freed, should be no memory/object leakage. 10109cc0e99cSViacheslav Ovsiienko */ 10113f0e54feSMichael Baum DRV_LOG(DEBUG, "Retrying to allocate DevX UAR"); 10129cc0e99cSViacheslav Ovsiienko uar = NULL; 10139cc0e99cSViacheslav Ovsiienko } 10149cc0e99cSViacheslav Ovsiienko /* Check whether we finally succeeded with valid UAR allocation. */ 10159cc0e99cSViacheslav Ovsiienko if (!uar) { 10169cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 10179cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 10189cc0e99cSViacheslav Ovsiienko } 10199cc0e99cSViacheslav Ovsiienko /* 10209cc0e99cSViacheslav Ovsiienko * Return void * instead of struct mlx5dv_devx_uar * 10219cc0e99cSViacheslav Ovsiienko * is for compatibility with older rdma-core library headers. 10229cc0e99cSViacheslav Ovsiienko */ 10239cc0e99cSViacheslav Ovsiienko exit: 10249cc0e99cSViacheslav Ovsiienko return uar; 10259cc0e99cSViacheslav Ovsiienko } 1026ad435d32SXueming Li 10275dfa003dSMichael Baum void 10285dfa003dSMichael Baum mlx5_devx_uar_release(struct mlx5_uar *uar) 10295dfa003dSMichael Baum { 10305dfa003dSMichael Baum if (uar->obj != NULL) 10315dfa003dSMichael Baum mlx5_glue->devx_free_uar(uar->obj); 10325dfa003dSMichael Baum memset(uar, 0, sizeof(*uar)); 10335dfa003dSMichael Baum } 10345dfa003dSMichael Baum 10355dfa003dSMichael Baum int 10365dfa003dSMichael Baum mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar) 10375dfa003dSMichael Baum { 10385dfa003dSMichael Baum off_t uar_mmap_offset; 10395dfa003dSMichael Baum const size_t page_size = rte_mem_page_size(); 10405dfa003dSMichael Baum void *base_addr; 10415dfa003dSMichael Baum void *uar_obj; 10425dfa003dSMichael Baum 10435dfa003dSMichael Baum if (page_size == (size_t)-1) { 10445dfa003dSMichael Baum DRV_LOG(ERR, "Failed to get mem page size"); 10455dfa003dSMichael Baum rte_errno = ENOMEM; 10465dfa003dSMichael Baum return -1; 10475dfa003dSMichael Baum } 10485dfa003dSMichael Baum uar_obj = mlx5_devx_alloc_uar(cdev); 10495dfa003dSMichael Baum if (uar_obj == NULL || mlx5_os_get_devx_uar_reg_addr(uar_obj) == NULL) { 10505dfa003dSMichael Baum rte_errno = errno; 10515dfa003dSMichael Baum DRV_LOG(ERR, "Failed to allocate UAR."); 10525dfa003dSMichael Baum return -1; 10535dfa003dSMichael Baum } 10545dfa003dSMichael Baum uar->obj = uar_obj; 10555dfa003dSMichael Baum uar_mmap_offset = mlx5_os_get_devx_uar_mmap_offset(uar_obj); 10565dfa003dSMichael Baum base_addr = mlx5_os_get_devx_uar_base_addr(uar_obj); 10575dfa003dSMichael Baum uar->dbnc = mlx5_db_map_type_get(uar_mmap_offset, page_size); 10585dfa003dSMichael Baum uar->bf_db.db = mlx5_os_get_devx_uar_reg_addr(uar_obj); 10595dfa003dSMichael Baum uar->cq_db.db = RTE_PTR_ADD(base_addr, MLX5_CQ_DOORBELL); 10605dfa003dSMichael Baum #ifndef RTE_ARCH_64 10615dfa003dSMichael Baum rte_spinlock_init(&uar->bf_sl); 10625dfa003dSMichael Baum rte_spinlock_init(&uar->cq_sl); 10635dfa003dSMichael Baum uar->bf_db.sl_p = &uar->bf_sl; 10645dfa003dSMichael Baum uar->cq_db.sl_p = &uar->cq_sl; 10655dfa003dSMichael Baum #endif /* RTE_ARCH_64 */ 10665dfa003dSMichael Baum return 0; 10675dfa003dSMichael Baum } 10685dfa003dSMichael Baum 1069ad435d32SXueming Li RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__); 1070