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 24*a729d2f0SMichael Baum /* Driver type key for new device global syntax. */ 25*a729d2f0SMichael Baum #define MLX5_DRIVER_KEY "driver" 26*a729d2f0SMichael Baum 27*a729d2f0SMichael Baum /* Enable extending memsegs when creating a MR. */ 28*a729d2f0SMichael Baum #define MLX5_MR_EXT_MEMSEG_EN "mr_ext_memseg_en" 29*a729d2f0SMichael Baum 30*a729d2f0SMichael Baum /* Device parameter to configure implicit registration of mempool memory. */ 31*a729d2f0SMichael Baum #define MLX5_MR_MEMPOOL_REG_EN "mr_mempool_reg_en" 32*a729d2f0SMichael Baum 33*a729d2f0SMichael Baum /* The default memory allocator used in PMD. */ 34*a729d2f0SMichael Baum #define MLX5_SYS_MEM_EN "sys_mem_en" 35*a729d2f0SMichael Baum 36*a729d2f0SMichael Baum /* 37*a729d2f0SMichael Baum * Device parameter to force doorbell register mapping 38*a729d2f0SMichael Baum * to non-cahed region eliminating the extra write memory barrier. 39*a729d2f0SMichael Baum */ 40*a729d2f0SMichael Baum #define MLX5_TX_DB_NC "tx_db_nc" 41*a729d2f0SMichael Baum 424c204fe5SShiri Kuzin /* In case this is an x86_64 intel processor to check if 434c204fe5SShiri Kuzin * we should use relaxed ordering. 444c204fe5SShiri Kuzin */ 454c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 464c204fe5SShiri Kuzin /** 474c204fe5SShiri Kuzin * This function returns processor identification and feature information 484c204fe5SShiri Kuzin * into the registers. 494c204fe5SShiri Kuzin * 504c204fe5SShiri Kuzin * @param eax, ebx, ecx, edx 514c204fe5SShiri Kuzin * Pointers to the registers that will hold cpu information. 524c204fe5SShiri Kuzin * @param level 534c204fe5SShiri Kuzin * The main category of information returned. 544c204fe5SShiri Kuzin */ 554c204fe5SShiri Kuzin static inline void mlx5_cpu_id(unsigned int level, 564c204fe5SShiri Kuzin unsigned int *eax, unsigned int *ebx, 574c204fe5SShiri Kuzin unsigned int *ecx, unsigned int *edx) 584c204fe5SShiri Kuzin { 594c204fe5SShiri Kuzin __asm__("cpuid\n\t" 604c204fe5SShiri Kuzin : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 614c204fe5SShiri Kuzin : "0" (level)); 624c204fe5SShiri Kuzin } 634c204fe5SShiri Kuzin #endif 644c204fe5SShiri Kuzin 65eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE) 6683c99c36SThomas Monjalon 67ad435d32SXueming Li /* Head of list of drivers. */ 68ad435d32SXueming Li static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list = 69ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(drivers_list); 70ad435d32SXueming Li 71ad435d32SXueming Li /* Head of devices. */ 72ad435d32SXueming Li static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list = 73ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(devices_list); 74dc26c9c2SMichael Baum static pthread_mutex_t devices_list_lock; 75ad435d32SXueming Li 76ad435d32SXueming Li static const struct { 77ad435d32SXueming Li const char *name; 78ad435d32SXueming Li unsigned int drv_class; 79ad435d32SXueming Li } mlx5_classes[] = { 80ad435d32SXueming Li { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA }, 81ad435d32SXueming Li { .name = "eth", .drv_class = MLX5_CLASS_ETH }, 82ad435d32SXueming Li /* Keep class "net" for backward compatibility. */ 83ad435d32SXueming Li { .name = "net", .drv_class = MLX5_CLASS_ETH }, 84ad435d32SXueming Li { .name = "regex", .drv_class = MLX5_CLASS_REGEX }, 85ad435d32SXueming Li { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS }, 86ad435d32SXueming Li { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO }, 87ad435d32SXueming Li }; 88ad435d32SXueming Li 89ad435d32SXueming Li static int 90ad435d32SXueming Li class_name_to_value(const char *class_name) 91ad435d32SXueming Li { 92ad435d32SXueming Li unsigned int i; 93ad435d32SXueming Li 94ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 95ad435d32SXueming Li if (strcmp(class_name, mlx5_classes[i].name) == 0) 96ad435d32SXueming Li return mlx5_classes[i].drv_class; 97ad435d32SXueming Li } 98ad435d32SXueming Li return -EINVAL; 99ad435d32SXueming Li } 100ad435d32SXueming Li 101ad435d32SXueming Li static struct mlx5_class_driver * 102ad435d32SXueming Li driver_get(uint32_t class) 103ad435d32SXueming Li { 104ad435d32SXueming Li struct mlx5_class_driver *driver; 105ad435d32SXueming Li 106ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 107ad435d32SXueming Li if ((uint32_t)driver->drv_class == class) 108ad435d32SXueming Li return driver; 109ad435d32SXueming Li } 110ad435d32SXueming Li return NULL; 111ad435d32SXueming Li } 112ad435d32SXueming Li 113*a729d2f0SMichael Baum int 114*a729d2f0SMichael Baum mlx5_kvargs_process(struct mlx5_kvargs_ctrl *mkvlist, const char *const keys[], 115*a729d2f0SMichael Baum arg_handler_t handler, void *opaque_arg) 116*a729d2f0SMichael Baum { 117*a729d2f0SMichael Baum const struct rte_kvargs_pair *pair; 118*a729d2f0SMichael Baum uint32_t i, j; 119*a729d2f0SMichael Baum 120*a729d2f0SMichael Baum MLX5_ASSERT(mkvlist && mkvlist->kvlist); 121*a729d2f0SMichael Baum /* Process parameters. */ 122*a729d2f0SMichael Baum for (i = 0; i < mkvlist->kvlist->count; i++) { 123*a729d2f0SMichael Baum pair = &mkvlist->kvlist->pairs[i]; 124*a729d2f0SMichael Baum for (j = 0; keys[j] != NULL; ++j) { 125*a729d2f0SMichael Baum if (strcmp(pair->key, keys[j]) != 0) 126*a729d2f0SMichael Baum continue; 127*a729d2f0SMichael Baum if ((*handler)(pair->key, pair->value, opaque_arg) < 0) 128*a729d2f0SMichael Baum return -1; 129*a729d2f0SMichael Baum mkvlist->is_used[i] = true; 130*a729d2f0SMichael Baum break; 131*a729d2f0SMichael Baum } 132*a729d2f0SMichael Baum } 133*a729d2f0SMichael Baum return 0; 134*a729d2f0SMichael Baum } 135*a729d2f0SMichael Baum 136*a729d2f0SMichael Baum /** 137*a729d2f0SMichael Baum * Prepare a mlx5 kvargs control. 138*a729d2f0SMichael Baum * 139*a729d2f0SMichael Baum * @param[out] mkvlist 140*a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 141*a729d2f0SMichael Baum * @param[in] devargs 142*a729d2f0SMichael Baum * The input string containing the key/value associations. 143*a729d2f0SMichael Baum * 144*a729d2f0SMichael Baum * @return 145*a729d2f0SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 146*a729d2f0SMichael Baum */ 147*a729d2f0SMichael Baum static int 148*a729d2f0SMichael Baum mlx5_kvargs_prepare(struct mlx5_kvargs_ctrl *mkvlist, 149*a729d2f0SMichael Baum const struct rte_devargs *devargs) 150*a729d2f0SMichael Baum { 151*a729d2f0SMichael Baum struct rte_kvargs *kvlist; 152*a729d2f0SMichael Baum uint32_t i; 153*a729d2f0SMichael Baum 154*a729d2f0SMichael Baum if (devargs == NULL) 155*a729d2f0SMichael Baum return 0; 156*a729d2f0SMichael Baum kvlist = rte_kvargs_parse(devargs->args, NULL); 157*a729d2f0SMichael Baum if (kvlist == NULL) { 158*a729d2f0SMichael Baum rte_errno = EINVAL; 159*a729d2f0SMichael Baum return -rte_errno; 160*a729d2f0SMichael Baum } 161*a729d2f0SMichael Baum /* 162*a729d2f0SMichael Baum * rte_kvargs_parse enable key without value, in mlx5 PMDs we disable 163*a729d2f0SMichael Baum * this syntax. 164*a729d2f0SMichael Baum */ 165*a729d2f0SMichael Baum for (i = 0; i < kvlist->count; i++) { 166*a729d2f0SMichael Baum const struct rte_kvargs_pair *pair = &kvlist->pairs[i]; 167*a729d2f0SMichael Baum if (pair->value == NULL || *(pair->value) == '\0') { 168*a729d2f0SMichael Baum DRV_LOG(ERR, "Key %s is missing value.", pair->key); 169*a729d2f0SMichael Baum rte_kvargs_free(kvlist); 170*a729d2f0SMichael Baum rte_errno = EINVAL; 171*a729d2f0SMichael Baum return -rte_errno; 172*a729d2f0SMichael Baum } 173*a729d2f0SMichael Baum } 174*a729d2f0SMichael Baum /* Makes sure all devargs used array is false. */ 175*a729d2f0SMichael Baum memset(mkvlist, 0, sizeof(*mkvlist)); 176*a729d2f0SMichael Baum mkvlist->kvlist = kvlist; 177*a729d2f0SMichael Baum DRV_LOG(DEBUG, "Parse successfully %u devargs.", 178*a729d2f0SMichael Baum mkvlist->kvlist->count); 179*a729d2f0SMichael Baum return 0; 180*a729d2f0SMichael Baum } 181*a729d2f0SMichael Baum 182*a729d2f0SMichael Baum /** 183*a729d2f0SMichael Baum * Release a mlx5 kvargs control. 184*a729d2f0SMichael Baum * 185*a729d2f0SMichael Baum * @param[out] mkvlist 186*a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 187*a729d2f0SMichael Baum */ 188*a729d2f0SMichael Baum static void 189*a729d2f0SMichael Baum mlx5_kvargs_release(struct mlx5_kvargs_ctrl *mkvlist) 190*a729d2f0SMichael Baum { 191*a729d2f0SMichael Baum if (mkvlist == NULL) 192*a729d2f0SMichael Baum return; 193*a729d2f0SMichael Baum rte_kvargs_free(mkvlist->kvlist); 194*a729d2f0SMichael Baum memset(mkvlist, 0, sizeof(*mkvlist)); 195*a729d2f0SMichael Baum } 196*a729d2f0SMichael Baum 197*a729d2f0SMichael Baum /** 198*a729d2f0SMichael Baum * Validate device arguments list. 199*a729d2f0SMichael Baum * It report about the first unknown parameter. 200*a729d2f0SMichael Baum * 201*a729d2f0SMichael Baum * @param[in] mkvlist 202*a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 203*a729d2f0SMichael Baum * 204*a729d2f0SMichael Baum * @return 205*a729d2f0SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 206*a729d2f0SMichael Baum */ 207*a729d2f0SMichael Baum static int 208*a729d2f0SMichael Baum mlx5_kvargs_validate(struct mlx5_kvargs_ctrl *mkvlist) 209*a729d2f0SMichael Baum { 210*a729d2f0SMichael Baum uint32_t i; 211*a729d2f0SMichael Baum 212*a729d2f0SMichael Baum /* Secondary process should not handle devargs. */ 213*a729d2f0SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 214*a729d2f0SMichael Baum return 0; 215*a729d2f0SMichael Baum if (mkvlist == NULL) 216*a729d2f0SMichael Baum return 0; 217*a729d2f0SMichael Baum for (i = 0; i < mkvlist->kvlist->count; i++) { 218*a729d2f0SMichael Baum if (mkvlist->is_used[i] == 0) { 219*a729d2f0SMichael Baum DRV_LOG(ERR, "Key \"%s\" " 220*a729d2f0SMichael Baum "is unknown for the provided classes.", 221*a729d2f0SMichael Baum mkvlist->kvlist->pairs[i].key); 222*a729d2f0SMichael Baum rte_errno = EINVAL; 223*a729d2f0SMichael Baum return -rte_errno; 224*a729d2f0SMichael Baum } 225*a729d2f0SMichael Baum } 226*a729d2f0SMichael Baum return 0; 227*a729d2f0SMichael Baum } 228*a729d2f0SMichael Baum 22985209924SMichael Baum /** 23085209924SMichael Baum * Verify and store value for devargs. 23185209924SMichael Baum * 23285209924SMichael Baum * @param[in] key 23385209924SMichael Baum * Key argument to verify. 23485209924SMichael Baum * @param[in] val 23585209924SMichael Baum * Value associated with key. 23685209924SMichael Baum * @param opaque 23785209924SMichael Baum * User data. 23885209924SMichael Baum * 23985209924SMichael Baum * @return 24085209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 24185209924SMichael Baum */ 24285209924SMichael Baum static int 24385209924SMichael Baum mlx5_common_args_check_handler(const char *key, const char *val, void *opaque) 24485209924SMichael Baum { 24585209924SMichael Baum struct mlx5_common_dev_config *config = opaque; 24685209924SMichael Baum signed long tmp; 24785209924SMichael Baum 248*a729d2f0SMichael Baum if (strcmp(MLX5_DRIVER_KEY, key) == 0 || 249*a729d2f0SMichael Baum strcmp(RTE_DEVARGS_KEY_CLASS, key) == 0) 250*a729d2f0SMichael Baum return 0; 25185209924SMichael Baum errno = 0; 25285209924SMichael Baum tmp = strtol(val, NULL, 0); 25385209924SMichael Baum if (errno) { 25485209924SMichael Baum rte_errno = errno; 25585209924SMichael Baum DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val); 25685209924SMichael Baum return -rte_errno; 25785209924SMichael Baum } 258*a729d2f0SMichael Baum if (strcmp(key, MLX5_TX_DB_NC) == 0) { 25985209924SMichael Baum if (tmp != MLX5_TXDB_CACHED && 26085209924SMichael Baum tmp != MLX5_TXDB_NCACHED && 26185209924SMichael Baum tmp != MLX5_TXDB_HEURISTIC) { 26285209924SMichael Baum DRV_LOG(ERR, "Invalid Tx doorbell mapping parameter."); 26385209924SMichael Baum rte_errno = EINVAL; 26485209924SMichael Baum return -rte_errno; 26585209924SMichael Baum } 26685209924SMichael Baum config->dbnc = tmp; 267*a729d2f0SMichael Baum } else if (strcmp(key, MLX5_MR_EXT_MEMSEG_EN) == 0) { 26885209924SMichael Baum config->mr_ext_memseg_en = !!tmp; 269*a729d2f0SMichael Baum } else if (strcmp(key, MLX5_MR_MEMPOOL_REG_EN) == 0) { 27085209924SMichael Baum config->mr_mempool_reg_en = !!tmp; 271*a729d2f0SMichael Baum } else if (strcmp(key, MLX5_SYS_MEM_EN) == 0) { 27285209924SMichael Baum config->sys_mem_en = !!tmp; 27385209924SMichael Baum } 27485209924SMichael Baum return 0; 27585209924SMichael Baum } 27685209924SMichael Baum 27785209924SMichael Baum /** 27885209924SMichael Baum * Parse common device parameters. 27985209924SMichael Baum * 28085209924SMichael Baum * @param devargs 28185209924SMichael Baum * Device arguments structure. 28285209924SMichael Baum * @param config 28385209924SMichael Baum * Pointer to device configuration structure. 28485209924SMichael Baum * 28585209924SMichael Baum * @return 28685209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 28785209924SMichael Baum */ 28885209924SMichael Baum static int 289*a729d2f0SMichael Baum mlx5_common_config_get(struct mlx5_kvargs_ctrl *mkvlist, 29085209924SMichael Baum struct mlx5_common_dev_config *config) 29185209924SMichael Baum { 292*a729d2f0SMichael Baum const char **params = (const char *[]){ 293*a729d2f0SMichael Baum RTE_DEVARGS_KEY_CLASS, 294*a729d2f0SMichael Baum MLX5_DRIVER_KEY, 295*a729d2f0SMichael Baum MLX5_TX_DB_NC, 296*a729d2f0SMichael Baum MLX5_MR_EXT_MEMSEG_EN, 297*a729d2f0SMichael Baum MLX5_SYS_MEM_EN, 298*a729d2f0SMichael Baum MLX5_MR_MEMPOOL_REG_EN, 299*a729d2f0SMichael Baum NULL, 300*a729d2f0SMichael Baum }; 30185209924SMichael Baum int ret = 0; 30285209924SMichael Baum 303*a729d2f0SMichael Baum if (mkvlist == NULL) 304*a729d2f0SMichael Baum return 0; 30585209924SMichael Baum /* Set defaults. */ 30685209924SMichael Baum config->mr_ext_memseg_en = 1; 30785209924SMichael Baum config->mr_mempool_reg_en = 1; 30885209924SMichael Baum config->sys_mem_en = 0; 30985209924SMichael Baum config->dbnc = MLX5_ARG_UNSET; 310*a729d2f0SMichael Baum /* Process common parameters. */ 311*a729d2f0SMichael Baum ret = mlx5_kvargs_process(mkvlist, params, 312*a729d2f0SMichael Baum mlx5_common_args_check_handler, config); 313*a729d2f0SMichael Baum if (ret) { 31485209924SMichael Baum rte_errno = EINVAL; 31585209924SMichael Baum ret = -rte_errno; 316*a729d2f0SMichael Baum } 31785209924SMichael Baum DRV_LOG(DEBUG, "mr_ext_memseg_en is %u.", config->mr_ext_memseg_en); 31885209924SMichael Baum DRV_LOG(DEBUG, "mr_mempool_reg_en is %u.", config->mr_mempool_reg_en); 31985209924SMichael Baum DRV_LOG(DEBUG, "sys_mem_en is %u.", config->sys_mem_en); 32085209924SMichael Baum DRV_LOG(DEBUG, "Tx doorbell mapping parameter is %d.", config->dbnc); 32185209924SMichael Baum return ret; 32285209924SMichael Baum } 32385209924SMichael Baum 324ad435d32SXueming Li static int 325ad435d32SXueming Li devargs_class_handler(__rte_unused const char *key, 326ad435d32SXueming Li const char *class_names, void *opaque) 327ad435d32SXueming Li { 328ad435d32SXueming Li int *ret = opaque; 329ad435d32SXueming Li int class_val; 330ad435d32SXueming Li char *scratch; 331ad435d32SXueming Li char *found; 332ad435d32SXueming Li char *refstr = NULL; 333ad435d32SXueming Li 334ad435d32SXueming Li *ret = 0; 335ad435d32SXueming Li scratch = strdup(class_names); 336ad435d32SXueming Li if (scratch == NULL) { 337ad435d32SXueming Li *ret = -ENOMEM; 338ad435d32SXueming Li return *ret; 339ad435d32SXueming Li } 340ad435d32SXueming Li found = strtok_r(scratch, ":", &refstr); 341ad435d32SXueming Li if (found == NULL) 342ad435d32SXueming Li /* Empty string. */ 343ad435d32SXueming Li goto err; 344ad435d32SXueming Li do { 345ad435d32SXueming Li /* Extract each individual class name. Multiple 346ad435d32SXueming Li * classes can be supplied as class=net:regex:foo:bar. 347ad435d32SXueming Li */ 348ad435d32SXueming Li class_val = class_name_to_value(found); 349ad435d32SXueming Li /* Check if its a valid class. */ 350ad435d32SXueming Li if (class_val < 0) { 351ad435d32SXueming Li *ret = -EINVAL; 352ad435d32SXueming Li goto err; 353ad435d32SXueming Li } 354ad435d32SXueming Li *ret |= class_val; 355ad435d32SXueming Li found = strtok_r(NULL, ":", &refstr); 356ad435d32SXueming Li } while (found != NULL); 357ad435d32SXueming Li err: 358ad435d32SXueming Li free(scratch); 359ad435d32SXueming Li if (*ret < 0) 360ad435d32SXueming Li DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names); 361ad435d32SXueming Li return *ret; 362ad435d32SXueming Li } 363ad435d32SXueming Li 364ad435d32SXueming Li static int 365*a729d2f0SMichael Baum parse_class_options(const struct rte_devargs *devargs, 366*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 367ad435d32SXueming Li { 368ad435d32SXueming Li int ret = 0; 369ad435d32SXueming Li 370ad435d32SXueming Li if (devargs == NULL) 371ad435d32SXueming Li return 0; 372ad435d32SXueming Li if (devargs->cls != NULL && devargs->cls->name != NULL) 373ad435d32SXueming Li /* Global syntax, only one class type. */ 374ad435d32SXueming Li return class_name_to_value(devargs->cls->name); 375ad435d32SXueming Li /* Legacy devargs support multiple classes. */ 376*a729d2f0SMichael Baum rte_kvargs_process(mkvlist->kvlist, RTE_DEVARGS_KEY_CLASS, 377ad435d32SXueming Li devargs_class_handler, &ret); 378ad435d32SXueming Li return ret; 379ad435d32SXueming Li } 380ad435d32SXueming Li 381ad435d32SXueming Li static const unsigned int mlx5_class_invalid_combinations[] = { 382ad435d32SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_VDPA, 383ad435d32SXueming Li /* New class combination should be added here. */ 384ad435d32SXueming Li }; 385ad435d32SXueming Li 386ad435d32SXueming Li static int 387ad435d32SXueming Li is_valid_class_combination(uint32_t user_classes) 388ad435d32SXueming Li { 389ad435d32SXueming Li unsigned int i; 390ad435d32SXueming Li 391ad435d32SXueming Li /* Verify if user specified unsupported combination. */ 392ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) { 393ad435d32SXueming Li if ((mlx5_class_invalid_combinations[i] & user_classes) == 394ad435d32SXueming Li mlx5_class_invalid_combinations[i]) 395ad435d32SXueming Li return -EINVAL; 396ad435d32SXueming Li } 397ad435d32SXueming Li /* Not found any invalid class combination. */ 398ad435d32SXueming Li return 0; 399ad435d32SXueming Li } 400ad435d32SXueming Li 401ad435d32SXueming Li static bool 402ad435d32SXueming Li mlx5_bus_match(const struct mlx5_class_driver *drv, 403ad435d32SXueming Li const struct rte_device *dev) 404ad435d32SXueming Li { 405ad435d32SXueming Li if (mlx5_dev_is_pci(dev)) 406ad435d32SXueming Li return mlx5_dev_pci_match(drv, dev); 407ad435d32SXueming Li return true; 408ad435d32SXueming Li } 409ad435d32SXueming Li 410ad435d32SXueming Li static struct mlx5_common_device * 411ad435d32SXueming Li to_mlx5_device(const struct rte_device *rte_dev) 412ad435d32SXueming Li { 41385209924SMichael Baum struct mlx5_common_device *cdev; 414ad435d32SXueming Li 41585209924SMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) { 41685209924SMichael Baum if (rte_dev == cdev->dev) 41785209924SMichael Baum return cdev; 418ad435d32SXueming Li } 419ad435d32SXueming Li return NULL; 420ad435d32SXueming Li } 421ad435d32SXueming Li 4224d567938SThomas Monjalon int 4234d567938SThomas Monjalon mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size) 4244d567938SThomas Monjalon { 4254d567938SThomas Monjalon struct rte_pci_addr pci_addr = { 0 }; 4264d567938SThomas Monjalon int ret; 4274d567938SThomas Monjalon 4284d567938SThomas Monjalon if (mlx5_dev_is_pci(dev)) { 4294d567938SThomas Monjalon /* Input might be <BDF>, format PCI address to <DBDF>. */ 4304d567938SThomas Monjalon ret = rte_pci_addr_parse(dev->name, &pci_addr); 4314d567938SThomas Monjalon if (ret != 0) 4324d567938SThomas Monjalon return -ENODEV; 4334d567938SThomas Monjalon rte_pci_device_name(&pci_addr, addr, size); 4344d567938SThomas Monjalon return 0; 4354d567938SThomas Monjalon } 4364d567938SThomas Monjalon #ifdef RTE_EXEC_ENV_LINUX 4374d567938SThomas Monjalon return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev), 4384d567938SThomas Monjalon addr, size); 4394d567938SThomas Monjalon #else 4404d567938SThomas Monjalon rte_errno = ENODEV; 4414d567938SThomas Monjalon return -rte_errno; 4424d567938SThomas Monjalon #endif 4434d567938SThomas Monjalon } 4444d567938SThomas Monjalon 445ca1418ceSMichael Baum /** 446fc59a1ecSMichael Baum * Register the mempool for the protection domain. 447fc59a1ecSMichael Baum * 448fc59a1ecSMichael Baum * @param cdev 449fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 450fc59a1ecSMichael Baum * @param mp 451fc59a1ecSMichael Baum * Mempool being registered. 452fc59a1ecSMichael Baum * 453fc59a1ecSMichael Baum * @return 454fc59a1ecSMichael Baum * 0 on success, (-1) on failure and rte_errno is set. 455fc59a1ecSMichael Baum */ 456fc59a1ecSMichael Baum static int 457fc59a1ecSMichael Baum mlx5_dev_mempool_register(struct mlx5_common_device *cdev, 45808ac0358SDmitry Kozlyuk struct rte_mempool *mp, bool is_extmem) 459fc59a1ecSMichael Baum { 46008ac0358SDmitry Kozlyuk return mlx5_mr_mempool_register(cdev, mp, is_extmem); 461fc59a1ecSMichael Baum } 462fc59a1ecSMichael Baum 463fc59a1ecSMichael Baum /** 464fc59a1ecSMichael Baum * Unregister the mempool from the protection domain. 465fc59a1ecSMichael Baum * 466fc59a1ecSMichael Baum * @param cdev 467fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 468fc59a1ecSMichael Baum * @param mp 469fc59a1ecSMichael Baum * Mempool being unregistered. 470fc59a1ecSMichael Baum */ 471fc59a1ecSMichael Baum void 472fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(struct mlx5_common_device *cdev, 473fc59a1ecSMichael Baum struct rte_mempool *mp) 474fc59a1ecSMichael Baum { 47520489176SMichael Baum if (mlx5_mr_mempool_unregister(cdev, mp) < 0) 476fc59a1ecSMichael Baum DRV_LOG(WARNING, "Failed to unregister mempool %s for PD %p: %s", 477fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 478fc59a1ecSMichael Baum } 479fc59a1ecSMichael Baum 480fc59a1ecSMichael Baum /** 481fc59a1ecSMichael Baum * rte_mempool_walk() callback to register mempools for the protection domain. 482fc59a1ecSMichael Baum * 483fc59a1ecSMichael Baum * @param mp 484fc59a1ecSMichael Baum * The mempool being walked. 485fc59a1ecSMichael Baum * @param arg 486fc59a1ecSMichael Baum * Pointer to the device shared context. 487fc59a1ecSMichael Baum */ 488fc59a1ecSMichael Baum static void 489fc59a1ecSMichael Baum mlx5_dev_mempool_register_cb(struct rte_mempool *mp, void *arg) 490fc59a1ecSMichael Baum { 491fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 492fc59a1ecSMichael Baum int ret; 493fc59a1ecSMichael Baum 49408ac0358SDmitry Kozlyuk ret = mlx5_dev_mempool_register(cdev, mp, false); 495fc59a1ecSMichael Baum if (ret < 0 && rte_errno != EEXIST) 496fc59a1ecSMichael Baum DRV_LOG(ERR, 497fc59a1ecSMichael Baum "Failed to register existing mempool %s for PD %p: %s", 498fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 499fc59a1ecSMichael Baum } 500fc59a1ecSMichael Baum 501fc59a1ecSMichael Baum /** 502fc59a1ecSMichael Baum * rte_mempool_walk() callback to unregister mempools 503fc59a1ecSMichael Baum * from the protection domain. 504fc59a1ecSMichael Baum * 505fc59a1ecSMichael Baum * @param mp 506fc59a1ecSMichael Baum * The mempool being walked. 507fc59a1ecSMichael Baum * @param arg 508fc59a1ecSMichael Baum * Pointer to the device shared context. 509fc59a1ecSMichael Baum */ 510fc59a1ecSMichael Baum static void 511fc59a1ecSMichael Baum mlx5_dev_mempool_unregister_cb(struct rte_mempool *mp, void *arg) 512fc59a1ecSMichael Baum { 513fc59a1ecSMichael Baum mlx5_dev_mempool_unregister((struct mlx5_common_device *)arg, mp); 514fc59a1ecSMichael Baum } 515fc59a1ecSMichael Baum 516fc59a1ecSMichael Baum /** 517fc59a1ecSMichael Baum * Mempool life cycle callback for mlx5 common devices. 518fc59a1ecSMichael Baum * 519fc59a1ecSMichael Baum * @param event 520fc59a1ecSMichael Baum * Mempool life cycle event. 521fc59a1ecSMichael Baum * @param mp 522fc59a1ecSMichael Baum * Associated mempool. 523fc59a1ecSMichael Baum * @param arg 524fc59a1ecSMichael Baum * Pointer to a device shared context. 525fc59a1ecSMichael Baum */ 526fc59a1ecSMichael Baum static void 527fc59a1ecSMichael Baum mlx5_dev_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp, 528fc59a1ecSMichael Baum void *arg) 529fc59a1ecSMichael Baum { 530fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 531fc59a1ecSMichael Baum 532fc59a1ecSMichael Baum switch (event) { 533fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_READY: 53408ac0358SDmitry Kozlyuk if (mlx5_dev_mempool_register(cdev, mp, false) < 0) 535fc59a1ecSMichael Baum DRV_LOG(ERR, 536fc59a1ecSMichael Baum "Failed to register new mempool %s for PD %p: %s", 537fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 538fc59a1ecSMichael Baum break; 539fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_DESTROY: 540fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(cdev, mp); 541fc59a1ecSMichael Baum break; 542fc59a1ecSMichael Baum } 543fc59a1ecSMichael Baum } 544fc59a1ecSMichael Baum 545fc59a1ecSMichael Baum int 546fc59a1ecSMichael Baum mlx5_dev_mempool_subscribe(struct mlx5_common_device *cdev) 547fc59a1ecSMichael Baum { 548fc59a1ecSMichael Baum int ret = 0; 549fc59a1ecSMichael Baum 550fc59a1ecSMichael Baum if (!cdev->config.mr_mempool_reg_en) 551fc59a1ecSMichael Baum return 0; 552fc59a1ecSMichael Baum rte_rwlock_write_lock(&cdev->mr_scache.mprwlock); 553fc59a1ecSMichael Baum if (cdev->mr_scache.mp_cb_registered) 554fc59a1ecSMichael Baum goto exit; 555fc59a1ecSMichael Baum /* Callback for this device may be already registered. */ 556fc59a1ecSMichael Baum ret = rte_mempool_event_callback_register(mlx5_dev_mempool_event_cb, 557fc59a1ecSMichael Baum cdev); 558fc59a1ecSMichael Baum if (ret != 0 && rte_errno != EEXIST) 559fc59a1ecSMichael Baum goto exit; 560fc59a1ecSMichael Baum /* Register mempools only once for this device. */ 561fc59a1ecSMichael Baum if (ret == 0) 562fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_register_cb, cdev); 563fc59a1ecSMichael Baum ret = 0; 564fc59a1ecSMichael Baum cdev->mr_scache.mp_cb_registered = 1; 565fc59a1ecSMichael Baum exit: 566fc59a1ecSMichael Baum rte_rwlock_write_unlock(&cdev->mr_scache.mprwlock); 567fc59a1ecSMichael Baum return ret; 568fc59a1ecSMichael Baum } 569fc59a1ecSMichael Baum 570fc59a1ecSMichael Baum static void 571fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(struct mlx5_common_device *cdev) 572fc59a1ecSMichael Baum { 573fc59a1ecSMichael Baum int ret; 574fc59a1ecSMichael Baum 575fc59a1ecSMichael Baum if (!cdev->mr_scache.mp_cb_registered || 576fc59a1ecSMichael Baum !cdev->config.mr_mempool_reg_en) 577fc59a1ecSMichael Baum return; 578fc59a1ecSMichael Baum /* Stop watching for mempool events and unregister all mempools. */ 579fc59a1ecSMichael Baum ret = rte_mempool_event_callback_unregister(mlx5_dev_mempool_event_cb, 580fc59a1ecSMichael Baum cdev); 581fc59a1ecSMichael Baum if (ret == 0) 582fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_unregister_cb, cdev); 583fc59a1ecSMichael Baum } 584fc59a1ecSMichael Baum 585fc59a1ecSMichael Baum /** 5869f1d636fSMichael Baum * Callback for memory event. 5879f1d636fSMichael Baum * 5889f1d636fSMichael Baum * @param event_type 5899f1d636fSMichael Baum * Memory event type. 5909f1d636fSMichael Baum * @param addr 5919f1d636fSMichael Baum * Address of memory. 5929f1d636fSMichael Baum * @param len 5939f1d636fSMichael Baum * Size of memory. 5949f1d636fSMichael Baum */ 5959f1d636fSMichael Baum static void 5969f1d636fSMichael Baum mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr, 5979f1d636fSMichael Baum size_t len, void *arg __rte_unused) 5989f1d636fSMichael Baum { 5999f1d636fSMichael Baum struct mlx5_common_device *cdev; 6009f1d636fSMichael Baum 6019f1d636fSMichael Baum /* Must be called from the primary process. */ 6029f1d636fSMichael Baum MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 6039f1d636fSMichael Baum switch (event_type) { 6049f1d636fSMichael Baum case RTE_MEM_EVENT_FREE: 6059f1d636fSMichael Baum pthread_mutex_lock(&devices_list_lock); 6069f1d636fSMichael Baum /* Iterate all the existing mlx5 devices. */ 6079f1d636fSMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) 6089f1d636fSMichael Baum mlx5_free_mr_by_addr(&cdev->mr_scache, 6099f1d636fSMichael Baum mlx5_os_get_ctx_device_name 6109f1d636fSMichael Baum (cdev->ctx), 6119f1d636fSMichael Baum addr, len); 6129f1d636fSMichael Baum pthread_mutex_unlock(&devices_list_lock); 6139f1d636fSMichael Baum break; 6149f1d636fSMichael Baum case RTE_MEM_EVENT_ALLOC: 6159f1d636fSMichael Baum default: 6169f1d636fSMichael Baum break; 6179f1d636fSMichael Baum } 6189f1d636fSMichael Baum } 6199f1d636fSMichael Baum 6209f1d636fSMichael Baum /** 621ca1418ceSMichael Baum * Uninitialize all HW global of device context. 622ca1418ceSMichael Baum * 623ca1418ceSMichael Baum * @param cdev 624ca1418ceSMichael Baum * Pointer to mlx5 device structure. 625ca1418ceSMichael Baum * 626ca1418ceSMichael Baum * @return 627ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 628ca1418ceSMichael Baum */ 629ca1418ceSMichael Baum static void 630ca1418ceSMichael Baum mlx5_dev_hw_global_release(struct mlx5_common_device *cdev) 631ca1418ceSMichael Baum { 632e35ccf24SMichael Baum if (cdev->pd != NULL) { 633e35ccf24SMichael Baum claim_zero(mlx5_os_dealloc_pd(cdev->pd)); 634e35ccf24SMichael Baum cdev->pd = NULL; 635e35ccf24SMichael Baum } 636ca1418ceSMichael Baum if (cdev->ctx != NULL) { 637ca1418ceSMichael Baum claim_zero(mlx5_glue->close_device(cdev->ctx)); 638ca1418ceSMichael Baum cdev->ctx = NULL; 639ca1418ceSMichael Baum } 640ca1418ceSMichael Baum } 641ca1418ceSMichael Baum 642ca1418ceSMichael Baum /** 643ca1418ceSMichael Baum * Initialize all HW global of device context. 644ca1418ceSMichael Baum * 645ca1418ceSMichael Baum * @param cdev 646ca1418ceSMichael Baum * Pointer to mlx5 device structure. 647ca1418ceSMichael Baum * @param classes 648ca1418ceSMichael Baum * Chosen classes come from user device arguments. 649ca1418ceSMichael Baum * 650ca1418ceSMichael Baum * @return 651ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 652ca1418ceSMichael Baum */ 653ca1418ceSMichael Baum static int 654ca1418ceSMichael Baum mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes) 655ca1418ceSMichael Baum { 656ca1418ceSMichael Baum int ret; 657ca1418ceSMichael Baum 658ca1418ceSMichael Baum /* Create context device */ 659ca1418ceSMichael Baum ret = mlx5_os_open_device(cdev, classes); 660ca1418ceSMichael Baum if (ret < 0) 661ca1418ceSMichael Baum return ret; 662e35ccf24SMichael Baum /* Allocate Protection Domain object and extract its pdn. */ 663e35ccf24SMichael Baum ret = mlx5_os_pd_create(cdev); 664e35ccf24SMichael Baum if (ret) 665e35ccf24SMichael Baum goto error; 666fe46b20cSMichael Baum /* All actions taken below are relevant only when DevX is supported */ 667fe46b20cSMichael Baum if (cdev->config.devx == 0) 668fe46b20cSMichael Baum return 0; 669fe46b20cSMichael Baum /* Query HCA attributes. */ 670fe46b20cSMichael Baum ret = mlx5_devx_cmd_query_hca_attr(cdev->ctx, &cdev->config.hca_attr); 671fe46b20cSMichael Baum if (ret) { 672fe46b20cSMichael Baum DRV_LOG(ERR, "Unable to read HCA capabilities."); 673fe46b20cSMichael Baum rte_errno = ENOTSUP; 674fe46b20cSMichael Baum goto error; 675fe46b20cSMichael Baum } 676ca1418ceSMichael Baum return 0; 677e35ccf24SMichael Baum error: 678e35ccf24SMichael Baum mlx5_dev_hw_global_release(cdev); 679e35ccf24SMichael Baum return ret; 680ca1418ceSMichael Baum } 681ca1418ceSMichael Baum 682ad435d32SXueming Li static void 68385209924SMichael Baum mlx5_common_dev_release(struct mlx5_common_device *cdev) 684ad435d32SXueming Li { 685dc26c9c2SMichael Baum pthread_mutex_lock(&devices_list_lock); 68685209924SMichael Baum TAILQ_REMOVE(&devices_list, cdev, next); 687dc26c9c2SMichael Baum pthread_mutex_unlock(&devices_list_lock); 6889f1d636fSMichael Baum if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 6899f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 6909f1d636fSMichael Baum rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB", 6919f1d636fSMichael Baum NULL); 692fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(cdev); 6939f1d636fSMichael Baum mlx5_mr_release_cache(&cdev->mr_scache); 694ca1418ceSMichael Baum mlx5_dev_hw_global_release(cdev); 6959f1d636fSMichael Baum } 69685209924SMichael Baum rte_free(cdev); 69785209924SMichael Baum } 69885209924SMichael Baum 69985209924SMichael Baum static struct mlx5_common_device * 700*a729d2f0SMichael Baum mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes, 701*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 70285209924SMichael Baum { 70385209924SMichael Baum struct mlx5_common_device *cdev; 70485209924SMichael Baum int ret; 70585209924SMichael Baum 70685209924SMichael Baum cdev = rte_zmalloc("mlx5_common_device", sizeof(*cdev), 0); 70785209924SMichael Baum if (!cdev) { 70885209924SMichael Baum DRV_LOG(ERR, "Device allocation failure."); 70985209924SMichael Baum rte_errno = ENOMEM; 71085209924SMichael Baum return NULL; 71185209924SMichael Baum } 71285209924SMichael Baum cdev->dev = eal_dev; 71385209924SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 71485209924SMichael Baum goto exit; 71585209924SMichael Baum /* Parse device parameters. */ 716*a729d2f0SMichael Baum ret = mlx5_common_config_get(mkvlist, &cdev->config); 71785209924SMichael Baum if (ret < 0) { 71885209924SMichael Baum DRV_LOG(ERR, "Failed to process device arguments: %s", 71985209924SMichael Baum strerror(rte_errno)); 72085209924SMichael Baum rte_free(cdev); 72185209924SMichael Baum return NULL; 72285209924SMichael Baum } 72385209924SMichael Baum mlx5_malloc_mem_select(cdev->config.sys_mem_en); 724ca1418ceSMichael Baum /* Initialize all HW global of device context. */ 725ca1418ceSMichael Baum ret = mlx5_dev_hw_global_prepare(cdev, classes); 726ca1418ceSMichael Baum if (ret) { 727ca1418ceSMichael Baum DRV_LOG(ERR, "Failed to initialize device context."); 728ca1418ceSMichael Baum rte_free(cdev); 729ca1418ceSMichael Baum return NULL; 730ca1418ceSMichael Baum } 7319f1d636fSMichael Baum /* Initialize global MR cache resources and update its functions. */ 7329f1d636fSMichael Baum ret = mlx5_mr_create_cache(&cdev->mr_scache, eal_dev->numa_node); 7339f1d636fSMichael Baum if (ret) { 7349f1d636fSMichael Baum DRV_LOG(ERR, "Failed to initialize global MR share cache."); 7359f1d636fSMichael Baum mlx5_dev_hw_global_release(cdev); 7369f1d636fSMichael Baum rte_free(cdev); 7379f1d636fSMichael Baum return NULL; 7389f1d636fSMichael Baum } 7399f1d636fSMichael Baum /* Register callback function for global shared MR cache management. */ 7409f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 7419f1d636fSMichael Baum rte_mem_event_callback_register("MLX5_MEM_EVENT_CB", 7429f1d636fSMichael Baum mlx5_mr_mem_event_cb, NULL); 74385209924SMichael Baum exit: 74485209924SMichael Baum pthread_mutex_lock(&devices_list_lock); 74585209924SMichael Baum TAILQ_INSERT_HEAD(&devices_list, cdev, next); 74685209924SMichael Baum pthread_mutex_unlock(&devices_list_lock); 74785209924SMichael Baum return cdev; 748ad435d32SXueming Li } 749ad435d32SXueming Li 750c089eb93SMichael Baum /** 751c089eb93SMichael Baum * Validate common devargs when probing again. 752c089eb93SMichael Baum * 753c089eb93SMichael Baum * When common device probing again, it cannot change its configurations. 754c089eb93SMichael Baum * If user ask non compatible configurations in devargs, it is error. 755c089eb93SMichael Baum * This function checks the match between: 756c089eb93SMichael Baum * - Common device configurations requested by probe again devargs. 757c089eb93SMichael Baum * - Existing common device configurations. 758c089eb93SMichael Baum * 759c089eb93SMichael Baum * @param cdev 760c089eb93SMichael Baum * Pointer to mlx5 device structure. 761*a729d2f0SMichael Baum * @param mkvlist 762*a729d2f0SMichael Baum * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. 763c089eb93SMichael Baum * 764c089eb93SMichael Baum * @return 765c089eb93SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 766c089eb93SMichael Baum */ 767c089eb93SMichael Baum static int 768*a729d2f0SMichael Baum mlx5_common_probe_again_args_validate(struct mlx5_common_device *cdev, 769*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 770c089eb93SMichael Baum { 771c089eb93SMichael Baum struct mlx5_common_dev_config *config; 772c089eb93SMichael Baum int ret; 773c089eb93SMichael Baum 774c089eb93SMichael Baum /* Secondary process should not handle devargs. */ 775c089eb93SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 776c089eb93SMichael Baum return 0; 777c089eb93SMichael Baum /* Probe again doesn't have to generate devargs. */ 778*a729d2f0SMichael Baum if (mkvlist == NULL) 779c089eb93SMichael Baum return 0; 780c089eb93SMichael Baum config = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, 781c089eb93SMichael Baum sizeof(struct mlx5_common_dev_config), 782c089eb93SMichael Baum RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 783c089eb93SMichael Baum if (config == NULL) { 784c089eb93SMichael Baum rte_errno = -ENOMEM; 785c089eb93SMichael Baum return -rte_errno; 786c089eb93SMichael Baum } 787c089eb93SMichael Baum /* 788c089eb93SMichael Baum * Creates a temporary common configure structure according to new 789c089eb93SMichael Baum * devargs attached in probing again. 790c089eb93SMichael Baum */ 791*a729d2f0SMichael Baum ret = mlx5_common_config_get(mkvlist, config); 792c089eb93SMichael Baum if (ret) { 793c089eb93SMichael Baum DRV_LOG(ERR, "Failed to process device configure: %s", 794c089eb93SMichael Baum strerror(rte_errno)); 795c089eb93SMichael Baum mlx5_free(config); 796c089eb93SMichael Baum return ret; 797c089eb93SMichael Baum } 798c089eb93SMichael Baum /* 799c089eb93SMichael Baum * Checks the match between the temporary structure and the existing 800c089eb93SMichael Baum * common device structure. 801c089eb93SMichael Baum */ 802c089eb93SMichael Baum if (cdev->config.mr_ext_memseg_en ^ config->mr_ext_memseg_en) { 803c089eb93SMichael Baum DRV_LOG(ERR, "\"mr_ext_memseg_en\" " 804c089eb93SMichael Baum "configuration mismatch for device %s.", 805c089eb93SMichael Baum cdev->dev->name); 806c089eb93SMichael Baum goto error; 807c089eb93SMichael Baum } 808c089eb93SMichael Baum if (cdev->config.mr_mempool_reg_en ^ config->mr_mempool_reg_en) { 809c089eb93SMichael Baum DRV_LOG(ERR, "\"mr_mempool_reg_en\" " 810c089eb93SMichael Baum "configuration mismatch for device %s.", 811c089eb93SMichael Baum cdev->dev->name); 812c089eb93SMichael Baum goto error; 813c089eb93SMichael Baum } 814c089eb93SMichael Baum if (cdev->config.sys_mem_en ^ config->sys_mem_en) { 815c089eb93SMichael Baum DRV_LOG(ERR, 816c089eb93SMichael Baum "\"sys_mem_en\" configuration mismatch for device %s.", 817c089eb93SMichael Baum cdev->dev->name); 818c089eb93SMichael Baum goto error; 819c089eb93SMichael Baum } 820c089eb93SMichael Baum if (cdev->config.dbnc ^ config->dbnc) { 821c089eb93SMichael Baum DRV_LOG(ERR, "\"dbnc\" configuration mismatch for device %s.", 822c089eb93SMichael Baum cdev->dev->name); 823c089eb93SMichael Baum goto error; 824c089eb93SMichael Baum } 825c089eb93SMichael Baum mlx5_free(config); 826c089eb93SMichael Baum return 0; 827c089eb93SMichael Baum error: 828c089eb93SMichael Baum mlx5_free(config); 829c089eb93SMichael Baum rte_errno = EINVAL; 830c089eb93SMichael Baum return -rte_errno; 831c089eb93SMichael Baum } 832c089eb93SMichael Baum 833ad435d32SXueming Li static int 83485209924SMichael Baum drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes) 835ad435d32SXueming Li { 836ad435d32SXueming Li struct mlx5_class_driver *driver; 837ad435d32SXueming Li int local_ret = -ENODEV; 838ad435d32SXueming Li unsigned int i = 0; 839ad435d32SXueming Li int ret = 0; 840ad435d32SXueming Li 841ad435d32SXueming Li while (enabled_classes) { 842ad435d32SXueming Li driver = driver_get(RTE_BIT64(i)); 843ad435d32SXueming Li if (driver != NULL) { 84485209924SMichael Baum local_ret = driver->remove(cdev); 845ad435d32SXueming Li if (local_ret == 0) 84685209924SMichael Baum cdev->classes_loaded &= ~RTE_BIT64(i); 847ad435d32SXueming Li else if (ret == 0) 848ad435d32SXueming Li ret = local_ret; 849ad435d32SXueming Li } 850ad435d32SXueming Li enabled_classes &= ~RTE_BIT64(i); 851ad435d32SXueming Li i++; 852ad435d32SXueming Li } 853ad435d32SXueming Li if (local_ret != 0 && ret == 0) 854ad435d32SXueming Li ret = local_ret; 855ad435d32SXueming Li return ret; 856ad435d32SXueming Li } 857ad435d32SXueming Li 858ad435d32SXueming Li static int 859*a729d2f0SMichael Baum drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes, 860*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 861ad435d32SXueming Li { 862ad435d32SXueming Li struct mlx5_class_driver *driver; 863ad435d32SXueming Li uint32_t enabled_classes = 0; 864ad435d32SXueming Li bool already_loaded; 865b4a4159dSBing Zhao int ret = -EINVAL; 866ad435d32SXueming Li 867ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 868ad435d32SXueming Li if ((driver->drv_class & user_classes) == 0) 869ad435d32SXueming Li continue; 87085209924SMichael Baum if (!mlx5_bus_match(driver, cdev->dev)) 871ad435d32SXueming Li continue; 87285209924SMichael Baum already_loaded = cdev->classes_loaded & driver->drv_class; 873ad435d32SXueming Li if (already_loaded && driver->probe_again == 0) { 874ad435d32SXueming Li DRV_LOG(ERR, "Device %s is already probed", 87585209924SMichael Baum cdev->dev->name); 876ad435d32SXueming Li ret = -EEXIST; 877ad435d32SXueming Li goto probe_err; 878ad435d32SXueming Li } 879*a729d2f0SMichael Baum ret = driver->probe(cdev, mkvlist); 880ad435d32SXueming Li if (ret < 0) { 881ad435d32SXueming Li DRV_LOG(ERR, "Failed to load driver %s", 882ad435d32SXueming Li driver->name); 883ad435d32SXueming Li goto probe_err; 884ad435d32SXueming Li } 885ad435d32SXueming Li enabled_classes |= driver->drv_class; 886ad435d32SXueming Li } 887b4a4159dSBing Zhao if (!ret) { 88885209924SMichael Baum cdev->classes_loaded |= enabled_classes; 889ad435d32SXueming Li return 0; 890b4a4159dSBing Zhao } 891ad435d32SXueming Li probe_err: 8928928997aSMichael Baum /* 8938928997aSMichael Baum * Need to remove only drivers which were not probed before this probe 8948928997aSMichael Baum * instance, but have already been probed before this failure. 895ad435d32SXueming Li */ 8968928997aSMichael Baum enabled_classes &= ~cdev->classes_loaded; 89785209924SMichael Baum drivers_remove(cdev, enabled_classes); 898ad435d32SXueming Li return ret; 899ad435d32SXueming Li } 900ad435d32SXueming Li 901ad435d32SXueming Li int 902ad435d32SXueming Li mlx5_common_dev_probe(struct rte_device *eal_dev) 903ad435d32SXueming Li { 90485209924SMichael Baum struct mlx5_common_device *cdev; 905*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl mkvlist; 906*a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist_p = NULL; 907ad435d32SXueming Li uint32_t classes = 0; 908ad435d32SXueming Li bool new_device = false; 909ad435d32SXueming Li int ret; 910ad435d32SXueming Li 911ad435d32SXueming Li DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name); 912*a729d2f0SMichael Baum if (eal_dev->devargs != NULL) 913*a729d2f0SMichael Baum mkvlist_p = &mkvlist; 914*a729d2f0SMichael Baum ret = mlx5_kvargs_prepare(mkvlist_p, eal_dev->devargs); 915*a729d2f0SMichael Baum if (ret < 0) { 916*a729d2f0SMichael Baum DRV_LOG(ERR, "Unsupported device arguments: %s", 917*a729d2f0SMichael Baum eal_dev->devargs->args); 918*a729d2f0SMichael Baum return ret; 919*a729d2f0SMichael Baum } 920*a729d2f0SMichael Baum ret = parse_class_options(eal_dev->devargs, mkvlist_p); 921ad435d32SXueming Li if (ret < 0) { 922ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 class type: %s", 923ad435d32SXueming Li eal_dev->devargs->args); 924*a729d2f0SMichael Baum goto class_err; 925ad435d32SXueming Li } 926ad435d32SXueming Li classes = ret; 927ad435d32SXueming Li if (classes == 0) 928ad435d32SXueming Li /* Default to net class. */ 929ad435d32SXueming Li classes = MLX5_CLASS_ETH; 930c089eb93SMichael Baum /* 931c089eb93SMichael Baum * MLX5 common driver supports probing again in two scenarios: 932c089eb93SMichael Baum * - Add new driver under existing common device (regardless of the 933c089eb93SMichael Baum * driver's own support in probing again). 934c089eb93SMichael Baum * - Transfer the probing again support of the drivers themselves. 935c089eb93SMichael Baum * 936c089eb93SMichael Baum * In both scenarios it uses in the existing device. here it looks for 937c089eb93SMichael Baum * device that match to rte device, if it exists, the request classes 938c089eb93SMichael Baum * were probed with this device. 939c089eb93SMichael Baum */ 94085209924SMichael Baum cdev = to_mlx5_device(eal_dev); 94185209924SMichael Baum if (!cdev) { 942c089eb93SMichael Baum /* It isn't probing again, creates a new device. */ 943*a729d2f0SMichael Baum cdev = mlx5_common_dev_create(eal_dev, classes, mkvlist_p); 944*a729d2f0SMichael Baum if (!cdev) { 945*a729d2f0SMichael Baum ret = -ENOMEM; 946*a729d2f0SMichael Baum goto class_err; 947*a729d2f0SMichael Baum } 948ad435d32SXueming Li new_device = true; 949c089eb93SMichael Baum } else { 950c089eb93SMichael Baum /* It is probing again, validate common devargs match. */ 951*a729d2f0SMichael Baum ret = mlx5_common_probe_again_args_validate(cdev, mkvlist_p); 952c089eb93SMichael Baum if (ret) { 953c089eb93SMichael Baum DRV_LOG(ERR, 954c089eb93SMichael Baum "Probe again parameters aren't compatible : %s", 955c089eb93SMichael Baum strerror(rte_errno)); 956*a729d2f0SMichael Baum goto class_err; 957c089eb93SMichael Baum } 958288d7c3fSMichael Baum } 959288d7c3fSMichael Baum /* 960288d7c3fSMichael Baum * Validate combination here. 961288d7c3fSMichael Baum * For new device, the classes_loaded field is 0 and it check only 962288d7c3fSMichael Baum * the classes given as user device arguments. 963288d7c3fSMichael Baum */ 96485209924SMichael Baum ret = is_valid_class_combination(classes | cdev->classes_loaded); 965ad435d32SXueming Li if (ret != 0) { 966ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 classes combination."); 967288d7c3fSMichael Baum goto class_err; 968ad435d32SXueming Li } 969*a729d2f0SMichael Baum ret = drivers_probe(cdev, classes, mkvlist_p); 970ad435d32SXueming Li if (ret) 971ad435d32SXueming Li goto class_err; 972*a729d2f0SMichael Baum /* 973*a729d2f0SMichael Baum * Validate that all devargs have been used, unused key -> unknown Key. 974*a729d2f0SMichael Baum * When probe again validate is failed, the added drivers aren't removed 975*a729d2f0SMichael Baum * here but when device is released. 976*a729d2f0SMichael Baum */ 977*a729d2f0SMichael Baum ret = mlx5_kvargs_validate(mkvlist_p); 978*a729d2f0SMichael Baum if (ret) 979*a729d2f0SMichael Baum goto class_err; 980*a729d2f0SMichael Baum mlx5_kvargs_release(mkvlist_p); 981ad435d32SXueming Li return 0; 982ad435d32SXueming Li class_err: 983*a729d2f0SMichael Baum if (new_device) { 984*a729d2f0SMichael Baum /* 985*a729d2f0SMichael Baum * For new device, classes_loaded is always 0 before 986*a729d2f0SMichael Baum * drivers_probe function. 987*a729d2f0SMichael Baum */ 988*a729d2f0SMichael Baum if (cdev->classes_loaded) 989*a729d2f0SMichael Baum drivers_remove(cdev, cdev->classes_loaded); 99085209924SMichael Baum mlx5_common_dev_release(cdev); 991*a729d2f0SMichael Baum } 992*a729d2f0SMichael Baum mlx5_kvargs_release(mkvlist_p); 993ad435d32SXueming Li return ret; 994ad435d32SXueming Li } 995ad435d32SXueming Li 996ad435d32SXueming Li int 997ad435d32SXueming Li mlx5_common_dev_remove(struct rte_device *eal_dev) 998ad435d32SXueming Li { 99985209924SMichael Baum struct mlx5_common_device *cdev; 1000ad435d32SXueming Li int ret; 1001ad435d32SXueming Li 100285209924SMichael Baum cdev = to_mlx5_device(eal_dev); 100385209924SMichael Baum if (!cdev) 1004ad435d32SXueming Li return -ENODEV; 1005ad435d32SXueming Li /* Matching device found, cleanup and unload drivers. */ 100685209924SMichael Baum ret = drivers_remove(cdev, cdev->classes_loaded); 1007dffae63dSMichael Baum if (ret == 0) 100885209924SMichael Baum mlx5_common_dev_release(cdev); 1009ad435d32SXueming Li return ret; 1010ad435d32SXueming Li } 1011ad435d32SXueming Li 1012a5d06c90SMichael Baum /** 1013a5d06c90SMichael Baum * Callback to DMA map external memory to a device. 1014a5d06c90SMichael Baum * 1015a5d06c90SMichael Baum * @param rte_dev 1016a5d06c90SMichael Baum * Pointer to the generic device. 1017a5d06c90SMichael Baum * @param addr 1018a5d06c90SMichael Baum * Starting virtual address of memory to be mapped. 1019a5d06c90SMichael Baum * @param iova 1020a5d06c90SMichael Baum * Starting IOVA address of memory to be mapped. 1021a5d06c90SMichael Baum * @param len 1022a5d06c90SMichael Baum * Length of memory segment being mapped. 1023a5d06c90SMichael Baum * 1024a5d06c90SMichael Baum * @return 1025a5d06c90SMichael Baum * 0 on success, negative value on error. 1026a5d06c90SMichael Baum */ 1027ad435d32SXueming Li int 1028a5d06c90SMichael Baum mlx5_common_dev_dma_map(struct rte_device *rte_dev, void *addr, 1029a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len) 1030ad435d32SXueming Li { 1031a5d06c90SMichael Baum struct mlx5_common_device *dev; 1032a5d06c90SMichael Baum struct mlx5_mr *mr; 1033ad435d32SXueming Li 1034a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 1035a5d06c90SMichael Baum if (!dev) { 1036a5d06c90SMichael Baum DRV_LOG(WARNING, 1037a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s", 1038a5d06c90SMichael Baum rte_dev->name); 1039a5d06c90SMichael Baum rte_errno = ENODEV; 1040a5d06c90SMichael Baum return -1; 1041ad435d32SXueming Li } 1042a5d06c90SMichael Baum mr = mlx5_create_mr_ext(dev->pd, (uintptr_t)addr, len, 1043a5d06c90SMichael Baum SOCKET_ID_ANY, dev->mr_scache.reg_mr_cb); 1044a5d06c90SMichael Baum if (!mr) { 1045a5d06c90SMichael Baum DRV_LOG(WARNING, "Device %s unable to DMA map", rte_dev->name); 1046a5d06c90SMichael Baum rte_errno = EINVAL; 1047a5d06c90SMichael Baum return -1; 1048ad435d32SXueming Li } 1049a5d06c90SMichael Baum rte_rwlock_write_lock(&dev->mr_scache.rwlock); 1050a5d06c90SMichael Baum LIST_INSERT_HEAD(&dev->mr_scache.mr_list, mr, mr); 1051a5d06c90SMichael Baum /* Insert to the global cache table. */ 1052a5d06c90SMichael Baum mlx5_mr_insert_cache(&dev->mr_scache, mr); 1053a5d06c90SMichael Baum rte_rwlock_write_unlock(&dev->mr_scache.rwlock); 1054a5d06c90SMichael Baum return 0; 1055ad435d32SXueming Li } 1056ad435d32SXueming Li 1057a5d06c90SMichael Baum /** 1058a5d06c90SMichael Baum * Callback to DMA unmap external memory to a device. 1059a5d06c90SMichael Baum * 1060a5d06c90SMichael Baum * @param rte_dev 1061a5d06c90SMichael Baum * Pointer to the generic device. 1062a5d06c90SMichael Baum * @param addr 1063a5d06c90SMichael Baum * Starting virtual address of memory to be unmapped. 1064a5d06c90SMichael Baum * @param iova 1065a5d06c90SMichael Baum * Starting IOVA address of memory to be unmapped. 1066a5d06c90SMichael Baum * @param len 1067a5d06c90SMichael Baum * Length of memory segment being unmapped. 1068a5d06c90SMichael Baum * 1069a5d06c90SMichael Baum * @return 1070a5d06c90SMichael Baum * 0 on success, negative value on error. 1071a5d06c90SMichael Baum */ 1072ad435d32SXueming Li int 1073a5d06c90SMichael Baum mlx5_common_dev_dma_unmap(struct rte_device *rte_dev, void *addr, 1074a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len __rte_unused) 1075ad435d32SXueming Li { 1076a5d06c90SMichael Baum struct mlx5_common_device *dev; 1077a5d06c90SMichael Baum struct mr_cache_entry entry; 1078a5d06c90SMichael Baum struct mlx5_mr *mr; 1079ad435d32SXueming Li 1080a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 1081a5d06c90SMichael Baum if (!dev) { 1082a5d06c90SMichael Baum DRV_LOG(WARNING, 1083a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s.", 1084a5d06c90SMichael Baum rte_dev->name); 1085a5d06c90SMichael Baum rte_errno = ENODEV; 1086a5d06c90SMichael Baum return -1; 1087ad435d32SXueming Li } 1088a5d06c90SMichael Baum rte_rwlock_read_lock(&dev->mr_scache.rwlock); 1089a5d06c90SMichael Baum mr = mlx5_mr_lookup_list(&dev->mr_scache, &entry, (uintptr_t)addr); 1090a5d06c90SMichael Baum if (!mr) { 1091a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1092a5d06c90SMichael Baum DRV_LOG(WARNING, 1093a5d06c90SMichael Baum "Address 0x%" PRIxPTR " wasn't registered to device %s", 1094a5d06c90SMichael Baum (uintptr_t)addr, rte_dev->name); 1095a5d06c90SMichael Baum rte_errno = EINVAL; 1096a5d06c90SMichael Baum return -1; 1097a5d06c90SMichael Baum } 1098a5d06c90SMichael Baum LIST_REMOVE(mr, mr); 1099a5d06c90SMichael Baum DRV_LOG(DEBUG, "MR(%p) is removed from list.", (void *)mr); 1100a5d06c90SMichael Baum mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb); 1101a5d06c90SMichael Baum mlx5_mr_rebuild_cache(&dev->mr_scache); 1102a5d06c90SMichael Baum /* 1103a5d06c90SMichael Baum * No explicit wmb is needed after updating dev_gen due to 1104a5d06c90SMichael Baum * store-release ordering in unlock that provides the 1105a5d06c90SMichael Baum * implicit barrier at the software visible level. 1106a5d06c90SMichael Baum */ 1107a5d06c90SMichael Baum ++dev->mr_scache.dev_gen; 1108a5d06c90SMichael Baum DRV_LOG(DEBUG, "Broadcasting local cache flush, gen=%d.", 1109a5d06c90SMichael Baum dev->mr_scache.dev_gen); 1110a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1111a5d06c90SMichael Baum return 0; 1112ad435d32SXueming Li } 1113ad435d32SXueming Li 1114ad435d32SXueming Li void 1115ad435d32SXueming Li mlx5_class_driver_register(struct mlx5_class_driver *driver) 1116ad435d32SXueming Li { 1117ad435d32SXueming Li mlx5_common_driver_on_register_pci(driver); 1118ad435d32SXueming Li TAILQ_INSERT_TAIL(&drivers_list, driver, next); 1119ad435d32SXueming Li } 1120ad435d32SXueming Li 1121ad435d32SXueming Li static void mlx5_common_driver_init(void) 1122ad435d32SXueming Li { 1123ad435d32SXueming Li mlx5_common_pci_init(); 1124777b72a9SXueming Li #ifdef RTE_EXEC_ENV_LINUX 1125777b72a9SXueming Li mlx5_common_auxiliary_init(); 1126777b72a9SXueming Li #endif 1127ad435d32SXueming Li } 1128ad435d32SXueming Li 112982088001SParav Pandit static bool mlx5_common_initialized; 113082088001SParav Pandit 113183c99c36SThomas Monjalon /** 11327be78d02SJosh Soref * One time initialization routine for run-time dependency on glue library 113382088001SParav Pandit * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 113482088001SParav Pandit * must invoke in its constructor. 113583c99c36SThomas Monjalon */ 113682088001SParav Pandit void 113782088001SParav Pandit mlx5_common_init(void) 113883c99c36SThomas Monjalon { 113982088001SParav Pandit if (mlx5_common_initialized) 114082088001SParav Pandit return; 114182088001SParav Pandit 1142dc26c9c2SMichael Baum pthread_mutex_init(&devices_list_lock, NULL); 114379aa4307SOphir Munk mlx5_glue_constructor(); 1144ad435d32SXueming Li mlx5_common_driver_init(); 114582088001SParav Pandit mlx5_common_initialized = true; 11467b4f1e6bSMatan Azrad } 11474c204fe5SShiri Kuzin 11484c204fe5SShiri Kuzin /** 11494c204fe5SShiri Kuzin * This function is responsible of initializing the variable 11504c204fe5SShiri Kuzin * haswell_broadwell_cpu by checking if the cpu is intel 11514c204fe5SShiri Kuzin * and reading the data returned from mlx5_cpu_id(). 11524c204fe5SShiri Kuzin * since haswell and broadwell cpus don't have improved performance 11534c204fe5SShiri Kuzin * when using relaxed ordering we want to check the cpu type before 11544c204fe5SShiri Kuzin * before deciding whether to enable RO or not. 11554c204fe5SShiri Kuzin * if the cpu is haswell or broadwell the variable will be set to 1 11564c204fe5SShiri Kuzin * otherwise it will be 0. 11574c204fe5SShiri Kuzin */ 11584c204fe5SShiri Kuzin RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 11594c204fe5SShiri Kuzin { 11604c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 11614c204fe5SShiri Kuzin unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 11624c204fe5SShiri Kuzin unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 11634c204fe5SShiri Kuzin unsigned int i, model, family, brand_id, vendor; 11644c204fe5SShiri Kuzin unsigned int signature_intel_ebx = 0x756e6547; 11654c204fe5SShiri Kuzin unsigned int extended_model; 11664c204fe5SShiri Kuzin unsigned int eax = 0; 11674c204fe5SShiri Kuzin unsigned int ebx = 0; 11684c204fe5SShiri Kuzin unsigned int ecx = 0; 11694c204fe5SShiri Kuzin unsigned int edx = 0; 11704c204fe5SShiri Kuzin int max_level; 11714c204fe5SShiri Kuzin 11724c204fe5SShiri Kuzin mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 11734c204fe5SShiri Kuzin vendor = ebx; 11744c204fe5SShiri Kuzin max_level = eax; 11754c204fe5SShiri Kuzin if (max_level < 1) { 11764c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 11774c204fe5SShiri Kuzin return; 11784c204fe5SShiri Kuzin } 11794c204fe5SShiri Kuzin mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 11804c204fe5SShiri Kuzin model = (eax >> 4) & 0x0f; 11814c204fe5SShiri Kuzin family = (eax >> 8) & 0x0f; 11824c204fe5SShiri Kuzin brand_id = ebx & 0xff; 11834c204fe5SShiri Kuzin extended_model = (eax >> 12) & 0xf0; 11844c204fe5SShiri Kuzin /* Check if the processor is Haswell or Broadwell */ 11854c204fe5SShiri Kuzin if (vendor == signature_intel_ebx) { 11864c204fe5SShiri Kuzin if (family == 0x06) 11874c204fe5SShiri Kuzin model += extended_model; 11884c204fe5SShiri Kuzin if (brand_id == 0 && family == 0x6) { 11894c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(broadwell_models); i++) 11904c204fe5SShiri Kuzin if (model == broadwell_models[i]) { 11914c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 11924c204fe5SShiri Kuzin return; 11934c204fe5SShiri Kuzin } 11944c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(haswell_models); i++) 11954c204fe5SShiri Kuzin if (model == haswell_models[i]) { 11964c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 11974c204fe5SShiri Kuzin return; 11984c204fe5SShiri Kuzin } 11994c204fe5SShiri Kuzin } 12004c204fe5SShiri Kuzin } 12014c204fe5SShiri Kuzin #endif 12024c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 12034c204fe5SShiri Kuzin } 1204262c7ad0SOri Kam 1205262c7ad0SOri Kam /** 12069cc0e99cSViacheslav Ovsiienko * Allocate the User Access Region with DevX on specified device. 1207b4371d3dSMichael Baum * This routine handles the following UAR allocation issues: 12089cc0e99cSViacheslav Ovsiienko * 12095dfa003dSMichael Baum * - Try to allocate the UAR with the most appropriate memory mapping 1210b4371d3dSMichael Baum * type from the ones supported by the host. 1211b4371d3dSMichael Baum * 12125dfa003dSMichael Baum * - Try to allocate the UAR with non-NULL base address OFED 5.0.x and 1213b4371d3dSMichael Baum * Upstream rdma_core before v29 returned the NULL as UAR base address 1214b4371d3dSMichael Baum * if UAR was not the first object in the UAR page. 1215b4371d3dSMichael Baum * It caused the PMD failure and we should try to get another UAR till 1216b4371d3dSMichael Baum * we get the first one with non-NULL base address returned. 1217b4371d3dSMichael Baum * 1218b4371d3dSMichael Baum * @param [in] cdev 1219b4371d3dSMichael Baum * Pointer to mlx5 device structure to perform allocation on its context. 12209cc0e99cSViacheslav Ovsiienko * 12219cc0e99cSViacheslav Ovsiienko * @return 12229cc0e99cSViacheslav Ovsiienko * UAR object pointer on success, NULL otherwise and rte_errno is set. 12239cc0e99cSViacheslav Ovsiienko */ 12245dfa003dSMichael Baum static void * 1225b4371d3dSMichael Baum mlx5_devx_alloc_uar(struct mlx5_common_device *cdev) 12269cc0e99cSViacheslav Ovsiienko { 12279cc0e99cSViacheslav Ovsiienko void *uar; 12289cc0e99cSViacheslav Ovsiienko uint32_t retry, uar_mapping; 12299cc0e99cSViacheslav Ovsiienko void *base_addr; 12309cc0e99cSViacheslav Ovsiienko 12319cc0e99cSViacheslav Ovsiienko for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 12329cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 12339cc0e99cSViacheslav Ovsiienko /* Control the mapping type according to the settings. */ 1234b4371d3dSMichael Baum uar_mapping = (cdev->config.dbnc == MLX5_TXDB_NCACHED) ? 1235b4371d3dSMichael Baum MLX5DV_UAR_ALLOC_TYPE_NC : MLX5DV_UAR_ALLOC_TYPE_BF; 12369cc0e99cSViacheslav Ovsiienko #else 12379cc0e99cSViacheslav Ovsiienko /* 12389cc0e99cSViacheslav Ovsiienko * It seems we have no way to control the memory mapping type 12399cc0e99cSViacheslav Ovsiienko * for the UAR, the default "Write-Combining" type is supposed. 12409cc0e99cSViacheslav Ovsiienko */ 12419cc0e99cSViacheslav Ovsiienko uar_mapping = 0; 12429cc0e99cSViacheslav Ovsiienko #endif 1243b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 12449cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1245b4371d3dSMichael Baum if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 1246b4371d3dSMichael Baum /* 1247b4371d3dSMichael Baum * In some environments like virtual machine the 1248b4371d3dSMichael Baum * Write Combining mapped might be not supported and 1249b4371d3dSMichael Baum * UAR allocation fails. We tried "Non-Cached" mapping 1250b4371d3dSMichael Baum * for the case. 1251b4371d3dSMichael Baum */ 1252b4371d3dSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (BF)"); 1253b4371d3dSMichael Baum uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 1254b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 1255b4371d3dSMichael Baum } else if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 12569cc0e99cSViacheslav Ovsiienko /* 12579cc0e99cSViacheslav Ovsiienko * If Verbs/kernel does not support "Non-Cached" 12589cc0e99cSViacheslav Ovsiienko * try the "Write-Combining". 12599cc0e99cSViacheslav Ovsiienko */ 12603f0e54feSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (NC)"); 12619cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 1262b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 12639cc0e99cSViacheslav Ovsiienko } 12649cc0e99cSViacheslav Ovsiienko #endif 12659cc0e99cSViacheslav Ovsiienko if (!uar) { 12669cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 12679cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 12689cc0e99cSViacheslav Ovsiienko goto exit; 12699cc0e99cSViacheslav Ovsiienko } 12709cc0e99cSViacheslav Ovsiienko base_addr = mlx5_os_get_devx_uar_base_addr(uar); 12719cc0e99cSViacheslav Ovsiienko if (base_addr) 12729cc0e99cSViacheslav Ovsiienko break; 12739cc0e99cSViacheslav Ovsiienko /* 12749cc0e99cSViacheslav Ovsiienko * The UARs are allocated by rdma_core within the 12759cc0e99cSViacheslav Ovsiienko * IB device context, on context closure all UARs 12769cc0e99cSViacheslav Ovsiienko * will be freed, should be no memory/object leakage. 12779cc0e99cSViacheslav Ovsiienko */ 12783f0e54feSMichael Baum DRV_LOG(DEBUG, "Retrying to allocate DevX UAR"); 12799cc0e99cSViacheslav Ovsiienko uar = NULL; 12809cc0e99cSViacheslav Ovsiienko } 12819cc0e99cSViacheslav Ovsiienko /* Check whether we finally succeeded with valid UAR allocation. */ 12829cc0e99cSViacheslav Ovsiienko if (!uar) { 12839cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 12849cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 12859cc0e99cSViacheslav Ovsiienko } 12869cc0e99cSViacheslav Ovsiienko /* 12879cc0e99cSViacheslav Ovsiienko * Return void * instead of struct mlx5dv_devx_uar * 12889cc0e99cSViacheslav Ovsiienko * is for compatibility with older rdma-core library headers. 12899cc0e99cSViacheslav Ovsiienko */ 12909cc0e99cSViacheslav Ovsiienko exit: 12919cc0e99cSViacheslav Ovsiienko return uar; 12929cc0e99cSViacheslav Ovsiienko } 1293ad435d32SXueming Li 12945dfa003dSMichael Baum void 12955dfa003dSMichael Baum mlx5_devx_uar_release(struct mlx5_uar *uar) 12965dfa003dSMichael Baum { 12975dfa003dSMichael Baum if (uar->obj != NULL) 12985dfa003dSMichael Baum mlx5_glue->devx_free_uar(uar->obj); 12995dfa003dSMichael Baum memset(uar, 0, sizeof(*uar)); 13005dfa003dSMichael Baum } 13015dfa003dSMichael Baum 13025dfa003dSMichael Baum int 13035dfa003dSMichael Baum mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar) 13045dfa003dSMichael Baum { 13055dfa003dSMichael Baum off_t uar_mmap_offset; 13065dfa003dSMichael Baum const size_t page_size = rte_mem_page_size(); 13075dfa003dSMichael Baum void *base_addr; 13085dfa003dSMichael Baum void *uar_obj; 13095dfa003dSMichael Baum 13105dfa003dSMichael Baum if (page_size == (size_t)-1) { 13115dfa003dSMichael Baum DRV_LOG(ERR, "Failed to get mem page size"); 13125dfa003dSMichael Baum rte_errno = ENOMEM; 13135dfa003dSMichael Baum return -1; 13145dfa003dSMichael Baum } 13155dfa003dSMichael Baum uar_obj = mlx5_devx_alloc_uar(cdev); 13165dfa003dSMichael Baum if (uar_obj == NULL || mlx5_os_get_devx_uar_reg_addr(uar_obj) == NULL) { 13175dfa003dSMichael Baum rte_errno = errno; 13185dfa003dSMichael Baum DRV_LOG(ERR, "Failed to allocate UAR."); 13195dfa003dSMichael Baum return -1; 13205dfa003dSMichael Baum } 13215dfa003dSMichael Baum uar->obj = uar_obj; 13225dfa003dSMichael Baum uar_mmap_offset = mlx5_os_get_devx_uar_mmap_offset(uar_obj); 13235dfa003dSMichael Baum base_addr = mlx5_os_get_devx_uar_base_addr(uar_obj); 13245dfa003dSMichael Baum uar->dbnc = mlx5_db_map_type_get(uar_mmap_offset, page_size); 13255dfa003dSMichael Baum uar->bf_db.db = mlx5_os_get_devx_uar_reg_addr(uar_obj); 13265dfa003dSMichael Baum uar->cq_db.db = RTE_PTR_ADD(base_addr, MLX5_CQ_DOORBELL); 13275dfa003dSMichael Baum #ifndef RTE_ARCH_64 13285dfa003dSMichael Baum rte_spinlock_init(&uar->bf_sl); 13295dfa003dSMichael Baum rte_spinlock_init(&uar->cq_sl); 13305dfa003dSMichael Baum uar->bf_db.sl_p = &uar->bf_sl; 13315dfa003dSMichael Baum uar->cq_db.sl_p = &uar->cq_sl; 13325dfa003dSMichael Baum #endif /* RTE_ARCH_64 */ 13335dfa003dSMichael Baum return 0; 13345dfa003dSMichael Baum } 13355dfa003dSMichael Baum 1336ad435d32SXueming Li RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__); 1337