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 24a729d2f0SMichael Baum /* Driver type key for new device global syntax. */ 25a729d2f0SMichael Baum #define MLX5_DRIVER_KEY "driver" 26a729d2f0SMichael Baum 27a729d2f0SMichael Baum /* Enable extending memsegs when creating a MR. */ 28a729d2f0SMichael Baum #define MLX5_MR_EXT_MEMSEG_EN "mr_ext_memseg_en" 29a729d2f0SMichael Baum 30a729d2f0SMichael Baum /* Device parameter to configure implicit registration of mempool memory. */ 31a729d2f0SMichael Baum #define MLX5_MR_MEMPOOL_REG_EN "mr_mempool_reg_en" 32a729d2f0SMichael Baum 33a729d2f0SMichael Baum /* The default memory allocator used in PMD. */ 34a729d2f0SMichael Baum #define MLX5_SYS_MEM_EN "sys_mem_en" 35a729d2f0SMichael Baum 36a729d2f0SMichael Baum /* 37a729d2f0SMichael Baum * Device parameter to force doorbell register mapping 38*a6b9d5a5SMichael Baum * to non-cached region eliminating the extra write memory barrier. 39*a6b9d5a5SMichael Baum * Deprecated, ignored (Name changed to sq_db_nc). 40a729d2f0SMichael Baum */ 41a729d2f0SMichael Baum #define MLX5_TX_DB_NC "tx_db_nc" 42a729d2f0SMichael Baum 43*a6b9d5a5SMichael Baum /* 44*a6b9d5a5SMichael Baum * Device parameter to force doorbell register mapping 45*a6b9d5a5SMichael Baum * to non-cached region eliminating the extra write memory barrier. 46*a6b9d5a5SMichael Baum */ 47*a6b9d5a5SMichael Baum #define MLX5_SQ_DB_NC "sq_db_nc" 48*a6b9d5a5SMichael Baum 494c204fe5SShiri Kuzin /* In case this is an x86_64 intel processor to check if 504c204fe5SShiri Kuzin * we should use relaxed ordering. 514c204fe5SShiri Kuzin */ 524c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 534c204fe5SShiri Kuzin /** 544c204fe5SShiri Kuzin * This function returns processor identification and feature information 554c204fe5SShiri Kuzin * into the registers. 564c204fe5SShiri Kuzin * 574c204fe5SShiri Kuzin * @param eax, ebx, ecx, edx 584c204fe5SShiri Kuzin * Pointers to the registers that will hold cpu information. 594c204fe5SShiri Kuzin * @param level 604c204fe5SShiri Kuzin * The main category of information returned. 614c204fe5SShiri Kuzin */ 624c204fe5SShiri Kuzin static inline void mlx5_cpu_id(unsigned int level, 634c204fe5SShiri Kuzin unsigned int *eax, unsigned int *ebx, 644c204fe5SShiri Kuzin unsigned int *ecx, unsigned int *edx) 654c204fe5SShiri Kuzin { 664c204fe5SShiri Kuzin __asm__("cpuid\n\t" 674c204fe5SShiri Kuzin : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 684c204fe5SShiri Kuzin : "0" (level)); 694c204fe5SShiri Kuzin } 704c204fe5SShiri Kuzin #endif 714c204fe5SShiri Kuzin 72eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE) 7383c99c36SThomas Monjalon 74ad435d32SXueming Li /* Head of list of drivers. */ 75ad435d32SXueming Li static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list = 76ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(drivers_list); 77ad435d32SXueming Li 78ad435d32SXueming Li /* Head of devices. */ 79ad435d32SXueming Li static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list = 80ad435d32SXueming Li TAILQ_HEAD_INITIALIZER(devices_list); 81dc26c9c2SMichael Baum static pthread_mutex_t devices_list_lock; 82ad435d32SXueming Li 83ad435d32SXueming Li static const struct { 84ad435d32SXueming Li const char *name; 85ad435d32SXueming Li unsigned int drv_class; 86ad435d32SXueming Li } mlx5_classes[] = { 87ad435d32SXueming Li { .name = "vdpa", .drv_class = MLX5_CLASS_VDPA }, 88ad435d32SXueming Li { .name = "eth", .drv_class = MLX5_CLASS_ETH }, 89ad435d32SXueming Li /* Keep class "net" for backward compatibility. */ 90ad435d32SXueming Li { .name = "net", .drv_class = MLX5_CLASS_ETH }, 91ad435d32SXueming Li { .name = "regex", .drv_class = MLX5_CLASS_REGEX }, 92ad435d32SXueming Li { .name = "compress", .drv_class = MLX5_CLASS_COMPRESS }, 93ad435d32SXueming Li { .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO }, 94ad435d32SXueming Li }; 95ad435d32SXueming Li 96ad435d32SXueming Li static int 97ad435d32SXueming Li class_name_to_value(const char *class_name) 98ad435d32SXueming Li { 99ad435d32SXueming Li unsigned int i; 100ad435d32SXueming Li 101ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 102ad435d32SXueming Li if (strcmp(class_name, mlx5_classes[i].name) == 0) 103ad435d32SXueming Li return mlx5_classes[i].drv_class; 104ad435d32SXueming Li } 105ad435d32SXueming Li return -EINVAL; 106ad435d32SXueming Li } 107ad435d32SXueming Li 108ad435d32SXueming Li static struct mlx5_class_driver * 109ad435d32SXueming Li driver_get(uint32_t class) 110ad435d32SXueming Li { 111ad435d32SXueming Li struct mlx5_class_driver *driver; 112ad435d32SXueming Li 113ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 114ad435d32SXueming Li if ((uint32_t)driver->drv_class == class) 115ad435d32SXueming Li return driver; 116ad435d32SXueming Li } 117ad435d32SXueming Li return NULL; 118ad435d32SXueming Li } 119ad435d32SXueming Li 120a729d2f0SMichael Baum int 121a729d2f0SMichael Baum mlx5_kvargs_process(struct mlx5_kvargs_ctrl *mkvlist, const char *const keys[], 122a729d2f0SMichael Baum arg_handler_t handler, void *opaque_arg) 123a729d2f0SMichael Baum { 124a729d2f0SMichael Baum const struct rte_kvargs_pair *pair; 125a729d2f0SMichael Baum uint32_t i, j; 126a729d2f0SMichael Baum 127a729d2f0SMichael Baum MLX5_ASSERT(mkvlist && mkvlist->kvlist); 128a729d2f0SMichael Baum /* Process parameters. */ 129a729d2f0SMichael Baum for (i = 0; i < mkvlist->kvlist->count; i++) { 130a729d2f0SMichael Baum pair = &mkvlist->kvlist->pairs[i]; 131a729d2f0SMichael Baum for (j = 0; keys[j] != NULL; ++j) { 132a729d2f0SMichael Baum if (strcmp(pair->key, keys[j]) != 0) 133a729d2f0SMichael Baum continue; 134a729d2f0SMichael Baum if ((*handler)(pair->key, pair->value, opaque_arg) < 0) 135a729d2f0SMichael Baum return -1; 136a729d2f0SMichael Baum mkvlist->is_used[i] = true; 137a729d2f0SMichael Baum break; 138a729d2f0SMichael Baum } 139a729d2f0SMichael Baum } 140a729d2f0SMichael Baum return 0; 141a729d2f0SMichael Baum } 142a729d2f0SMichael Baum 143a729d2f0SMichael Baum /** 144a729d2f0SMichael Baum * Prepare a mlx5 kvargs control. 145a729d2f0SMichael Baum * 146a729d2f0SMichael Baum * @param[out] mkvlist 147a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 148a729d2f0SMichael Baum * @param[in] devargs 149a729d2f0SMichael Baum * The input string containing the key/value associations. 150a729d2f0SMichael Baum * 151a729d2f0SMichael Baum * @return 152a729d2f0SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 153a729d2f0SMichael Baum */ 154a729d2f0SMichael Baum static int 155a729d2f0SMichael Baum mlx5_kvargs_prepare(struct mlx5_kvargs_ctrl *mkvlist, 156a729d2f0SMichael Baum const struct rte_devargs *devargs) 157a729d2f0SMichael Baum { 158a729d2f0SMichael Baum struct rte_kvargs *kvlist; 159a729d2f0SMichael Baum uint32_t i; 160a729d2f0SMichael Baum 161a729d2f0SMichael Baum if (devargs == NULL) 162a729d2f0SMichael Baum return 0; 163a729d2f0SMichael Baum kvlist = rte_kvargs_parse(devargs->args, NULL); 164a729d2f0SMichael Baum if (kvlist == NULL) { 165a729d2f0SMichael Baum rte_errno = EINVAL; 166a729d2f0SMichael Baum return -rte_errno; 167a729d2f0SMichael Baum } 168a729d2f0SMichael Baum /* 169a729d2f0SMichael Baum * rte_kvargs_parse enable key without value, in mlx5 PMDs we disable 170a729d2f0SMichael Baum * this syntax. 171a729d2f0SMichael Baum */ 172a729d2f0SMichael Baum for (i = 0; i < kvlist->count; i++) { 173a729d2f0SMichael Baum const struct rte_kvargs_pair *pair = &kvlist->pairs[i]; 174a729d2f0SMichael Baum if (pair->value == NULL || *(pair->value) == '\0') { 175a729d2f0SMichael Baum DRV_LOG(ERR, "Key %s is missing value.", pair->key); 176a729d2f0SMichael Baum rte_kvargs_free(kvlist); 177a729d2f0SMichael Baum rte_errno = EINVAL; 178a729d2f0SMichael Baum return -rte_errno; 179a729d2f0SMichael Baum } 180a729d2f0SMichael Baum } 181a729d2f0SMichael Baum /* Makes sure all devargs used array is false. */ 182a729d2f0SMichael Baum memset(mkvlist, 0, sizeof(*mkvlist)); 183a729d2f0SMichael Baum mkvlist->kvlist = kvlist; 184a729d2f0SMichael Baum DRV_LOG(DEBUG, "Parse successfully %u devargs.", 185a729d2f0SMichael Baum mkvlist->kvlist->count); 186a729d2f0SMichael Baum return 0; 187a729d2f0SMichael Baum } 188a729d2f0SMichael Baum 189a729d2f0SMichael Baum /** 190a729d2f0SMichael Baum * Release a mlx5 kvargs control. 191a729d2f0SMichael Baum * 192a729d2f0SMichael Baum * @param[out] mkvlist 193a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 194a729d2f0SMichael Baum */ 195a729d2f0SMichael Baum static void 196a729d2f0SMichael Baum mlx5_kvargs_release(struct mlx5_kvargs_ctrl *mkvlist) 197a729d2f0SMichael Baum { 198a729d2f0SMichael Baum if (mkvlist == NULL) 199a729d2f0SMichael Baum return; 200a729d2f0SMichael Baum rte_kvargs_free(mkvlist->kvlist); 201a729d2f0SMichael Baum memset(mkvlist, 0, sizeof(*mkvlist)); 202a729d2f0SMichael Baum } 203a729d2f0SMichael Baum 204a729d2f0SMichael Baum /** 205a729d2f0SMichael Baum * Validate device arguments list. 206a729d2f0SMichael Baum * It report about the first unknown parameter. 207a729d2f0SMichael Baum * 208a729d2f0SMichael Baum * @param[in] mkvlist 209a729d2f0SMichael Baum * Pointer to mlx5 kvargs control. 210a729d2f0SMichael Baum * 211a729d2f0SMichael Baum * @return 212a729d2f0SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 213a729d2f0SMichael Baum */ 214a729d2f0SMichael Baum static int 215a729d2f0SMichael Baum mlx5_kvargs_validate(struct mlx5_kvargs_ctrl *mkvlist) 216a729d2f0SMichael Baum { 217a729d2f0SMichael Baum uint32_t i; 218a729d2f0SMichael Baum 219a729d2f0SMichael Baum /* Secondary process should not handle devargs. */ 220a729d2f0SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 221a729d2f0SMichael Baum return 0; 222a729d2f0SMichael Baum if (mkvlist == NULL) 223a729d2f0SMichael Baum return 0; 224a729d2f0SMichael Baum for (i = 0; i < mkvlist->kvlist->count; i++) { 225a729d2f0SMichael Baum if (mkvlist->is_used[i] == 0) { 226a729d2f0SMichael Baum DRV_LOG(ERR, "Key \"%s\" " 227a729d2f0SMichael Baum "is unknown for the provided classes.", 228a729d2f0SMichael Baum mkvlist->kvlist->pairs[i].key); 229a729d2f0SMichael Baum rte_errno = EINVAL; 230a729d2f0SMichael Baum return -rte_errno; 231a729d2f0SMichael Baum } 232a729d2f0SMichael Baum } 233a729d2f0SMichael Baum return 0; 234a729d2f0SMichael Baum } 235a729d2f0SMichael Baum 23685209924SMichael Baum /** 23785209924SMichael Baum * Verify and store value for devargs. 23885209924SMichael Baum * 23985209924SMichael Baum * @param[in] key 24085209924SMichael Baum * Key argument to verify. 24185209924SMichael Baum * @param[in] val 24285209924SMichael Baum * Value associated with key. 24385209924SMichael Baum * @param opaque 24485209924SMichael Baum * User data. 24585209924SMichael Baum * 24685209924SMichael Baum * @return 24785209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 24885209924SMichael Baum */ 24985209924SMichael Baum static int 25085209924SMichael Baum mlx5_common_args_check_handler(const char *key, const char *val, void *opaque) 25185209924SMichael Baum { 25285209924SMichael Baum struct mlx5_common_dev_config *config = opaque; 25385209924SMichael Baum signed long tmp; 25485209924SMichael Baum 255a729d2f0SMichael Baum if (strcmp(MLX5_DRIVER_KEY, key) == 0 || 256a729d2f0SMichael Baum strcmp(RTE_DEVARGS_KEY_CLASS, key) == 0) 257a729d2f0SMichael Baum return 0; 25885209924SMichael Baum errno = 0; 25985209924SMichael Baum tmp = strtol(val, NULL, 0); 26085209924SMichael Baum if (errno) { 26185209924SMichael Baum rte_errno = errno; 26285209924SMichael Baum DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val); 26385209924SMichael Baum return -rte_errno; 26485209924SMichael Baum } 265*a6b9d5a5SMichael Baum if (strcmp(key, MLX5_TX_DB_NC) == 0) 266*a6b9d5a5SMichael Baum DRV_LOG(WARNING, 267*a6b9d5a5SMichael Baum "%s: deprecated parameter, converted to queue_db_nc", 268*a6b9d5a5SMichael Baum key); 269*a6b9d5a5SMichael Baum if (strcmp(key, MLX5_SQ_DB_NC) == 0 || 270*a6b9d5a5SMichael Baum strcmp(key, MLX5_TX_DB_NC) == 0) { 271*a6b9d5a5SMichael Baum if (tmp != MLX5_SQ_DB_CACHED && 272*a6b9d5a5SMichael Baum tmp != MLX5_SQ_DB_NCACHED && 273*a6b9d5a5SMichael Baum tmp != MLX5_SQ_DB_HEURISTIC) { 274*a6b9d5a5SMichael Baum DRV_LOG(ERR, 275*a6b9d5a5SMichael Baum "Invalid Send Queue doorbell mapping parameter."); 27685209924SMichael Baum rte_errno = EINVAL; 27785209924SMichael Baum return -rte_errno; 27885209924SMichael Baum } 27985209924SMichael Baum config->dbnc = tmp; 280a729d2f0SMichael Baum } else if (strcmp(key, MLX5_MR_EXT_MEMSEG_EN) == 0) { 28185209924SMichael Baum config->mr_ext_memseg_en = !!tmp; 282a729d2f0SMichael Baum } else if (strcmp(key, MLX5_MR_MEMPOOL_REG_EN) == 0) { 28385209924SMichael Baum config->mr_mempool_reg_en = !!tmp; 284a729d2f0SMichael Baum } else if (strcmp(key, MLX5_SYS_MEM_EN) == 0) { 28585209924SMichael Baum config->sys_mem_en = !!tmp; 28685209924SMichael Baum } 28785209924SMichael Baum return 0; 28885209924SMichael Baum } 28985209924SMichael Baum 29085209924SMichael Baum /** 29185209924SMichael Baum * Parse common device parameters. 29285209924SMichael Baum * 29385209924SMichael Baum * @param devargs 29485209924SMichael Baum * Device arguments structure. 29585209924SMichael Baum * @param config 29685209924SMichael Baum * Pointer to device configuration structure. 29785209924SMichael Baum * 29885209924SMichael Baum * @return 29985209924SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 30085209924SMichael Baum */ 30185209924SMichael Baum static int 302a729d2f0SMichael Baum mlx5_common_config_get(struct mlx5_kvargs_ctrl *mkvlist, 30385209924SMichael Baum struct mlx5_common_dev_config *config) 30485209924SMichael Baum { 305a729d2f0SMichael Baum const char **params = (const char *[]){ 306a729d2f0SMichael Baum RTE_DEVARGS_KEY_CLASS, 307a729d2f0SMichael Baum MLX5_DRIVER_KEY, 308a729d2f0SMichael Baum MLX5_TX_DB_NC, 309*a6b9d5a5SMichael Baum MLX5_SQ_DB_NC, 310a729d2f0SMichael Baum MLX5_MR_EXT_MEMSEG_EN, 311a729d2f0SMichael Baum MLX5_SYS_MEM_EN, 312a729d2f0SMichael Baum MLX5_MR_MEMPOOL_REG_EN, 313a729d2f0SMichael Baum NULL, 314a729d2f0SMichael Baum }; 31585209924SMichael Baum int ret = 0; 31685209924SMichael Baum 317a729d2f0SMichael Baum if (mkvlist == NULL) 318a729d2f0SMichael Baum return 0; 31985209924SMichael Baum /* Set defaults. */ 32085209924SMichael Baum config->mr_ext_memseg_en = 1; 32185209924SMichael Baum config->mr_mempool_reg_en = 1; 32285209924SMichael Baum config->sys_mem_en = 0; 32385209924SMichael Baum config->dbnc = MLX5_ARG_UNSET; 324a729d2f0SMichael Baum /* Process common parameters. */ 325a729d2f0SMichael Baum ret = mlx5_kvargs_process(mkvlist, params, 326a729d2f0SMichael Baum mlx5_common_args_check_handler, config); 327a729d2f0SMichael Baum if (ret) { 32885209924SMichael Baum rte_errno = EINVAL; 32985209924SMichael Baum ret = -rte_errno; 330a729d2f0SMichael Baum } 33185209924SMichael Baum DRV_LOG(DEBUG, "mr_ext_memseg_en is %u.", config->mr_ext_memseg_en); 33285209924SMichael Baum DRV_LOG(DEBUG, "mr_mempool_reg_en is %u.", config->mr_mempool_reg_en); 33385209924SMichael Baum DRV_LOG(DEBUG, "sys_mem_en is %u.", config->sys_mem_en); 334*a6b9d5a5SMichael Baum DRV_LOG(DEBUG, "Send Queue doorbell mapping parameter is %d.", 335*a6b9d5a5SMichael Baum config->dbnc); 33685209924SMichael Baum return ret; 33785209924SMichael Baum } 33885209924SMichael Baum 339ad435d32SXueming Li static int 340ad435d32SXueming Li devargs_class_handler(__rte_unused const char *key, 341ad435d32SXueming Li const char *class_names, void *opaque) 342ad435d32SXueming Li { 343ad435d32SXueming Li int *ret = opaque; 344ad435d32SXueming Li int class_val; 345ad435d32SXueming Li char *scratch; 346ad435d32SXueming Li char *found; 347ad435d32SXueming Li char *refstr = NULL; 348ad435d32SXueming Li 349ad435d32SXueming Li *ret = 0; 350ad435d32SXueming Li scratch = strdup(class_names); 351ad435d32SXueming Li if (scratch == NULL) { 352ad435d32SXueming Li *ret = -ENOMEM; 353ad435d32SXueming Li return *ret; 354ad435d32SXueming Li } 355ad435d32SXueming Li found = strtok_r(scratch, ":", &refstr); 356ad435d32SXueming Li if (found == NULL) 357ad435d32SXueming Li /* Empty string. */ 358ad435d32SXueming Li goto err; 359ad435d32SXueming Li do { 360ad435d32SXueming Li /* Extract each individual class name. Multiple 361ad435d32SXueming Li * classes can be supplied as class=net:regex:foo:bar. 362ad435d32SXueming Li */ 363ad435d32SXueming Li class_val = class_name_to_value(found); 364ad435d32SXueming Li /* Check if its a valid class. */ 365ad435d32SXueming Li if (class_val < 0) { 366ad435d32SXueming Li *ret = -EINVAL; 367ad435d32SXueming Li goto err; 368ad435d32SXueming Li } 369ad435d32SXueming Li *ret |= class_val; 370ad435d32SXueming Li found = strtok_r(NULL, ":", &refstr); 371ad435d32SXueming Li } while (found != NULL); 372ad435d32SXueming Li err: 373ad435d32SXueming Li free(scratch); 374ad435d32SXueming Li if (*ret < 0) 375ad435d32SXueming Li DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names); 376ad435d32SXueming Li return *ret; 377ad435d32SXueming Li } 378ad435d32SXueming Li 379ad435d32SXueming Li static int 380a729d2f0SMichael Baum parse_class_options(const struct rte_devargs *devargs, 381a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 382ad435d32SXueming Li { 383ad435d32SXueming Li int ret = 0; 384ad435d32SXueming Li 385ad435d32SXueming Li if (devargs == NULL) 386ad435d32SXueming Li return 0; 387ad435d32SXueming Li if (devargs->cls != NULL && devargs->cls->name != NULL) 388ad435d32SXueming Li /* Global syntax, only one class type. */ 389ad435d32SXueming Li return class_name_to_value(devargs->cls->name); 390ad435d32SXueming Li /* Legacy devargs support multiple classes. */ 391a729d2f0SMichael Baum rte_kvargs_process(mkvlist->kvlist, RTE_DEVARGS_KEY_CLASS, 392ad435d32SXueming Li devargs_class_handler, &ret); 393ad435d32SXueming Li return ret; 394ad435d32SXueming Li } 395ad435d32SXueming Li 396ad435d32SXueming Li static const unsigned int mlx5_class_invalid_combinations[] = { 397ad435d32SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_VDPA, 398ad435d32SXueming Li /* New class combination should be added here. */ 399ad435d32SXueming Li }; 400ad435d32SXueming Li 401ad435d32SXueming Li static int 402ad435d32SXueming Li is_valid_class_combination(uint32_t user_classes) 403ad435d32SXueming Li { 404ad435d32SXueming Li unsigned int i; 405ad435d32SXueming Li 406ad435d32SXueming Li /* Verify if user specified unsupported combination. */ 407ad435d32SXueming Li for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) { 408ad435d32SXueming Li if ((mlx5_class_invalid_combinations[i] & user_classes) == 409ad435d32SXueming Li mlx5_class_invalid_combinations[i]) 410ad435d32SXueming Li return -EINVAL; 411ad435d32SXueming Li } 412ad435d32SXueming Li /* Not found any invalid class combination. */ 413ad435d32SXueming Li return 0; 414ad435d32SXueming Li } 415ad435d32SXueming Li 416ad435d32SXueming Li static bool 417ad435d32SXueming Li mlx5_bus_match(const struct mlx5_class_driver *drv, 418ad435d32SXueming Li const struct rte_device *dev) 419ad435d32SXueming Li { 420ad435d32SXueming Li if (mlx5_dev_is_pci(dev)) 421ad435d32SXueming Li return mlx5_dev_pci_match(drv, dev); 422ad435d32SXueming Li return true; 423ad435d32SXueming Li } 424ad435d32SXueming Li 425ad435d32SXueming Li static struct mlx5_common_device * 426ad435d32SXueming Li to_mlx5_device(const struct rte_device *rte_dev) 427ad435d32SXueming Li { 42885209924SMichael Baum struct mlx5_common_device *cdev; 429ad435d32SXueming Li 43085209924SMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) { 43185209924SMichael Baum if (rte_dev == cdev->dev) 43285209924SMichael Baum return cdev; 433ad435d32SXueming Li } 434ad435d32SXueming Li return NULL; 435ad435d32SXueming Li } 436ad435d32SXueming Li 4374d567938SThomas Monjalon int 4384d567938SThomas Monjalon mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size) 4394d567938SThomas Monjalon { 4404d567938SThomas Monjalon struct rte_pci_addr pci_addr = { 0 }; 4414d567938SThomas Monjalon int ret; 4424d567938SThomas Monjalon 4434d567938SThomas Monjalon if (mlx5_dev_is_pci(dev)) { 4444d567938SThomas Monjalon /* Input might be <BDF>, format PCI address to <DBDF>. */ 4454d567938SThomas Monjalon ret = rte_pci_addr_parse(dev->name, &pci_addr); 4464d567938SThomas Monjalon if (ret != 0) 4474d567938SThomas Monjalon return -ENODEV; 4484d567938SThomas Monjalon rte_pci_device_name(&pci_addr, addr, size); 4494d567938SThomas Monjalon return 0; 4504d567938SThomas Monjalon } 4514d567938SThomas Monjalon #ifdef RTE_EXEC_ENV_LINUX 4524d567938SThomas Monjalon return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev), 4534d567938SThomas Monjalon addr, size); 4544d567938SThomas Monjalon #else 4554d567938SThomas Monjalon rte_errno = ENODEV; 4564d567938SThomas Monjalon return -rte_errno; 4574d567938SThomas Monjalon #endif 4584d567938SThomas Monjalon } 4594d567938SThomas Monjalon 460ca1418ceSMichael Baum /** 461fc59a1ecSMichael Baum * Register the mempool for the protection domain. 462fc59a1ecSMichael Baum * 463fc59a1ecSMichael Baum * @param cdev 464fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 465fc59a1ecSMichael Baum * @param mp 466fc59a1ecSMichael Baum * Mempool being registered. 467fc59a1ecSMichael Baum * 468fc59a1ecSMichael Baum * @return 469fc59a1ecSMichael Baum * 0 on success, (-1) on failure and rte_errno is set. 470fc59a1ecSMichael Baum */ 471fc59a1ecSMichael Baum static int 472fc59a1ecSMichael Baum mlx5_dev_mempool_register(struct mlx5_common_device *cdev, 47308ac0358SDmitry Kozlyuk struct rte_mempool *mp, bool is_extmem) 474fc59a1ecSMichael Baum { 47508ac0358SDmitry Kozlyuk return mlx5_mr_mempool_register(cdev, mp, is_extmem); 476fc59a1ecSMichael Baum } 477fc59a1ecSMichael Baum 478fc59a1ecSMichael Baum /** 479fc59a1ecSMichael Baum * Unregister the mempool from the protection domain. 480fc59a1ecSMichael Baum * 481fc59a1ecSMichael Baum * @param cdev 482fc59a1ecSMichael Baum * Pointer to the mlx5 common device. 483fc59a1ecSMichael Baum * @param mp 484fc59a1ecSMichael Baum * Mempool being unregistered. 485fc59a1ecSMichael Baum */ 486fc59a1ecSMichael Baum void 487fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(struct mlx5_common_device *cdev, 488fc59a1ecSMichael Baum struct rte_mempool *mp) 489fc59a1ecSMichael Baum { 49020489176SMichael Baum if (mlx5_mr_mempool_unregister(cdev, mp) < 0) 491fc59a1ecSMichael Baum DRV_LOG(WARNING, "Failed to unregister mempool %s for PD %p: %s", 492fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 493fc59a1ecSMichael Baum } 494fc59a1ecSMichael Baum 495fc59a1ecSMichael Baum /** 496fc59a1ecSMichael Baum * rte_mempool_walk() callback to register mempools for the protection domain. 497fc59a1ecSMichael Baum * 498fc59a1ecSMichael Baum * @param mp 499fc59a1ecSMichael Baum * The mempool being walked. 500fc59a1ecSMichael Baum * @param arg 501fc59a1ecSMichael Baum * Pointer to the device shared context. 502fc59a1ecSMichael Baum */ 503fc59a1ecSMichael Baum static void 504fc59a1ecSMichael Baum mlx5_dev_mempool_register_cb(struct rte_mempool *mp, void *arg) 505fc59a1ecSMichael Baum { 506fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 507fc59a1ecSMichael Baum int ret; 508fc59a1ecSMichael Baum 50908ac0358SDmitry Kozlyuk ret = mlx5_dev_mempool_register(cdev, mp, false); 510fc59a1ecSMichael Baum if (ret < 0 && rte_errno != EEXIST) 511fc59a1ecSMichael Baum DRV_LOG(ERR, 512fc59a1ecSMichael Baum "Failed to register existing mempool %s for PD %p: %s", 513fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 514fc59a1ecSMichael Baum } 515fc59a1ecSMichael Baum 516fc59a1ecSMichael Baum /** 517fc59a1ecSMichael Baum * rte_mempool_walk() callback to unregister mempools 518fc59a1ecSMichael Baum * from the protection domain. 519fc59a1ecSMichael Baum * 520fc59a1ecSMichael Baum * @param mp 521fc59a1ecSMichael Baum * The mempool being walked. 522fc59a1ecSMichael Baum * @param arg 523fc59a1ecSMichael Baum * Pointer to the device shared context. 524fc59a1ecSMichael Baum */ 525fc59a1ecSMichael Baum static void 526fc59a1ecSMichael Baum mlx5_dev_mempool_unregister_cb(struct rte_mempool *mp, void *arg) 527fc59a1ecSMichael Baum { 528fc59a1ecSMichael Baum mlx5_dev_mempool_unregister((struct mlx5_common_device *)arg, mp); 529fc59a1ecSMichael Baum } 530fc59a1ecSMichael Baum 531fc59a1ecSMichael Baum /** 532fc59a1ecSMichael Baum * Mempool life cycle callback for mlx5 common devices. 533fc59a1ecSMichael Baum * 534fc59a1ecSMichael Baum * @param event 535fc59a1ecSMichael Baum * Mempool life cycle event. 536fc59a1ecSMichael Baum * @param mp 537fc59a1ecSMichael Baum * Associated mempool. 538fc59a1ecSMichael Baum * @param arg 539fc59a1ecSMichael Baum * Pointer to a device shared context. 540fc59a1ecSMichael Baum */ 541fc59a1ecSMichael Baum static void 542fc59a1ecSMichael Baum mlx5_dev_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp, 543fc59a1ecSMichael Baum void *arg) 544fc59a1ecSMichael Baum { 545fc59a1ecSMichael Baum struct mlx5_common_device *cdev = arg; 546fc59a1ecSMichael Baum 547fc59a1ecSMichael Baum switch (event) { 548fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_READY: 54908ac0358SDmitry Kozlyuk if (mlx5_dev_mempool_register(cdev, mp, false) < 0) 550fc59a1ecSMichael Baum DRV_LOG(ERR, 551fc59a1ecSMichael Baum "Failed to register new mempool %s for PD %p: %s", 552fc59a1ecSMichael Baum mp->name, cdev->pd, rte_strerror(rte_errno)); 553fc59a1ecSMichael Baum break; 554fc59a1ecSMichael Baum case RTE_MEMPOOL_EVENT_DESTROY: 555fc59a1ecSMichael Baum mlx5_dev_mempool_unregister(cdev, mp); 556fc59a1ecSMichael Baum break; 557fc59a1ecSMichael Baum } 558fc59a1ecSMichael Baum } 559fc59a1ecSMichael Baum 560fc59a1ecSMichael Baum int 561fc59a1ecSMichael Baum mlx5_dev_mempool_subscribe(struct mlx5_common_device *cdev) 562fc59a1ecSMichael Baum { 563fc59a1ecSMichael Baum int ret = 0; 564fc59a1ecSMichael Baum 565fc59a1ecSMichael Baum if (!cdev->config.mr_mempool_reg_en) 566fc59a1ecSMichael Baum return 0; 567fc59a1ecSMichael Baum rte_rwlock_write_lock(&cdev->mr_scache.mprwlock); 568fc59a1ecSMichael Baum if (cdev->mr_scache.mp_cb_registered) 569fc59a1ecSMichael Baum goto exit; 570fc59a1ecSMichael Baum /* Callback for this device may be already registered. */ 571fc59a1ecSMichael Baum ret = rte_mempool_event_callback_register(mlx5_dev_mempool_event_cb, 572fc59a1ecSMichael Baum cdev); 573fc59a1ecSMichael Baum if (ret != 0 && rte_errno != EEXIST) 574fc59a1ecSMichael Baum goto exit; 575fc59a1ecSMichael Baum /* Register mempools only once for this device. */ 576fc59a1ecSMichael Baum if (ret == 0) 577fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_register_cb, cdev); 578fc59a1ecSMichael Baum ret = 0; 579fc59a1ecSMichael Baum cdev->mr_scache.mp_cb_registered = 1; 580fc59a1ecSMichael Baum exit: 581fc59a1ecSMichael Baum rte_rwlock_write_unlock(&cdev->mr_scache.mprwlock); 582fc59a1ecSMichael Baum return ret; 583fc59a1ecSMichael Baum } 584fc59a1ecSMichael Baum 585fc59a1ecSMichael Baum static void 586fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(struct mlx5_common_device *cdev) 587fc59a1ecSMichael Baum { 588fc59a1ecSMichael Baum int ret; 589fc59a1ecSMichael Baum 590fc59a1ecSMichael Baum if (!cdev->mr_scache.mp_cb_registered || 591fc59a1ecSMichael Baum !cdev->config.mr_mempool_reg_en) 592fc59a1ecSMichael Baum return; 593fc59a1ecSMichael Baum /* Stop watching for mempool events and unregister all mempools. */ 594fc59a1ecSMichael Baum ret = rte_mempool_event_callback_unregister(mlx5_dev_mempool_event_cb, 595fc59a1ecSMichael Baum cdev); 596fc59a1ecSMichael Baum if (ret == 0) 597fc59a1ecSMichael Baum rte_mempool_walk(mlx5_dev_mempool_unregister_cb, cdev); 598fc59a1ecSMichael Baum } 599fc59a1ecSMichael Baum 600fc59a1ecSMichael Baum /** 6019f1d636fSMichael Baum * Callback for memory event. 6029f1d636fSMichael Baum * 6039f1d636fSMichael Baum * @param event_type 6049f1d636fSMichael Baum * Memory event type. 6059f1d636fSMichael Baum * @param addr 6069f1d636fSMichael Baum * Address of memory. 6079f1d636fSMichael Baum * @param len 6089f1d636fSMichael Baum * Size of memory. 6099f1d636fSMichael Baum */ 6109f1d636fSMichael Baum static void 6119f1d636fSMichael Baum mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr, 6129f1d636fSMichael Baum size_t len, void *arg __rte_unused) 6139f1d636fSMichael Baum { 6149f1d636fSMichael Baum struct mlx5_common_device *cdev; 6159f1d636fSMichael Baum 6169f1d636fSMichael Baum /* Must be called from the primary process. */ 6179f1d636fSMichael Baum MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 6189f1d636fSMichael Baum switch (event_type) { 6199f1d636fSMichael Baum case RTE_MEM_EVENT_FREE: 6209f1d636fSMichael Baum pthread_mutex_lock(&devices_list_lock); 6219f1d636fSMichael Baum /* Iterate all the existing mlx5 devices. */ 6229f1d636fSMichael Baum TAILQ_FOREACH(cdev, &devices_list, next) 6239f1d636fSMichael Baum mlx5_free_mr_by_addr(&cdev->mr_scache, 6249f1d636fSMichael Baum mlx5_os_get_ctx_device_name 6259f1d636fSMichael Baum (cdev->ctx), 6269f1d636fSMichael Baum addr, len); 6279f1d636fSMichael Baum pthread_mutex_unlock(&devices_list_lock); 6289f1d636fSMichael Baum break; 6299f1d636fSMichael Baum case RTE_MEM_EVENT_ALLOC: 6309f1d636fSMichael Baum default: 6319f1d636fSMichael Baum break; 6329f1d636fSMichael Baum } 6339f1d636fSMichael Baum } 6349f1d636fSMichael Baum 6359f1d636fSMichael Baum /** 636ca1418ceSMichael Baum * Uninitialize all HW global of device context. 637ca1418ceSMichael Baum * 638ca1418ceSMichael Baum * @param cdev 639ca1418ceSMichael Baum * Pointer to mlx5 device structure. 640ca1418ceSMichael Baum * 641ca1418ceSMichael Baum * @return 642ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 643ca1418ceSMichael Baum */ 644ca1418ceSMichael Baum static void 645ca1418ceSMichael Baum mlx5_dev_hw_global_release(struct mlx5_common_device *cdev) 646ca1418ceSMichael Baum { 647e35ccf24SMichael Baum if (cdev->pd != NULL) { 648e35ccf24SMichael Baum claim_zero(mlx5_os_dealloc_pd(cdev->pd)); 649e35ccf24SMichael Baum cdev->pd = NULL; 650e35ccf24SMichael Baum } 651ca1418ceSMichael Baum if (cdev->ctx != NULL) { 652ca1418ceSMichael Baum claim_zero(mlx5_glue->close_device(cdev->ctx)); 653ca1418ceSMichael Baum cdev->ctx = NULL; 654ca1418ceSMichael Baum } 655ca1418ceSMichael Baum } 656ca1418ceSMichael Baum 657ca1418ceSMichael Baum /** 658ca1418ceSMichael Baum * Initialize all HW global of device context. 659ca1418ceSMichael Baum * 660ca1418ceSMichael Baum * @param cdev 661ca1418ceSMichael Baum * Pointer to mlx5 device structure. 662ca1418ceSMichael Baum * @param classes 663ca1418ceSMichael Baum * Chosen classes come from user device arguments. 664ca1418ceSMichael Baum * 665ca1418ceSMichael Baum * @return 666ca1418ceSMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 667ca1418ceSMichael Baum */ 668ca1418ceSMichael Baum static int 669ca1418ceSMichael Baum mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes) 670ca1418ceSMichael Baum { 671ca1418ceSMichael Baum int ret; 672ca1418ceSMichael Baum 673ca1418ceSMichael Baum /* Create context device */ 674ca1418ceSMichael Baum ret = mlx5_os_open_device(cdev, classes); 675ca1418ceSMichael Baum if (ret < 0) 676ca1418ceSMichael Baum return ret; 677e35ccf24SMichael Baum /* Allocate Protection Domain object and extract its pdn. */ 678e35ccf24SMichael Baum ret = mlx5_os_pd_create(cdev); 679e35ccf24SMichael Baum if (ret) 680e35ccf24SMichael Baum goto error; 681fe46b20cSMichael Baum /* All actions taken below are relevant only when DevX is supported */ 682fe46b20cSMichael Baum if (cdev->config.devx == 0) 683fe46b20cSMichael Baum return 0; 684fe46b20cSMichael Baum /* Query HCA attributes. */ 685fe46b20cSMichael Baum ret = mlx5_devx_cmd_query_hca_attr(cdev->ctx, &cdev->config.hca_attr); 686fe46b20cSMichael Baum if (ret) { 687fe46b20cSMichael Baum DRV_LOG(ERR, "Unable to read HCA capabilities."); 688fe46b20cSMichael Baum rte_errno = ENOTSUP; 689fe46b20cSMichael Baum goto error; 690fe46b20cSMichael Baum } 691ca1418ceSMichael Baum return 0; 692e35ccf24SMichael Baum error: 693e35ccf24SMichael Baum mlx5_dev_hw_global_release(cdev); 694e35ccf24SMichael Baum return ret; 695ca1418ceSMichael Baum } 696ca1418ceSMichael Baum 697ad435d32SXueming Li static void 69885209924SMichael Baum mlx5_common_dev_release(struct mlx5_common_device *cdev) 699ad435d32SXueming Li { 700dc26c9c2SMichael Baum pthread_mutex_lock(&devices_list_lock); 70185209924SMichael Baum TAILQ_REMOVE(&devices_list, cdev, next); 702dc26c9c2SMichael Baum pthread_mutex_unlock(&devices_list_lock); 7039f1d636fSMichael Baum if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 7049f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 7059f1d636fSMichael Baum rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB", 7069f1d636fSMichael Baum NULL); 707fc59a1ecSMichael Baum mlx5_dev_mempool_unsubscribe(cdev); 7089f1d636fSMichael Baum mlx5_mr_release_cache(&cdev->mr_scache); 709ca1418ceSMichael Baum mlx5_dev_hw_global_release(cdev); 7109f1d636fSMichael Baum } 71185209924SMichael Baum rte_free(cdev); 71285209924SMichael Baum } 71385209924SMichael Baum 71485209924SMichael Baum static struct mlx5_common_device * 715a729d2f0SMichael Baum mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes, 716a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 71785209924SMichael Baum { 71885209924SMichael Baum struct mlx5_common_device *cdev; 71985209924SMichael Baum int ret; 72085209924SMichael Baum 72185209924SMichael Baum cdev = rte_zmalloc("mlx5_common_device", sizeof(*cdev), 0); 72285209924SMichael Baum if (!cdev) { 72385209924SMichael Baum DRV_LOG(ERR, "Device allocation failure."); 72485209924SMichael Baum rte_errno = ENOMEM; 72585209924SMichael Baum return NULL; 72685209924SMichael Baum } 72785209924SMichael Baum cdev->dev = eal_dev; 72885209924SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 72985209924SMichael Baum goto exit; 73085209924SMichael Baum /* Parse device parameters. */ 731a729d2f0SMichael Baum ret = mlx5_common_config_get(mkvlist, &cdev->config); 73285209924SMichael Baum if (ret < 0) { 73385209924SMichael Baum DRV_LOG(ERR, "Failed to process device arguments: %s", 73485209924SMichael Baum strerror(rte_errno)); 73585209924SMichael Baum rte_free(cdev); 73685209924SMichael Baum return NULL; 73785209924SMichael Baum } 73885209924SMichael Baum mlx5_malloc_mem_select(cdev->config.sys_mem_en); 739ca1418ceSMichael Baum /* Initialize all HW global of device context. */ 740ca1418ceSMichael Baum ret = mlx5_dev_hw_global_prepare(cdev, classes); 741ca1418ceSMichael Baum if (ret) { 742ca1418ceSMichael Baum DRV_LOG(ERR, "Failed to initialize device context."); 743ca1418ceSMichael Baum rte_free(cdev); 744ca1418ceSMichael Baum return NULL; 745ca1418ceSMichael Baum } 7469f1d636fSMichael Baum /* Initialize global MR cache resources and update its functions. */ 7479f1d636fSMichael Baum ret = mlx5_mr_create_cache(&cdev->mr_scache, eal_dev->numa_node); 7489f1d636fSMichael Baum if (ret) { 7499f1d636fSMichael Baum DRV_LOG(ERR, "Failed to initialize global MR share cache."); 7509f1d636fSMichael Baum mlx5_dev_hw_global_release(cdev); 7519f1d636fSMichael Baum rte_free(cdev); 7529f1d636fSMichael Baum return NULL; 7539f1d636fSMichael Baum } 7549f1d636fSMichael Baum /* Register callback function for global shared MR cache management. */ 7559f1d636fSMichael Baum if (TAILQ_EMPTY(&devices_list)) 7569f1d636fSMichael Baum rte_mem_event_callback_register("MLX5_MEM_EVENT_CB", 7579f1d636fSMichael Baum mlx5_mr_mem_event_cb, NULL); 75885209924SMichael Baum exit: 75985209924SMichael Baum pthread_mutex_lock(&devices_list_lock); 76085209924SMichael Baum TAILQ_INSERT_HEAD(&devices_list, cdev, next); 76185209924SMichael Baum pthread_mutex_unlock(&devices_list_lock); 76285209924SMichael Baum return cdev; 763ad435d32SXueming Li } 764ad435d32SXueming Li 765c089eb93SMichael Baum /** 766c089eb93SMichael Baum * Validate common devargs when probing again. 767c089eb93SMichael Baum * 768c089eb93SMichael Baum * When common device probing again, it cannot change its configurations. 769c089eb93SMichael Baum * If user ask non compatible configurations in devargs, it is error. 770c089eb93SMichael Baum * This function checks the match between: 771c089eb93SMichael Baum * - Common device configurations requested by probe again devargs. 772c089eb93SMichael Baum * - Existing common device configurations. 773c089eb93SMichael Baum * 774c089eb93SMichael Baum * @param cdev 775c089eb93SMichael Baum * Pointer to mlx5 device structure. 776a729d2f0SMichael Baum * @param mkvlist 777a729d2f0SMichael Baum * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. 778c089eb93SMichael Baum * 779c089eb93SMichael Baum * @return 780c089eb93SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 781c089eb93SMichael Baum */ 782c089eb93SMichael Baum static int 783a729d2f0SMichael Baum mlx5_common_probe_again_args_validate(struct mlx5_common_device *cdev, 784a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 785c089eb93SMichael Baum { 786c089eb93SMichael Baum struct mlx5_common_dev_config *config; 787c089eb93SMichael Baum int ret; 788c089eb93SMichael Baum 789c089eb93SMichael Baum /* Secondary process should not handle devargs. */ 790c089eb93SMichael Baum if (rte_eal_process_type() != RTE_PROC_PRIMARY) 791c089eb93SMichael Baum return 0; 792c089eb93SMichael Baum /* Probe again doesn't have to generate devargs. */ 793a729d2f0SMichael Baum if (mkvlist == NULL) 794c089eb93SMichael Baum return 0; 795c089eb93SMichael Baum config = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, 796c089eb93SMichael Baum sizeof(struct mlx5_common_dev_config), 797c089eb93SMichael Baum RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 798c089eb93SMichael Baum if (config == NULL) { 799c089eb93SMichael Baum rte_errno = -ENOMEM; 800c089eb93SMichael Baum return -rte_errno; 801c089eb93SMichael Baum } 802c089eb93SMichael Baum /* 803c089eb93SMichael Baum * Creates a temporary common configure structure according to new 804c089eb93SMichael Baum * devargs attached in probing again. 805c089eb93SMichael Baum */ 806a729d2f0SMichael Baum ret = mlx5_common_config_get(mkvlist, config); 807c089eb93SMichael Baum if (ret) { 808c089eb93SMichael Baum DRV_LOG(ERR, "Failed to process device configure: %s", 809c089eb93SMichael Baum strerror(rte_errno)); 810c089eb93SMichael Baum mlx5_free(config); 811c089eb93SMichael Baum return ret; 812c089eb93SMichael Baum } 813c089eb93SMichael Baum /* 814c089eb93SMichael Baum * Checks the match between the temporary structure and the existing 815c089eb93SMichael Baum * common device structure. 816c089eb93SMichael Baum */ 817c089eb93SMichael Baum if (cdev->config.mr_ext_memseg_en ^ config->mr_ext_memseg_en) { 818c089eb93SMichael Baum DRV_LOG(ERR, "\"mr_ext_memseg_en\" " 819c089eb93SMichael Baum "configuration mismatch for device %s.", 820c089eb93SMichael Baum cdev->dev->name); 821c089eb93SMichael Baum goto error; 822c089eb93SMichael Baum } 823c089eb93SMichael Baum if (cdev->config.mr_mempool_reg_en ^ config->mr_mempool_reg_en) { 824c089eb93SMichael Baum DRV_LOG(ERR, "\"mr_mempool_reg_en\" " 825c089eb93SMichael Baum "configuration mismatch for device %s.", 826c089eb93SMichael Baum cdev->dev->name); 827c089eb93SMichael Baum goto error; 828c089eb93SMichael Baum } 829c089eb93SMichael Baum if (cdev->config.sys_mem_en ^ config->sys_mem_en) { 830c089eb93SMichael Baum DRV_LOG(ERR, 831c089eb93SMichael Baum "\"sys_mem_en\" configuration mismatch for device %s.", 832c089eb93SMichael Baum cdev->dev->name); 833c089eb93SMichael Baum goto error; 834c089eb93SMichael Baum } 835c089eb93SMichael Baum if (cdev->config.dbnc ^ config->dbnc) { 836c089eb93SMichael Baum DRV_LOG(ERR, "\"dbnc\" configuration mismatch for device %s.", 837c089eb93SMichael Baum cdev->dev->name); 838c089eb93SMichael Baum goto error; 839c089eb93SMichael Baum } 840c089eb93SMichael Baum mlx5_free(config); 841c089eb93SMichael Baum return 0; 842c089eb93SMichael Baum error: 843c089eb93SMichael Baum mlx5_free(config); 844c089eb93SMichael Baum rte_errno = EINVAL; 845c089eb93SMichael Baum return -rte_errno; 846c089eb93SMichael Baum } 847c089eb93SMichael Baum 848ad435d32SXueming Li static int 84985209924SMichael Baum drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes) 850ad435d32SXueming Li { 851ad435d32SXueming Li struct mlx5_class_driver *driver; 852ad435d32SXueming Li int local_ret = -ENODEV; 853ad435d32SXueming Li unsigned int i = 0; 854ad435d32SXueming Li int ret = 0; 855ad435d32SXueming Li 856ad435d32SXueming Li while (enabled_classes) { 857ad435d32SXueming Li driver = driver_get(RTE_BIT64(i)); 858ad435d32SXueming Li if (driver != NULL) { 85985209924SMichael Baum local_ret = driver->remove(cdev); 860ad435d32SXueming Li if (local_ret == 0) 86185209924SMichael Baum cdev->classes_loaded &= ~RTE_BIT64(i); 862ad435d32SXueming Li else if (ret == 0) 863ad435d32SXueming Li ret = local_ret; 864ad435d32SXueming Li } 865ad435d32SXueming Li enabled_classes &= ~RTE_BIT64(i); 866ad435d32SXueming Li i++; 867ad435d32SXueming Li } 868ad435d32SXueming Li if (local_ret != 0 && ret == 0) 869ad435d32SXueming Li ret = local_ret; 870ad435d32SXueming Li return ret; 871ad435d32SXueming Li } 872ad435d32SXueming Li 873ad435d32SXueming Li static int 874a729d2f0SMichael Baum drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes, 875a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist) 876ad435d32SXueming Li { 877ad435d32SXueming Li struct mlx5_class_driver *driver; 878ad435d32SXueming Li uint32_t enabled_classes = 0; 879ad435d32SXueming Li bool already_loaded; 880b4a4159dSBing Zhao int ret = -EINVAL; 881ad435d32SXueming Li 882ad435d32SXueming Li TAILQ_FOREACH(driver, &drivers_list, next) { 883ad435d32SXueming Li if ((driver->drv_class & user_classes) == 0) 884ad435d32SXueming Li continue; 88585209924SMichael Baum if (!mlx5_bus_match(driver, cdev->dev)) 886ad435d32SXueming Li continue; 88785209924SMichael Baum already_loaded = cdev->classes_loaded & driver->drv_class; 888ad435d32SXueming Li if (already_loaded && driver->probe_again == 0) { 889ad435d32SXueming Li DRV_LOG(ERR, "Device %s is already probed", 89085209924SMichael Baum cdev->dev->name); 891ad435d32SXueming Li ret = -EEXIST; 892ad435d32SXueming Li goto probe_err; 893ad435d32SXueming Li } 894a729d2f0SMichael Baum ret = driver->probe(cdev, mkvlist); 895ad435d32SXueming Li if (ret < 0) { 896ad435d32SXueming Li DRV_LOG(ERR, "Failed to load driver %s", 897ad435d32SXueming Li driver->name); 898ad435d32SXueming Li goto probe_err; 899ad435d32SXueming Li } 900ad435d32SXueming Li enabled_classes |= driver->drv_class; 901ad435d32SXueming Li } 902b4a4159dSBing Zhao if (!ret) { 90385209924SMichael Baum cdev->classes_loaded |= enabled_classes; 904ad435d32SXueming Li return 0; 905b4a4159dSBing Zhao } 906ad435d32SXueming Li probe_err: 9078928997aSMichael Baum /* 9088928997aSMichael Baum * Need to remove only drivers which were not probed before this probe 9098928997aSMichael Baum * instance, but have already been probed before this failure. 910ad435d32SXueming Li */ 9118928997aSMichael Baum enabled_classes &= ~cdev->classes_loaded; 91285209924SMichael Baum drivers_remove(cdev, enabled_classes); 913ad435d32SXueming Li return ret; 914ad435d32SXueming Li } 915ad435d32SXueming Li 916ad435d32SXueming Li int 917ad435d32SXueming Li mlx5_common_dev_probe(struct rte_device *eal_dev) 918ad435d32SXueming Li { 91985209924SMichael Baum struct mlx5_common_device *cdev; 920a729d2f0SMichael Baum struct mlx5_kvargs_ctrl mkvlist; 921a729d2f0SMichael Baum struct mlx5_kvargs_ctrl *mkvlist_p = NULL; 922ad435d32SXueming Li uint32_t classes = 0; 923ad435d32SXueming Li bool new_device = false; 924ad435d32SXueming Li int ret; 925ad435d32SXueming Li 926ad435d32SXueming Li DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name); 927a729d2f0SMichael Baum if (eal_dev->devargs != NULL) 928a729d2f0SMichael Baum mkvlist_p = &mkvlist; 929a729d2f0SMichael Baum ret = mlx5_kvargs_prepare(mkvlist_p, eal_dev->devargs); 930a729d2f0SMichael Baum if (ret < 0) { 931a729d2f0SMichael Baum DRV_LOG(ERR, "Unsupported device arguments: %s", 932a729d2f0SMichael Baum eal_dev->devargs->args); 933a729d2f0SMichael Baum return ret; 934a729d2f0SMichael Baum } 935a729d2f0SMichael Baum ret = parse_class_options(eal_dev->devargs, mkvlist_p); 936ad435d32SXueming Li if (ret < 0) { 937ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 class type: %s", 938ad435d32SXueming Li eal_dev->devargs->args); 939a729d2f0SMichael Baum goto class_err; 940ad435d32SXueming Li } 941ad435d32SXueming Li classes = ret; 942ad435d32SXueming Li if (classes == 0) 943ad435d32SXueming Li /* Default to net class. */ 944ad435d32SXueming Li classes = MLX5_CLASS_ETH; 945c089eb93SMichael Baum /* 946c089eb93SMichael Baum * MLX5 common driver supports probing again in two scenarios: 947c089eb93SMichael Baum * - Add new driver under existing common device (regardless of the 948c089eb93SMichael Baum * driver's own support in probing again). 949c089eb93SMichael Baum * - Transfer the probing again support of the drivers themselves. 950c089eb93SMichael Baum * 951c089eb93SMichael Baum * In both scenarios it uses in the existing device. here it looks for 952c089eb93SMichael Baum * device that match to rte device, if it exists, the request classes 953c089eb93SMichael Baum * were probed with this device. 954c089eb93SMichael Baum */ 95585209924SMichael Baum cdev = to_mlx5_device(eal_dev); 95685209924SMichael Baum if (!cdev) { 957c089eb93SMichael Baum /* It isn't probing again, creates a new device. */ 958a729d2f0SMichael Baum cdev = mlx5_common_dev_create(eal_dev, classes, mkvlist_p); 959a729d2f0SMichael Baum if (!cdev) { 960a729d2f0SMichael Baum ret = -ENOMEM; 961a729d2f0SMichael Baum goto class_err; 962a729d2f0SMichael Baum } 963ad435d32SXueming Li new_device = true; 964c089eb93SMichael Baum } else { 965c089eb93SMichael Baum /* It is probing again, validate common devargs match. */ 966a729d2f0SMichael Baum ret = mlx5_common_probe_again_args_validate(cdev, mkvlist_p); 967c089eb93SMichael Baum if (ret) { 968c089eb93SMichael Baum DRV_LOG(ERR, 969c089eb93SMichael Baum "Probe again parameters aren't compatible : %s", 970c089eb93SMichael Baum strerror(rte_errno)); 971a729d2f0SMichael Baum goto class_err; 972c089eb93SMichael Baum } 973288d7c3fSMichael Baum } 974288d7c3fSMichael Baum /* 975288d7c3fSMichael Baum * Validate combination here. 976288d7c3fSMichael Baum * For new device, the classes_loaded field is 0 and it check only 977288d7c3fSMichael Baum * the classes given as user device arguments. 978288d7c3fSMichael Baum */ 97985209924SMichael Baum ret = is_valid_class_combination(classes | cdev->classes_loaded); 980ad435d32SXueming Li if (ret != 0) { 981ad435d32SXueming Li DRV_LOG(ERR, "Unsupported mlx5 classes combination."); 982288d7c3fSMichael Baum goto class_err; 983ad435d32SXueming Li } 984a729d2f0SMichael Baum ret = drivers_probe(cdev, classes, mkvlist_p); 985ad435d32SXueming Li if (ret) 986ad435d32SXueming Li goto class_err; 987a729d2f0SMichael Baum /* 988a729d2f0SMichael Baum * Validate that all devargs have been used, unused key -> unknown Key. 989a729d2f0SMichael Baum * When probe again validate is failed, the added drivers aren't removed 990a729d2f0SMichael Baum * here but when device is released. 991a729d2f0SMichael Baum */ 992a729d2f0SMichael Baum ret = mlx5_kvargs_validate(mkvlist_p); 993a729d2f0SMichael Baum if (ret) 994a729d2f0SMichael Baum goto class_err; 995a729d2f0SMichael Baum mlx5_kvargs_release(mkvlist_p); 996ad435d32SXueming Li return 0; 997ad435d32SXueming Li class_err: 998a729d2f0SMichael Baum if (new_device) { 999a729d2f0SMichael Baum /* 1000a729d2f0SMichael Baum * For new device, classes_loaded is always 0 before 1001a729d2f0SMichael Baum * drivers_probe function. 1002a729d2f0SMichael Baum */ 1003a729d2f0SMichael Baum if (cdev->classes_loaded) 1004a729d2f0SMichael Baum drivers_remove(cdev, cdev->classes_loaded); 100585209924SMichael Baum mlx5_common_dev_release(cdev); 1006a729d2f0SMichael Baum } 1007a729d2f0SMichael Baum mlx5_kvargs_release(mkvlist_p); 1008ad435d32SXueming Li return ret; 1009ad435d32SXueming Li } 1010ad435d32SXueming Li 1011ad435d32SXueming Li int 1012ad435d32SXueming Li mlx5_common_dev_remove(struct rte_device *eal_dev) 1013ad435d32SXueming Li { 101485209924SMichael Baum struct mlx5_common_device *cdev; 1015ad435d32SXueming Li int ret; 1016ad435d32SXueming Li 101785209924SMichael Baum cdev = to_mlx5_device(eal_dev); 101885209924SMichael Baum if (!cdev) 1019ad435d32SXueming Li return -ENODEV; 1020ad435d32SXueming Li /* Matching device found, cleanup and unload drivers. */ 102185209924SMichael Baum ret = drivers_remove(cdev, cdev->classes_loaded); 1022dffae63dSMichael Baum if (ret == 0) 102385209924SMichael Baum mlx5_common_dev_release(cdev); 1024ad435d32SXueming Li return ret; 1025ad435d32SXueming Li } 1026ad435d32SXueming Li 1027a5d06c90SMichael Baum /** 1028a5d06c90SMichael Baum * Callback to DMA map external memory to a device. 1029a5d06c90SMichael Baum * 1030a5d06c90SMichael Baum * @param rte_dev 1031a5d06c90SMichael Baum * Pointer to the generic device. 1032a5d06c90SMichael Baum * @param addr 1033a5d06c90SMichael Baum * Starting virtual address of memory to be mapped. 1034a5d06c90SMichael Baum * @param iova 1035a5d06c90SMichael Baum * Starting IOVA address of memory to be mapped. 1036a5d06c90SMichael Baum * @param len 1037a5d06c90SMichael Baum * Length of memory segment being mapped. 1038a5d06c90SMichael Baum * 1039a5d06c90SMichael Baum * @return 1040a5d06c90SMichael Baum * 0 on success, negative value on error. 1041a5d06c90SMichael Baum */ 1042ad435d32SXueming Li int 1043a5d06c90SMichael Baum mlx5_common_dev_dma_map(struct rte_device *rte_dev, void *addr, 1044a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len) 1045ad435d32SXueming Li { 1046a5d06c90SMichael Baum struct mlx5_common_device *dev; 1047a5d06c90SMichael Baum struct mlx5_mr *mr; 1048ad435d32SXueming Li 1049a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 1050a5d06c90SMichael Baum if (!dev) { 1051a5d06c90SMichael Baum DRV_LOG(WARNING, 1052a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s", 1053a5d06c90SMichael Baum rte_dev->name); 1054a5d06c90SMichael Baum rte_errno = ENODEV; 1055a5d06c90SMichael Baum return -1; 1056ad435d32SXueming Li } 1057a5d06c90SMichael Baum mr = mlx5_create_mr_ext(dev->pd, (uintptr_t)addr, len, 1058a5d06c90SMichael Baum SOCKET_ID_ANY, dev->mr_scache.reg_mr_cb); 1059a5d06c90SMichael Baum if (!mr) { 1060a5d06c90SMichael Baum DRV_LOG(WARNING, "Device %s unable to DMA map", rte_dev->name); 1061a5d06c90SMichael Baum rte_errno = EINVAL; 1062a5d06c90SMichael Baum return -1; 1063ad435d32SXueming Li } 1064a5d06c90SMichael Baum rte_rwlock_write_lock(&dev->mr_scache.rwlock); 1065a5d06c90SMichael Baum LIST_INSERT_HEAD(&dev->mr_scache.mr_list, mr, mr); 1066a5d06c90SMichael Baum /* Insert to the global cache table. */ 1067a5d06c90SMichael Baum mlx5_mr_insert_cache(&dev->mr_scache, mr); 1068a5d06c90SMichael Baum rte_rwlock_write_unlock(&dev->mr_scache.rwlock); 1069a5d06c90SMichael Baum return 0; 1070ad435d32SXueming Li } 1071ad435d32SXueming Li 1072a5d06c90SMichael Baum /** 1073a5d06c90SMichael Baum * Callback to DMA unmap external memory to a device. 1074a5d06c90SMichael Baum * 1075a5d06c90SMichael Baum * @param rte_dev 1076a5d06c90SMichael Baum * Pointer to the generic device. 1077a5d06c90SMichael Baum * @param addr 1078a5d06c90SMichael Baum * Starting virtual address of memory to be unmapped. 1079a5d06c90SMichael Baum * @param iova 1080a5d06c90SMichael Baum * Starting IOVA address of memory to be unmapped. 1081a5d06c90SMichael Baum * @param len 1082a5d06c90SMichael Baum * Length of memory segment being unmapped. 1083a5d06c90SMichael Baum * 1084a5d06c90SMichael Baum * @return 1085a5d06c90SMichael Baum * 0 on success, negative value on error. 1086a5d06c90SMichael Baum */ 1087ad435d32SXueming Li int 1088a5d06c90SMichael Baum mlx5_common_dev_dma_unmap(struct rte_device *rte_dev, void *addr, 1089a5d06c90SMichael Baum uint64_t iova __rte_unused, size_t len __rte_unused) 1090ad435d32SXueming Li { 1091a5d06c90SMichael Baum struct mlx5_common_device *dev; 1092a5d06c90SMichael Baum struct mr_cache_entry entry; 1093a5d06c90SMichael Baum struct mlx5_mr *mr; 1094ad435d32SXueming Li 1095a5d06c90SMichael Baum dev = to_mlx5_device(rte_dev); 1096a5d06c90SMichael Baum if (!dev) { 1097a5d06c90SMichael Baum DRV_LOG(WARNING, 1098a5d06c90SMichael Baum "Unable to find matching mlx5 device to device %s.", 1099a5d06c90SMichael Baum rte_dev->name); 1100a5d06c90SMichael Baum rte_errno = ENODEV; 1101a5d06c90SMichael Baum return -1; 1102ad435d32SXueming Li } 1103a5d06c90SMichael Baum rte_rwlock_read_lock(&dev->mr_scache.rwlock); 1104a5d06c90SMichael Baum mr = mlx5_mr_lookup_list(&dev->mr_scache, &entry, (uintptr_t)addr); 1105a5d06c90SMichael Baum if (!mr) { 1106a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1107a5d06c90SMichael Baum DRV_LOG(WARNING, 1108a5d06c90SMichael Baum "Address 0x%" PRIxPTR " wasn't registered to device %s", 1109a5d06c90SMichael Baum (uintptr_t)addr, rte_dev->name); 1110a5d06c90SMichael Baum rte_errno = EINVAL; 1111a5d06c90SMichael Baum return -1; 1112a5d06c90SMichael Baum } 1113a5d06c90SMichael Baum LIST_REMOVE(mr, mr); 1114a5d06c90SMichael Baum DRV_LOG(DEBUG, "MR(%p) is removed from list.", (void *)mr); 1115a5d06c90SMichael Baum mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb); 1116a5d06c90SMichael Baum mlx5_mr_rebuild_cache(&dev->mr_scache); 1117a5d06c90SMichael Baum /* 1118a5d06c90SMichael Baum * No explicit wmb is needed after updating dev_gen due to 1119a5d06c90SMichael Baum * store-release ordering in unlock that provides the 1120a5d06c90SMichael Baum * implicit barrier at the software visible level. 1121a5d06c90SMichael Baum */ 1122a5d06c90SMichael Baum ++dev->mr_scache.dev_gen; 1123a5d06c90SMichael Baum DRV_LOG(DEBUG, "Broadcasting local cache flush, gen=%d.", 1124a5d06c90SMichael Baum dev->mr_scache.dev_gen); 1125a5d06c90SMichael Baum rte_rwlock_read_unlock(&dev->mr_scache.rwlock); 1126a5d06c90SMichael Baum return 0; 1127ad435d32SXueming Li } 1128ad435d32SXueming Li 1129ad435d32SXueming Li void 1130ad435d32SXueming Li mlx5_class_driver_register(struct mlx5_class_driver *driver) 1131ad435d32SXueming Li { 1132ad435d32SXueming Li mlx5_common_driver_on_register_pci(driver); 1133ad435d32SXueming Li TAILQ_INSERT_TAIL(&drivers_list, driver, next); 1134ad435d32SXueming Li } 1135ad435d32SXueming Li 1136ad435d32SXueming Li static void mlx5_common_driver_init(void) 1137ad435d32SXueming Li { 1138ad435d32SXueming Li mlx5_common_pci_init(); 1139777b72a9SXueming Li #ifdef RTE_EXEC_ENV_LINUX 1140777b72a9SXueming Li mlx5_common_auxiliary_init(); 1141777b72a9SXueming Li #endif 1142ad435d32SXueming Li } 1143ad435d32SXueming Li 114482088001SParav Pandit static bool mlx5_common_initialized; 114582088001SParav Pandit 114683c99c36SThomas Monjalon /** 11477be78d02SJosh Soref * One time initialization routine for run-time dependency on glue library 114882088001SParav Pandit * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 114982088001SParav Pandit * must invoke in its constructor. 115083c99c36SThomas Monjalon */ 115182088001SParav Pandit void 115282088001SParav Pandit mlx5_common_init(void) 115383c99c36SThomas Monjalon { 115482088001SParav Pandit if (mlx5_common_initialized) 115582088001SParav Pandit return; 115682088001SParav Pandit 1157dc26c9c2SMichael Baum pthread_mutex_init(&devices_list_lock, NULL); 115879aa4307SOphir Munk mlx5_glue_constructor(); 1159ad435d32SXueming Li mlx5_common_driver_init(); 116082088001SParav Pandit mlx5_common_initialized = true; 11617b4f1e6bSMatan Azrad } 11624c204fe5SShiri Kuzin 11634c204fe5SShiri Kuzin /** 11644c204fe5SShiri Kuzin * This function is responsible of initializing the variable 11654c204fe5SShiri Kuzin * haswell_broadwell_cpu by checking if the cpu is intel 11664c204fe5SShiri Kuzin * and reading the data returned from mlx5_cpu_id(). 11674c204fe5SShiri Kuzin * since haswell and broadwell cpus don't have improved performance 11684c204fe5SShiri Kuzin * when using relaxed ordering we want to check the cpu type before 11694c204fe5SShiri Kuzin * before deciding whether to enable RO or not. 11704c204fe5SShiri Kuzin * if the cpu is haswell or broadwell the variable will be set to 1 11714c204fe5SShiri Kuzin * otherwise it will be 0. 11724c204fe5SShiri Kuzin */ 11734c204fe5SShiri Kuzin RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 11744c204fe5SShiri Kuzin { 11754c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 11764c204fe5SShiri Kuzin unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 11774c204fe5SShiri Kuzin unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 11784c204fe5SShiri Kuzin unsigned int i, model, family, brand_id, vendor; 11794c204fe5SShiri Kuzin unsigned int signature_intel_ebx = 0x756e6547; 11804c204fe5SShiri Kuzin unsigned int extended_model; 11814c204fe5SShiri Kuzin unsigned int eax = 0; 11824c204fe5SShiri Kuzin unsigned int ebx = 0; 11834c204fe5SShiri Kuzin unsigned int ecx = 0; 11844c204fe5SShiri Kuzin unsigned int edx = 0; 11854c204fe5SShiri Kuzin int max_level; 11864c204fe5SShiri Kuzin 11874c204fe5SShiri Kuzin mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 11884c204fe5SShiri Kuzin vendor = ebx; 11894c204fe5SShiri Kuzin max_level = eax; 11904c204fe5SShiri Kuzin if (max_level < 1) { 11914c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 11924c204fe5SShiri Kuzin return; 11934c204fe5SShiri Kuzin } 11944c204fe5SShiri Kuzin mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 11954c204fe5SShiri Kuzin model = (eax >> 4) & 0x0f; 11964c204fe5SShiri Kuzin family = (eax >> 8) & 0x0f; 11974c204fe5SShiri Kuzin brand_id = ebx & 0xff; 11984c204fe5SShiri Kuzin extended_model = (eax >> 12) & 0xf0; 11994c204fe5SShiri Kuzin /* Check if the processor is Haswell or Broadwell */ 12004c204fe5SShiri Kuzin if (vendor == signature_intel_ebx) { 12014c204fe5SShiri Kuzin if (family == 0x06) 12024c204fe5SShiri Kuzin model += extended_model; 12034c204fe5SShiri Kuzin if (brand_id == 0 && family == 0x6) { 12044c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(broadwell_models); i++) 12054c204fe5SShiri Kuzin if (model == broadwell_models[i]) { 12064c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 12074c204fe5SShiri Kuzin return; 12084c204fe5SShiri Kuzin } 12094c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(haswell_models); i++) 12104c204fe5SShiri Kuzin if (model == haswell_models[i]) { 12114c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 12124c204fe5SShiri Kuzin return; 12134c204fe5SShiri Kuzin } 12144c204fe5SShiri Kuzin } 12154c204fe5SShiri Kuzin } 12164c204fe5SShiri Kuzin #endif 12174c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 12184c204fe5SShiri Kuzin } 1219262c7ad0SOri Kam 1220262c7ad0SOri Kam /** 12219cc0e99cSViacheslav Ovsiienko * Allocate the User Access Region with DevX on specified device. 1222b4371d3dSMichael Baum * This routine handles the following UAR allocation issues: 12239cc0e99cSViacheslav Ovsiienko * 12245dfa003dSMichael Baum * - Try to allocate the UAR with the most appropriate memory mapping 1225b4371d3dSMichael Baum * type from the ones supported by the host. 1226b4371d3dSMichael Baum * 12275dfa003dSMichael Baum * - Try to allocate the UAR with non-NULL base address OFED 5.0.x and 1228b4371d3dSMichael Baum * Upstream rdma_core before v29 returned the NULL as UAR base address 1229b4371d3dSMichael Baum * if UAR was not the first object in the UAR page. 1230b4371d3dSMichael Baum * It caused the PMD failure and we should try to get another UAR till 1231b4371d3dSMichael Baum * we get the first one with non-NULL base address returned. 1232b4371d3dSMichael Baum * 1233b4371d3dSMichael Baum * @param [in] cdev 1234b4371d3dSMichael Baum * Pointer to mlx5 device structure to perform allocation on its context. 12359cc0e99cSViacheslav Ovsiienko * 12369cc0e99cSViacheslav Ovsiienko * @return 12379cc0e99cSViacheslav Ovsiienko * UAR object pointer on success, NULL otherwise and rte_errno is set. 12389cc0e99cSViacheslav Ovsiienko */ 12395dfa003dSMichael Baum static void * 1240b4371d3dSMichael Baum mlx5_devx_alloc_uar(struct mlx5_common_device *cdev) 12419cc0e99cSViacheslav Ovsiienko { 12429cc0e99cSViacheslav Ovsiienko void *uar; 12439cc0e99cSViacheslav Ovsiienko uint32_t retry, uar_mapping; 12449cc0e99cSViacheslav Ovsiienko void *base_addr; 12459cc0e99cSViacheslav Ovsiienko 12469cc0e99cSViacheslav Ovsiienko for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 12479cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 12489cc0e99cSViacheslav Ovsiienko /* Control the mapping type according to the settings. */ 1249*a6b9d5a5SMichael Baum uar_mapping = (cdev->config.dbnc == MLX5_SQ_DB_NCACHED) ? 1250b4371d3dSMichael Baum MLX5DV_UAR_ALLOC_TYPE_NC : MLX5DV_UAR_ALLOC_TYPE_BF; 12519cc0e99cSViacheslav Ovsiienko #else 12529cc0e99cSViacheslav Ovsiienko /* 12539cc0e99cSViacheslav Ovsiienko * It seems we have no way to control the memory mapping type 12549cc0e99cSViacheslav Ovsiienko * for the UAR, the default "Write-Combining" type is supposed. 12559cc0e99cSViacheslav Ovsiienko */ 12569cc0e99cSViacheslav Ovsiienko uar_mapping = 0; 12579cc0e99cSViacheslav Ovsiienko #endif 1258b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 12599cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1260b4371d3dSMichael Baum if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 1261b4371d3dSMichael Baum /* 1262b4371d3dSMichael Baum * In some environments like virtual machine the 1263b4371d3dSMichael Baum * Write Combining mapped might be not supported and 1264b4371d3dSMichael Baum * UAR allocation fails. We tried "Non-Cached" mapping 1265b4371d3dSMichael Baum * for the case. 1266b4371d3dSMichael Baum */ 1267b4371d3dSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (BF)"); 1268b4371d3dSMichael Baum uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 1269b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 1270b4371d3dSMichael Baum } else if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 12719cc0e99cSViacheslav Ovsiienko /* 12729cc0e99cSViacheslav Ovsiienko * If Verbs/kernel does not support "Non-Cached" 12739cc0e99cSViacheslav Ovsiienko * try the "Write-Combining". 12749cc0e99cSViacheslav Ovsiienko */ 12753f0e54feSMichael Baum DRV_LOG(DEBUG, "Failed to allocate DevX UAR (NC)"); 12769cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 1277b4371d3dSMichael Baum uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping); 12789cc0e99cSViacheslav Ovsiienko } 12799cc0e99cSViacheslav Ovsiienko #endif 12809cc0e99cSViacheslav Ovsiienko if (!uar) { 12819cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 12829cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 12839cc0e99cSViacheslav Ovsiienko goto exit; 12849cc0e99cSViacheslav Ovsiienko } 12859cc0e99cSViacheslav Ovsiienko base_addr = mlx5_os_get_devx_uar_base_addr(uar); 12869cc0e99cSViacheslav Ovsiienko if (base_addr) 12879cc0e99cSViacheslav Ovsiienko break; 12889cc0e99cSViacheslav Ovsiienko /* 12899cc0e99cSViacheslav Ovsiienko * The UARs are allocated by rdma_core within the 12909cc0e99cSViacheslav Ovsiienko * IB device context, on context closure all UARs 12919cc0e99cSViacheslav Ovsiienko * will be freed, should be no memory/object leakage. 12929cc0e99cSViacheslav Ovsiienko */ 12933f0e54feSMichael Baum DRV_LOG(DEBUG, "Retrying to allocate DevX UAR"); 12949cc0e99cSViacheslav Ovsiienko uar = NULL; 12959cc0e99cSViacheslav Ovsiienko } 12969cc0e99cSViacheslav Ovsiienko /* Check whether we finally succeeded with valid UAR allocation. */ 12979cc0e99cSViacheslav Ovsiienko if (!uar) { 12989cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 12999cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 13009cc0e99cSViacheslav Ovsiienko } 13019cc0e99cSViacheslav Ovsiienko /* 13029cc0e99cSViacheslav Ovsiienko * Return void * instead of struct mlx5dv_devx_uar * 13039cc0e99cSViacheslav Ovsiienko * is for compatibility with older rdma-core library headers. 13049cc0e99cSViacheslav Ovsiienko */ 13059cc0e99cSViacheslav Ovsiienko exit: 13069cc0e99cSViacheslav Ovsiienko return uar; 13079cc0e99cSViacheslav Ovsiienko } 1308ad435d32SXueming Li 13095dfa003dSMichael Baum void 13105dfa003dSMichael Baum mlx5_devx_uar_release(struct mlx5_uar *uar) 13115dfa003dSMichael Baum { 13125dfa003dSMichael Baum if (uar->obj != NULL) 13135dfa003dSMichael Baum mlx5_glue->devx_free_uar(uar->obj); 13145dfa003dSMichael Baum memset(uar, 0, sizeof(*uar)); 13155dfa003dSMichael Baum } 13165dfa003dSMichael Baum 13175dfa003dSMichael Baum int 13185dfa003dSMichael Baum mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar) 13195dfa003dSMichael Baum { 13205dfa003dSMichael Baum off_t uar_mmap_offset; 13215dfa003dSMichael Baum const size_t page_size = rte_mem_page_size(); 13225dfa003dSMichael Baum void *base_addr; 13235dfa003dSMichael Baum void *uar_obj; 13245dfa003dSMichael Baum 13255dfa003dSMichael Baum if (page_size == (size_t)-1) { 13265dfa003dSMichael Baum DRV_LOG(ERR, "Failed to get mem page size"); 13275dfa003dSMichael Baum rte_errno = ENOMEM; 13285dfa003dSMichael Baum return -1; 13295dfa003dSMichael Baum } 13305dfa003dSMichael Baum uar_obj = mlx5_devx_alloc_uar(cdev); 13315dfa003dSMichael Baum if (uar_obj == NULL || mlx5_os_get_devx_uar_reg_addr(uar_obj) == NULL) { 13325dfa003dSMichael Baum rte_errno = errno; 13335dfa003dSMichael Baum DRV_LOG(ERR, "Failed to allocate UAR."); 13345dfa003dSMichael Baum return -1; 13355dfa003dSMichael Baum } 13365dfa003dSMichael Baum uar->obj = uar_obj; 13375dfa003dSMichael Baum uar_mmap_offset = mlx5_os_get_devx_uar_mmap_offset(uar_obj); 13385dfa003dSMichael Baum base_addr = mlx5_os_get_devx_uar_base_addr(uar_obj); 13395dfa003dSMichael Baum uar->dbnc = mlx5_db_map_type_get(uar_mmap_offset, page_size); 13405dfa003dSMichael Baum uar->bf_db.db = mlx5_os_get_devx_uar_reg_addr(uar_obj); 13415dfa003dSMichael Baum uar->cq_db.db = RTE_PTR_ADD(base_addr, MLX5_CQ_DOORBELL); 13425dfa003dSMichael Baum #ifndef RTE_ARCH_64 13435dfa003dSMichael Baum rte_spinlock_init(&uar->bf_sl); 13445dfa003dSMichael Baum rte_spinlock_init(&uar->cq_sl); 13455dfa003dSMichael Baum uar->bf_db.sl_p = &uar->bf_sl; 13465dfa003dSMichael Baum uar->cq_db.sl_p = &uar->cq_sl; 13475dfa003dSMichael Baum #endif /* RTE_ARCH_64 */ 13485dfa003dSMichael Baum return 0; 13495dfa003dSMichael Baum } 13505dfa003dSMichael Baum 1351ad435d32SXueming Li RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__); 1352