1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2019 Mellanox Technologies, Ltd 3 */ 4 5 #include <unistd.h> 6 #include <string.h> 7 #include <stdio.h> 8 9 #include <rte_errno.h> 10 #include <rte_mempool.h> 11 12 #include "mlx5_common.h" 13 #include "mlx5_common_os.h" 14 #include "mlx5_common_utils.h" 15 #include "mlx5_common_pci.h" 16 17 uint8_t haswell_broadwell_cpu; 18 19 /* In case this is an x86_64 intel processor to check if 20 * we should use relaxed ordering. 21 */ 22 #ifdef RTE_ARCH_X86_64 23 /** 24 * This function returns processor identification and feature information 25 * into the registers. 26 * 27 * @param eax, ebx, ecx, edx 28 * Pointers to the registers that will hold cpu information. 29 * @param level 30 * The main category of information returned. 31 */ 32 static inline void mlx5_cpu_id(unsigned int level, 33 unsigned int *eax, unsigned int *ebx, 34 unsigned int *ecx, unsigned int *edx) 35 { 36 __asm__("cpuid\n\t" 37 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 38 : "0" (level)); 39 } 40 #endif 41 42 RTE_LOG_REGISTER(mlx5_common_logtype, pmd.common.mlx5, NOTICE) 43 44 static bool mlx5_common_initialized; 45 46 /** 47 * One time innitialization routine for run-time dependency on glue library 48 * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 49 * must invoke in its constructor. 50 */ 51 void 52 mlx5_common_init(void) 53 { 54 if (mlx5_common_initialized) 55 return; 56 57 mlx5_glue_constructor(); 58 mlx5_common_pci_init(); 59 mlx5_common_initialized = true; 60 } 61 62 /** 63 * This function is responsible of initializing the variable 64 * haswell_broadwell_cpu by checking if the cpu is intel 65 * and reading the data returned from mlx5_cpu_id(). 66 * since haswell and broadwell cpus don't have improved performance 67 * when using relaxed ordering we want to check the cpu type before 68 * before deciding whether to enable RO or not. 69 * if the cpu is haswell or broadwell the variable will be set to 1 70 * otherwise it will be 0. 71 */ 72 RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 73 { 74 #ifdef RTE_ARCH_X86_64 75 unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 76 unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 77 unsigned int i, model, family, brand_id, vendor; 78 unsigned int signature_intel_ebx = 0x756e6547; 79 unsigned int extended_model; 80 unsigned int eax = 0; 81 unsigned int ebx = 0; 82 unsigned int ecx = 0; 83 unsigned int edx = 0; 84 int max_level; 85 86 mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 87 vendor = ebx; 88 max_level = eax; 89 if (max_level < 1) { 90 haswell_broadwell_cpu = 0; 91 return; 92 } 93 mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 94 model = (eax >> 4) & 0x0f; 95 family = (eax >> 8) & 0x0f; 96 brand_id = ebx & 0xff; 97 extended_model = (eax >> 12) & 0xf0; 98 /* Check if the processor is Haswell or Broadwell */ 99 if (vendor == signature_intel_ebx) { 100 if (family == 0x06) 101 model += extended_model; 102 if (brand_id == 0 && family == 0x6) { 103 for (i = 0; i < RTE_DIM(broadwell_models); i++) 104 if (model == broadwell_models[i]) { 105 haswell_broadwell_cpu = 1; 106 return; 107 } 108 for (i = 0; i < RTE_DIM(haswell_models); i++) 109 if (model == haswell_models[i]) { 110 haswell_broadwell_cpu = 1; 111 return; 112 } 113 } 114 } 115 #endif 116 haswell_broadwell_cpu = 0; 117 } 118 119 /** 120 * Allocate the User Access Region with DevX on specified device. 121 * 122 * @param [in] ctx 123 * Infiniband device context to perform allocation on. 124 * @param [in] mapping 125 * MLX5DV_UAR_ALLOC_TYPE_BF - allocate as cached memory with write-combining 126 * attributes (if supported by the host), the 127 * writes to the UAR registers must be followed 128 * by write memory barrier. 129 * MLX5DV_UAR_ALLOC_TYPE_NC - allocate as non-cached nenory, all writes are 130 * promoted to the registers immediately, no 131 * memory barriers needed. 132 * mapping < 0 - the first attempt is performed with MLX5DV_UAR_ALLOC_TYPE_BF, 133 * if this fails the next attempt with MLX5DV_UAR_ALLOC_TYPE_NC 134 * is performed. The drivers specifying negative values should 135 * always provide the write memory barrier operation after UAR 136 * register writings. 137 * If there is no definitions for the MLX5DV_UAR_ALLOC_TYPE_xx (older rdma 138 * library headers), the caller can specify 0. 139 * 140 * @return 141 * UAR object pointer on success, NULL otherwise and rte_errno is set. 142 */ 143 void * 144 mlx5_devx_alloc_uar(void *ctx, int mapping) 145 { 146 void *uar; 147 uint32_t retry, uar_mapping; 148 void *base_addr; 149 150 for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 151 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 152 /* Control the mapping type according to the settings. */ 153 uar_mapping = (mapping < 0) ? 154 MLX5DV_UAR_ALLOC_TYPE_NC : mapping; 155 #else 156 /* 157 * It seems we have no way to control the memory mapping type 158 * for the UAR, the default "Write-Combining" type is supposed. 159 */ 160 uar_mapping = 0; 161 RTE_SET_USED(mapping); 162 #endif 163 uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 164 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 165 if (!uar && 166 mapping < 0 && 167 uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 168 /* 169 * In some environments like virtual machine the 170 * Write Combining mapped might be not supported and 171 * UAR allocation fails. We tried "Non-Cached" mapping 172 * for the case. 173 */ 174 DRV_LOG(WARNING, "Failed to allocate DevX UAR (BF)"); 175 uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 176 uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 177 } else if (!uar && 178 mapping < 0 && 179 uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 180 /* 181 * If Verbs/kernel does not support "Non-Cached" 182 * try the "Write-Combining". 183 */ 184 DRV_LOG(WARNING, "Failed to allocate DevX UAR (NC)"); 185 uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 186 uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 187 } 188 #endif 189 if (!uar) { 190 DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 191 rte_errno = ENOMEM; 192 goto exit; 193 } 194 base_addr = mlx5_os_get_devx_uar_base_addr(uar); 195 if (base_addr) 196 break; 197 /* 198 * The UARs are allocated by rdma_core within the 199 * IB device context, on context closure all UARs 200 * will be freed, should be no memory/object leakage. 201 */ 202 DRV_LOG(WARNING, "Retrying to allocate DevX UAR"); 203 uar = NULL; 204 } 205 /* Check whether we finally succeeded with valid UAR allocation. */ 206 if (!uar) { 207 DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 208 rte_errno = ENOMEM; 209 } 210 /* 211 * Return void * instead of struct mlx5dv_devx_uar * 212 * is for compatibility with older rdma-core library headers. 213 */ 214 exit: 215 return uar; 216 } 217