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