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> 117b4f1e6bSMatan Azrad 127b4f1e6bSMatan Azrad #include "mlx5_common.h" 13262c7ad0SOri Kam #include "mlx5_common_os.h" 14*25245d5dSShiri Kuzin #include "mlx5_common_log.h" 158a41f4deSParav Pandit #include "mlx5_common_pci.h" 167b4f1e6bSMatan Azrad 174c204fe5SShiri Kuzin uint8_t haswell_broadwell_cpu; 184c204fe5SShiri Kuzin 194c204fe5SShiri Kuzin /* In case this is an x86_64 intel processor to check if 204c204fe5SShiri Kuzin * we should use relaxed ordering. 214c204fe5SShiri Kuzin */ 224c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 234c204fe5SShiri Kuzin /** 244c204fe5SShiri Kuzin * This function returns processor identification and feature information 254c204fe5SShiri Kuzin * into the registers. 264c204fe5SShiri Kuzin * 274c204fe5SShiri Kuzin * @param eax, ebx, ecx, edx 284c204fe5SShiri Kuzin * Pointers to the registers that will hold cpu information. 294c204fe5SShiri Kuzin * @param level 304c204fe5SShiri Kuzin * The main category of information returned. 314c204fe5SShiri Kuzin */ 324c204fe5SShiri Kuzin static inline void mlx5_cpu_id(unsigned int level, 334c204fe5SShiri Kuzin unsigned int *eax, unsigned int *ebx, 344c204fe5SShiri Kuzin unsigned int *ecx, unsigned int *edx) 354c204fe5SShiri Kuzin { 364c204fe5SShiri Kuzin __asm__("cpuid\n\t" 374c204fe5SShiri Kuzin : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 384c204fe5SShiri Kuzin : "0" (level)); 394c204fe5SShiri Kuzin } 404c204fe5SShiri Kuzin #endif 414c204fe5SShiri Kuzin 423be42081SThomas Monjalon RTE_LOG_REGISTER(mlx5_common_logtype, pmd.common.mlx5, NOTICE) 4383c99c36SThomas Monjalon 4482088001SParav Pandit static bool mlx5_common_initialized; 4582088001SParav Pandit 4683c99c36SThomas Monjalon /** 4782088001SParav Pandit * One time innitialization routine for run-time dependency on glue library 4882088001SParav Pandit * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module, 4982088001SParav Pandit * must invoke in its constructor. 5083c99c36SThomas Monjalon */ 5182088001SParav Pandit void 5282088001SParav Pandit mlx5_common_init(void) 5383c99c36SThomas Monjalon { 5482088001SParav Pandit if (mlx5_common_initialized) 5582088001SParav Pandit return; 5682088001SParav Pandit 5779aa4307SOphir Munk mlx5_glue_constructor(); 588a41f4deSParav Pandit mlx5_common_pci_init(); 5982088001SParav Pandit mlx5_common_initialized = true; 607b4f1e6bSMatan Azrad } 614c204fe5SShiri Kuzin 624c204fe5SShiri Kuzin /** 634c204fe5SShiri Kuzin * This function is responsible of initializing the variable 644c204fe5SShiri Kuzin * haswell_broadwell_cpu by checking if the cpu is intel 654c204fe5SShiri Kuzin * and reading the data returned from mlx5_cpu_id(). 664c204fe5SShiri Kuzin * since haswell and broadwell cpus don't have improved performance 674c204fe5SShiri Kuzin * when using relaxed ordering we want to check the cpu type before 684c204fe5SShiri Kuzin * before deciding whether to enable RO or not. 694c204fe5SShiri Kuzin * if the cpu is haswell or broadwell the variable will be set to 1 704c204fe5SShiri Kuzin * otherwise it will be 0. 714c204fe5SShiri Kuzin */ 724c204fe5SShiri Kuzin RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG) 734c204fe5SShiri Kuzin { 744c204fe5SShiri Kuzin #ifdef RTE_ARCH_X86_64 754c204fe5SShiri Kuzin unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56}; 764c204fe5SShiri Kuzin unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46}; 774c204fe5SShiri Kuzin unsigned int i, model, family, brand_id, vendor; 784c204fe5SShiri Kuzin unsigned int signature_intel_ebx = 0x756e6547; 794c204fe5SShiri Kuzin unsigned int extended_model; 804c204fe5SShiri Kuzin unsigned int eax = 0; 814c204fe5SShiri Kuzin unsigned int ebx = 0; 824c204fe5SShiri Kuzin unsigned int ecx = 0; 834c204fe5SShiri Kuzin unsigned int edx = 0; 844c204fe5SShiri Kuzin int max_level; 854c204fe5SShiri Kuzin 864c204fe5SShiri Kuzin mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx); 874c204fe5SShiri Kuzin vendor = ebx; 884c204fe5SShiri Kuzin max_level = eax; 894c204fe5SShiri Kuzin if (max_level < 1) { 904c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 914c204fe5SShiri Kuzin return; 924c204fe5SShiri Kuzin } 934c204fe5SShiri Kuzin mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx); 944c204fe5SShiri Kuzin model = (eax >> 4) & 0x0f; 954c204fe5SShiri Kuzin family = (eax >> 8) & 0x0f; 964c204fe5SShiri Kuzin brand_id = ebx & 0xff; 974c204fe5SShiri Kuzin extended_model = (eax >> 12) & 0xf0; 984c204fe5SShiri Kuzin /* Check if the processor is Haswell or Broadwell */ 994c204fe5SShiri Kuzin if (vendor == signature_intel_ebx) { 1004c204fe5SShiri Kuzin if (family == 0x06) 1014c204fe5SShiri Kuzin model += extended_model; 1024c204fe5SShiri Kuzin if (brand_id == 0 && family == 0x6) { 1034c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(broadwell_models); i++) 1044c204fe5SShiri Kuzin if (model == broadwell_models[i]) { 1054c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 1064c204fe5SShiri Kuzin return; 1074c204fe5SShiri Kuzin } 1084c204fe5SShiri Kuzin for (i = 0; i < RTE_DIM(haswell_models); i++) 1094c204fe5SShiri Kuzin if (model == haswell_models[i]) { 1104c204fe5SShiri Kuzin haswell_broadwell_cpu = 1; 1114c204fe5SShiri Kuzin return; 1124c204fe5SShiri Kuzin } 1134c204fe5SShiri Kuzin } 1144c204fe5SShiri Kuzin } 1154c204fe5SShiri Kuzin #endif 1164c204fe5SShiri Kuzin haswell_broadwell_cpu = 0; 1174c204fe5SShiri Kuzin } 118262c7ad0SOri Kam 119262c7ad0SOri Kam /** 1209cc0e99cSViacheslav Ovsiienko * Allocate the User Access Region with DevX on specified device. 1219cc0e99cSViacheslav Ovsiienko * 1229cc0e99cSViacheslav Ovsiienko * @param [in] ctx 1239cc0e99cSViacheslav Ovsiienko * Infiniband device context to perform allocation on. 1249cc0e99cSViacheslav Ovsiienko * @param [in] mapping 1259cc0e99cSViacheslav Ovsiienko * MLX5DV_UAR_ALLOC_TYPE_BF - allocate as cached memory with write-combining 1269cc0e99cSViacheslav Ovsiienko * attributes (if supported by the host), the 1279cc0e99cSViacheslav Ovsiienko * writes to the UAR registers must be followed 1289cc0e99cSViacheslav Ovsiienko * by write memory barrier. 1299cc0e99cSViacheslav Ovsiienko * MLX5DV_UAR_ALLOC_TYPE_NC - allocate as non-cached nenory, all writes are 1309cc0e99cSViacheslav Ovsiienko * promoted to the registers immediately, no 1319cc0e99cSViacheslav Ovsiienko * memory barriers needed. 1329cc0e99cSViacheslav Ovsiienko * mapping < 0 - the first attempt is performed with MLX5DV_UAR_ALLOC_TYPE_BF, 1339cc0e99cSViacheslav Ovsiienko * if this fails the next attempt with MLX5DV_UAR_ALLOC_TYPE_NC 1349cc0e99cSViacheslav Ovsiienko * is performed. The drivers specifying negative values should 1359cc0e99cSViacheslav Ovsiienko * always provide the write memory barrier operation after UAR 1369cc0e99cSViacheslav Ovsiienko * register writings. 1379cc0e99cSViacheslav Ovsiienko * If there is no definitions for the MLX5DV_UAR_ALLOC_TYPE_xx (older rdma 1389cc0e99cSViacheslav Ovsiienko * library headers), the caller can specify 0. 1399cc0e99cSViacheslav Ovsiienko * 1409cc0e99cSViacheslav Ovsiienko * @return 1419cc0e99cSViacheslav Ovsiienko * UAR object pointer on success, NULL otherwise and rte_errno is set. 1429cc0e99cSViacheslav Ovsiienko */ 1439cc0e99cSViacheslav Ovsiienko void * 1449cc0e99cSViacheslav Ovsiienko mlx5_devx_alloc_uar(void *ctx, int mapping) 1459cc0e99cSViacheslav Ovsiienko { 1469cc0e99cSViacheslav Ovsiienko void *uar; 1479cc0e99cSViacheslav Ovsiienko uint32_t retry, uar_mapping; 1489cc0e99cSViacheslav Ovsiienko void *base_addr; 1499cc0e99cSViacheslav Ovsiienko 1509cc0e99cSViacheslav Ovsiienko for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) { 1519cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1529cc0e99cSViacheslav Ovsiienko /* Control the mapping type according to the settings. */ 1539cc0e99cSViacheslav Ovsiienko uar_mapping = (mapping < 0) ? 1549cc0e99cSViacheslav Ovsiienko MLX5DV_UAR_ALLOC_TYPE_NC : mapping; 1559cc0e99cSViacheslav Ovsiienko #else 1569cc0e99cSViacheslav Ovsiienko /* 1579cc0e99cSViacheslav Ovsiienko * It seems we have no way to control the memory mapping type 1589cc0e99cSViacheslav Ovsiienko * for the UAR, the default "Write-Combining" type is supposed. 1599cc0e99cSViacheslav Ovsiienko */ 1609cc0e99cSViacheslav Ovsiienko uar_mapping = 0; 1619cc0e99cSViacheslav Ovsiienko RTE_SET_USED(mapping); 1629cc0e99cSViacheslav Ovsiienko #endif 1639cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 1649cc0e99cSViacheslav Ovsiienko #ifdef MLX5DV_UAR_ALLOC_TYPE_NC 1659cc0e99cSViacheslav Ovsiienko if (!uar && 1669cc0e99cSViacheslav Ovsiienko mapping < 0 && 1679cc0e99cSViacheslav Ovsiienko uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) { 1689cc0e99cSViacheslav Ovsiienko /* 1699cc0e99cSViacheslav Ovsiienko * In some environments like virtual machine the 1709cc0e99cSViacheslav Ovsiienko * Write Combining mapped might be not supported and 1719cc0e99cSViacheslav Ovsiienko * UAR allocation fails. We tried "Non-Cached" mapping 1729cc0e99cSViacheslav Ovsiienko * for the case. 1739cc0e99cSViacheslav Ovsiienko */ 1749cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Failed to allocate DevX UAR (BF)"); 1759cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC; 1769cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 1779cc0e99cSViacheslav Ovsiienko } else if (!uar && 1789cc0e99cSViacheslav Ovsiienko mapping < 0 && 1799cc0e99cSViacheslav Ovsiienko uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) { 1809cc0e99cSViacheslav Ovsiienko /* 1819cc0e99cSViacheslav Ovsiienko * If Verbs/kernel does not support "Non-Cached" 1829cc0e99cSViacheslav Ovsiienko * try the "Write-Combining". 1839cc0e99cSViacheslav Ovsiienko */ 1849cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Failed to allocate DevX UAR (NC)"); 1859cc0e99cSViacheslav Ovsiienko uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF; 1869cc0e99cSViacheslav Ovsiienko uar = mlx5_glue->devx_alloc_uar(ctx, uar_mapping); 1879cc0e99cSViacheslav Ovsiienko } 1889cc0e99cSViacheslav Ovsiienko #endif 1899cc0e99cSViacheslav Ovsiienko if (!uar) { 1909cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)"); 1919cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 1929cc0e99cSViacheslav Ovsiienko goto exit; 1939cc0e99cSViacheslav Ovsiienko } 1949cc0e99cSViacheslav Ovsiienko base_addr = mlx5_os_get_devx_uar_base_addr(uar); 1959cc0e99cSViacheslav Ovsiienko if (base_addr) 1969cc0e99cSViacheslav Ovsiienko break; 1979cc0e99cSViacheslav Ovsiienko /* 1989cc0e99cSViacheslav Ovsiienko * The UARs are allocated by rdma_core within the 1999cc0e99cSViacheslav Ovsiienko * IB device context, on context closure all UARs 2009cc0e99cSViacheslav Ovsiienko * will be freed, should be no memory/object leakage. 2019cc0e99cSViacheslav Ovsiienko */ 2029cc0e99cSViacheslav Ovsiienko DRV_LOG(WARNING, "Retrying to allocate DevX UAR"); 2039cc0e99cSViacheslav Ovsiienko uar = NULL; 2049cc0e99cSViacheslav Ovsiienko } 2059cc0e99cSViacheslav Ovsiienko /* Check whether we finally succeeded with valid UAR allocation. */ 2069cc0e99cSViacheslav Ovsiienko if (!uar) { 2079cc0e99cSViacheslav Ovsiienko DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)"); 2089cc0e99cSViacheslav Ovsiienko rte_errno = ENOMEM; 2099cc0e99cSViacheslav Ovsiienko } 2109cc0e99cSViacheslav Ovsiienko /* 2119cc0e99cSViacheslav Ovsiienko * Return void * instead of struct mlx5dv_devx_uar * 2129cc0e99cSViacheslav Ovsiienko * is for compatibility with older rdma-core library headers. 2139cc0e99cSViacheslav Ovsiienko */ 2149cc0e99cSViacheslav Ovsiienko exit: 2159cc0e99cSViacheslav Ovsiienko return uar; 2169cc0e99cSViacheslav Ovsiienko } 217