1*d38e3d52SSuanming Mou /* SPDX-License-Identifier: BSD-3-Clause 2*d38e3d52SSuanming Mou * Copyright 2020 Mellanox Technologies, Ltd 3*d38e3d52SSuanming Mou */ 4*d38e3d52SSuanming Mou 5*d38e3d52SSuanming Mou #include <errno.h> 6*d38e3d52SSuanming Mou #include <rte_malloc.h> 7*d38e3d52SSuanming Mou #include <malloc.h> 8*d38e3d52SSuanming Mou #include <stdbool.h> 9*d38e3d52SSuanming Mou #include <string.h> 10*d38e3d52SSuanming Mou 11*d38e3d52SSuanming Mou #include <rte_atomic.h> 12*d38e3d52SSuanming Mou 13*d38e3d52SSuanming Mou #include "mlx5_common_utils.h" 14*d38e3d52SSuanming Mou #include "mlx5_malloc.h" 15*d38e3d52SSuanming Mou 16*d38e3d52SSuanming Mou struct mlx5_sys_mem { 17*d38e3d52SSuanming Mou uint32_t init:1; /* Memory allocator initialized. */ 18*d38e3d52SSuanming Mou uint32_t enable:1; /* System memory select. */ 19*d38e3d52SSuanming Mou uint32_t reserve:30; /* Reserve. */ 20*d38e3d52SSuanming Mou union { 21*d38e3d52SSuanming Mou struct rte_memseg_list *last_msl; 22*d38e3d52SSuanming Mou rte_atomic64_t a64_last_msl; 23*d38e3d52SSuanming Mou }; 24*d38e3d52SSuanming Mou /* last allocated rte memory memseg list. */ 25*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 26*d38e3d52SSuanming Mou rte_atomic64_t malloc_sys; 27*d38e3d52SSuanming Mou /* Memory allocated from system count. */ 28*d38e3d52SSuanming Mou rte_atomic64_t malloc_rte; 29*d38e3d52SSuanming Mou /* Memory allocated from hugepage count. */ 30*d38e3d52SSuanming Mou rte_atomic64_t realloc_sys; 31*d38e3d52SSuanming Mou /* Memory reallocate from system count. */ 32*d38e3d52SSuanming Mou rte_atomic64_t realloc_rte; 33*d38e3d52SSuanming Mou /* Memory reallocate from hugepage count. */ 34*d38e3d52SSuanming Mou rte_atomic64_t free_sys; 35*d38e3d52SSuanming Mou /* Memory free to system count. */ 36*d38e3d52SSuanming Mou rte_atomic64_t free_rte; 37*d38e3d52SSuanming Mou /* Memory free to hugepage count. */ 38*d38e3d52SSuanming Mou rte_atomic64_t msl_miss; 39*d38e3d52SSuanming Mou /* MSL miss count. */ 40*d38e3d52SSuanming Mou rte_atomic64_t msl_update; 41*d38e3d52SSuanming Mou /* MSL update count. */ 42*d38e3d52SSuanming Mou #endif 43*d38e3d52SSuanming Mou }; 44*d38e3d52SSuanming Mou 45*d38e3d52SSuanming Mou /* Initialize default as not */ 46*d38e3d52SSuanming Mou static struct mlx5_sys_mem mlx5_sys_mem = { 47*d38e3d52SSuanming Mou .init = 0, 48*d38e3d52SSuanming Mou .enable = 0, 49*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 50*d38e3d52SSuanming Mou .malloc_sys = RTE_ATOMIC64_INIT(0), 51*d38e3d52SSuanming Mou .malloc_rte = RTE_ATOMIC64_INIT(0), 52*d38e3d52SSuanming Mou .realloc_sys = RTE_ATOMIC64_INIT(0), 53*d38e3d52SSuanming Mou .realloc_rte = RTE_ATOMIC64_INIT(0), 54*d38e3d52SSuanming Mou .free_sys = RTE_ATOMIC64_INIT(0), 55*d38e3d52SSuanming Mou .free_rte = RTE_ATOMIC64_INIT(0), 56*d38e3d52SSuanming Mou .msl_miss = RTE_ATOMIC64_INIT(0), 57*d38e3d52SSuanming Mou .msl_update = RTE_ATOMIC64_INIT(0), 58*d38e3d52SSuanming Mou #endif 59*d38e3d52SSuanming Mou }; 60*d38e3d52SSuanming Mou 61*d38e3d52SSuanming Mou /** 62*d38e3d52SSuanming Mou * Check if the address belongs to memory seg list. 63*d38e3d52SSuanming Mou * 64*d38e3d52SSuanming Mou * @param addr 65*d38e3d52SSuanming Mou * Memory address to be ckeced. 66*d38e3d52SSuanming Mou * @param msl 67*d38e3d52SSuanming Mou * Memory seg list. 68*d38e3d52SSuanming Mou * 69*d38e3d52SSuanming Mou * @return 70*d38e3d52SSuanming Mou * True if it belongs, false otherwise. 71*d38e3d52SSuanming Mou */ 72*d38e3d52SSuanming Mou static bool 73*d38e3d52SSuanming Mou mlx5_mem_check_msl(void *addr, struct rte_memseg_list *msl) 74*d38e3d52SSuanming Mou { 75*d38e3d52SSuanming Mou void *start, *end; 76*d38e3d52SSuanming Mou 77*d38e3d52SSuanming Mou if (!msl) 78*d38e3d52SSuanming Mou return false; 79*d38e3d52SSuanming Mou start = msl->base_va; 80*d38e3d52SSuanming Mou end = RTE_PTR_ADD(start, msl->len); 81*d38e3d52SSuanming Mou if (addr >= start && addr < end) 82*d38e3d52SSuanming Mou return true; 83*d38e3d52SSuanming Mou return false; 84*d38e3d52SSuanming Mou } 85*d38e3d52SSuanming Mou 86*d38e3d52SSuanming Mou /** 87*d38e3d52SSuanming Mou * Update the msl if memory belongs to new msl. 88*d38e3d52SSuanming Mou * 89*d38e3d52SSuanming Mou * @param addr 90*d38e3d52SSuanming Mou * Memory address. 91*d38e3d52SSuanming Mou */ 92*d38e3d52SSuanming Mou static void 93*d38e3d52SSuanming Mou mlx5_mem_update_msl(void *addr) 94*d38e3d52SSuanming Mou { 95*d38e3d52SSuanming Mou /* 96*d38e3d52SSuanming Mou * Update the cache msl if the new addr comes from the new msl 97*d38e3d52SSuanming Mou * different with the cached msl. 98*d38e3d52SSuanming Mou */ 99*d38e3d52SSuanming Mou if (addr && !mlx5_mem_check_msl(addr, 100*d38e3d52SSuanming Mou (struct rte_memseg_list *)(uintptr_t)rte_atomic64_read 101*d38e3d52SSuanming Mou (&mlx5_sys_mem.a64_last_msl))) { 102*d38e3d52SSuanming Mou rte_atomic64_set(&mlx5_sys_mem.a64_last_msl, 103*d38e3d52SSuanming Mou (int64_t)(uintptr_t)rte_mem_virt2memseg_list(addr)); 104*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 105*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.msl_update); 106*d38e3d52SSuanming Mou #endif 107*d38e3d52SSuanming Mou } 108*d38e3d52SSuanming Mou } 109*d38e3d52SSuanming Mou 110*d38e3d52SSuanming Mou /** 111*d38e3d52SSuanming Mou * Check if the address belongs to rte memory. 112*d38e3d52SSuanming Mou * 113*d38e3d52SSuanming Mou * @param addr 114*d38e3d52SSuanming Mou * Memory address to be ckeced. 115*d38e3d52SSuanming Mou * 116*d38e3d52SSuanming Mou * @return 117*d38e3d52SSuanming Mou * True if it belongs, false otherwise. 118*d38e3d52SSuanming Mou */ 119*d38e3d52SSuanming Mou static bool 120*d38e3d52SSuanming Mou mlx5_mem_is_rte(void *addr) 121*d38e3d52SSuanming Mou { 122*d38e3d52SSuanming Mou /* 123*d38e3d52SSuanming Mou * Check if the last cache msl matches. Drop to slow path 124*d38e3d52SSuanming Mou * to check if the memory belongs to rte memory. 125*d38e3d52SSuanming Mou */ 126*d38e3d52SSuanming Mou if (!mlx5_mem_check_msl(addr, (struct rte_memseg_list *)(uintptr_t) 127*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.a64_last_msl))) { 128*d38e3d52SSuanming Mou if (!rte_mem_virt2memseg_list(addr)) 129*d38e3d52SSuanming Mou return false; 130*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 131*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.msl_miss); 132*d38e3d52SSuanming Mou #endif 133*d38e3d52SSuanming Mou } 134*d38e3d52SSuanming Mou return true; 135*d38e3d52SSuanming Mou } 136*d38e3d52SSuanming Mou 137*d38e3d52SSuanming Mou /** 138*d38e3d52SSuanming Mou * Allocate memory with alignment. 139*d38e3d52SSuanming Mou * 140*d38e3d52SSuanming Mou * @param size 141*d38e3d52SSuanming Mou * Memory size to be allocated. 142*d38e3d52SSuanming Mou * @param align 143*d38e3d52SSuanming Mou * Memory alignment. 144*d38e3d52SSuanming Mou * @param zero 145*d38e3d52SSuanming Mou * Clear the allocated memory or not. 146*d38e3d52SSuanming Mou * 147*d38e3d52SSuanming Mou * @return 148*d38e3d52SSuanming Mou * Pointer of the allocated memory, NULL otherwise. 149*d38e3d52SSuanming Mou */ 150*d38e3d52SSuanming Mou static void * 151*d38e3d52SSuanming Mou mlx5_alloc_align(size_t size, unsigned int align, unsigned int zero) 152*d38e3d52SSuanming Mou { 153*d38e3d52SSuanming Mou void *buf; 154*d38e3d52SSuanming Mou buf = memalign(align, size); 155*d38e3d52SSuanming Mou if (!buf) { 156*d38e3d52SSuanming Mou DRV_LOG(ERR, "Couldn't allocate buf.\n"); 157*d38e3d52SSuanming Mou return NULL; 158*d38e3d52SSuanming Mou } 159*d38e3d52SSuanming Mou if (zero) 160*d38e3d52SSuanming Mou memset(buf, 0, size); 161*d38e3d52SSuanming Mou return buf; 162*d38e3d52SSuanming Mou } 163*d38e3d52SSuanming Mou 164*d38e3d52SSuanming Mou void * 165*d38e3d52SSuanming Mou mlx5_malloc(uint32_t flags, size_t size, unsigned int align, int socket) 166*d38e3d52SSuanming Mou { 167*d38e3d52SSuanming Mou void *addr; 168*d38e3d52SSuanming Mou bool rte_mem; 169*d38e3d52SSuanming Mou 170*d38e3d52SSuanming Mou /* 171*d38e3d52SSuanming Mou * If neither system memory nor rte memory is required, allocate 172*d38e3d52SSuanming Mou * memory according to mlx5_sys_mem.enable. 173*d38e3d52SSuanming Mou */ 174*d38e3d52SSuanming Mou if (flags & MLX5_MEM_RTE) 175*d38e3d52SSuanming Mou rte_mem = true; 176*d38e3d52SSuanming Mou else if (flags & MLX5_MEM_SYS) 177*d38e3d52SSuanming Mou rte_mem = false; 178*d38e3d52SSuanming Mou else 179*d38e3d52SSuanming Mou rte_mem = mlx5_sys_mem.enable ? false : true; 180*d38e3d52SSuanming Mou if (rte_mem) { 181*d38e3d52SSuanming Mou if (flags & MLX5_MEM_ZERO) 182*d38e3d52SSuanming Mou addr = rte_zmalloc_socket(NULL, size, align, socket); 183*d38e3d52SSuanming Mou else 184*d38e3d52SSuanming Mou addr = rte_malloc_socket(NULL, size, align, socket); 185*d38e3d52SSuanming Mou mlx5_mem_update_msl(addr); 186*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 187*d38e3d52SSuanming Mou if (addr) 188*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.malloc_rte); 189*d38e3d52SSuanming Mou #endif 190*d38e3d52SSuanming Mou return addr; 191*d38e3d52SSuanming Mou } 192*d38e3d52SSuanming Mou /* The memory will be allocated from system. */ 193*d38e3d52SSuanming Mou if (align) 194*d38e3d52SSuanming Mou addr = mlx5_alloc_align(size, align, !!(flags & MLX5_MEM_ZERO)); 195*d38e3d52SSuanming Mou else if (flags & MLX5_MEM_ZERO) 196*d38e3d52SSuanming Mou addr = calloc(1, size); 197*d38e3d52SSuanming Mou else 198*d38e3d52SSuanming Mou addr = malloc(size); 199*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 200*d38e3d52SSuanming Mou if (addr) 201*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.malloc_sys); 202*d38e3d52SSuanming Mou #endif 203*d38e3d52SSuanming Mou return addr; 204*d38e3d52SSuanming Mou } 205*d38e3d52SSuanming Mou 206*d38e3d52SSuanming Mou void * 207*d38e3d52SSuanming Mou mlx5_realloc(void *addr, uint32_t flags, size_t size, unsigned int align, 208*d38e3d52SSuanming Mou int socket) 209*d38e3d52SSuanming Mou { 210*d38e3d52SSuanming Mou void *new_addr; 211*d38e3d52SSuanming Mou bool rte_mem; 212*d38e3d52SSuanming Mou 213*d38e3d52SSuanming Mou /* Allocate directly if old memory address is NULL. */ 214*d38e3d52SSuanming Mou if (!addr) 215*d38e3d52SSuanming Mou return mlx5_malloc(flags, size, align, socket); 216*d38e3d52SSuanming Mou /* Get the memory type. */ 217*d38e3d52SSuanming Mou if (flags & MLX5_MEM_RTE) 218*d38e3d52SSuanming Mou rte_mem = true; 219*d38e3d52SSuanming Mou else if (flags & MLX5_MEM_SYS) 220*d38e3d52SSuanming Mou rte_mem = false; 221*d38e3d52SSuanming Mou else 222*d38e3d52SSuanming Mou rte_mem = mlx5_sys_mem.enable ? false : true; 223*d38e3d52SSuanming Mou /* Check if old memory and to be allocated memory are the same type. */ 224*d38e3d52SSuanming Mou if (rte_mem != mlx5_mem_is_rte(addr)) { 225*d38e3d52SSuanming Mou DRV_LOG(ERR, "Couldn't reallocate to different memory type."); 226*d38e3d52SSuanming Mou return NULL; 227*d38e3d52SSuanming Mou } 228*d38e3d52SSuanming Mou /* Allocate memory from rte memory. */ 229*d38e3d52SSuanming Mou if (rte_mem) { 230*d38e3d52SSuanming Mou new_addr = rte_realloc_socket(addr, size, align, socket); 231*d38e3d52SSuanming Mou mlx5_mem_update_msl(new_addr); 232*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 233*d38e3d52SSuanming Mou if (new_addr) 234*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.realloc_rte); 235*d38e3d52SSuanming Mou #endif 236*d38e3d52SSuanming Mou return new_addr; 237*d38e3d52SSuanming Mou } 238*d38e3d52SSuanming Mou /* Align is not supported for system memory. */ 239*d38e3d52SSuanming Mou if (align) { 240*d38e3d52SSuanming Mou DRV_LOG(ERR, "Couldn't reallocate with alignment"); 241*d38e3d52SSuanming Mou return NULL; 242*d38e3d52SSuanming Mou } 243*d38e3d52SSuanming Mou new_addr = realloc(addr, size); 244*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 245*d38e3d52SSuanming Mou if (new_addr) 246*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.realloc_sys); 247*d38e3d52SSuanming Mou #endif 248*d38e3d52SSuanming Mou return new_addr; 249*d38e3d52SSuanming Mou } 250*d38e3d52SSuanming Mou 251*d38e3d52SSuanming Mou void 252*d38e3d52SSuanming Mou mlx5_free(void *addr) 253*d38e3d52SSuanming Mou { 254*d38e3d52SSuanming Mou if (addr == NULL) 255*d38e3d52SSuanming Mou return; 256*d38e3d52SSuanming Mou if (!mlx5_mem_is_rte(addr)) { 257*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 258*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.free_sys); 259*d38e3d52SSuanming Mou #endif 260*d38e3d52SSuanming Mou free(addr); 261*d38e3d52SSuanming Mou } else { 262*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 263*d38e3d52SSuanming Mou rte_atomic64_inc(&mlx5_sys_mem.free_rte); 264*d38e3d52SSuanming Mou #endif 265*d38e3d52SSuanming Mou rte_free(addr); 266*d38e3d52SSuanming Mou } 267*d38e3d52SSuanming Mou } 268*d38e3d52SSuanming Mou 269*d38e3d52SSuanming Mou void 270*d38e3d52SSuanming Mou mlx5_memory_stat_dump(void) 271*d38e3d52SSuanming Mou { 272*d38e3d52SSuanming Mou #ifdef RTE_LIBRTE_MLX5_DEBUG 273*d38e3d52SSuanming Mou DRV_LOG(INFO, "System memory malloc:%"PRIi64", realloc:%"PRIi64"," 274*d38e3d52SSuanming Mou " free:%"PRIi64"\nRTE memory malloc:%"PRIi64"," 275*d38e3d52SSuanming Mou " realloc:%"PRIi64", free:%"PRIi64"\nMSL miss:%"PRIi64"," 276*d38e3d52SSuanming Mou " update:%"PRIi64"", 277*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.malloc_sys), 278*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.realloc_sys), 279*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.free_sys), 280*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.malloc_rte), 281*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.realloc_rte), 282*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.free_rte), 283*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.msl_miss), 284*d38e3d52SSuanming Mou rte_atomic64_read(&mlx5_sys_mem.msl_update)); 285*d38e3d52SSuanming Mou #endif 286*d38e3d52SSuanming Mou } 287*d38e3d52SSuanming Mou 288*d38e3d52SSuanming Mou void 289*d38e3d52SSuanming Mou mlx5_malloc_mem_select(uint32_t sys_mem_en) 290*d38e3d52SSuanming Mou { 291*d38e3d52SSuanming Mou /* 292*d38e3d52SSuanming Mou * The initialization should be called only once and all devices 293*d38e3d52SSuanming Mou * should use the same memory type. Otherwise, when new device is 294*d38e3d52SSuanming Mou * being attached with some different memory allocation configuration, 295*d38e3d52SSuanming Mou * the memory will get wrong behavior or a failure will be raised. 296*d38e3d52SSuanming Mou */ 297*d38e3d52SSuanming Mou if (!mlx5_sys_mem.init) { 298*d38e3d52SSuanming Mou if (sys_mem_en) 299*d38e3d52SSuanming Mou mlx5_sys_mem.enable = 1; 300*d38e3d52SSuanming Mou mlx5_sys_mem.init = 1; 301*d38e3d52SSuanming Mou DRV_LOG(INFO, "%s is selected.", sys_mem_en ? "SYS_MEM" : "RTE_MEM"); 302*d38e3d52SSuanming Mou } else if (mlx5_sys_mem.enable != sys_mem_en) { 303*d38e3d52SSuanming Mou DRV_LOG(WARNING, "%s is already selected.", 304*d38e3d52SSuanming Mou mlx5_sys_mem.enable ? "SYS_MEM" : "RTE_MEM"); 305*d38e3d52SSuanming Mou } 306*d38e3d52SSuanming Mou } 307