199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2019 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson #include <stdint.h> 699a2dd95SBruce Richardson #include <stddef.h> 799a2dd95SBruce Richardson #include <stdio.h> 899a2dd95SBruce Richardson #include <string.h> 999a2dd95SBruce Richardson #include <sys/queue.h> 1099a2dd95SBruce Richardson 1199a2dd95SBruce Richardson #include <rte_errno.h> 1299a2dd95SBruce Richardson #include <rte_memcpy.h> 1399a2dd95SBruce Richardson #include <rte_memory.h> 1499a2dd95SBruce Richardson #include <rte_eal.h> 1599a2dd95SBruce Richardson #include <rte_eal_memconfig.h> 1699a2dd95SBruce Richardson #include <rte_branch_prediction.h> 1799a2dd95SBruce Richardson #include <rte_debug.h> 1899a2dd95SBruce Richardson #include <rte_launch.h> 1999a2dd95SBruce Richardson #include <rte_per_lcore.h> 2099a2dd95SBruce Richardson #include <rte_lcore.h> 2199a2dd95SBruce Richardson #include <rte_common.h> 2299a2dd95SBruce Richardson #include <rte_spinlock.h> 2399a2dd95SBruce Richardson 2499a2dd95SBruce Richardson #include <rte_eal_trace.h> 2599a2dd95SBruce Richardson 2699a2dd95SBruce Richardson #include <rte_malloc.h> 2799a2dd95SBruce Richardson #include "malloc_elem.h" 2899a2dd95SBruce Richardson #include "malloc_heap.h" 2999a2dd95SBruce Richardson #include "eal_memalloc.h" 3099a2dd95SBruce Richardson #include "eal_memcfg.h" 3199a2dd95SBruce Richardson #include "eal_private.h" 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson 3499a2dd95SBruce Richardson /* Free the memory space back to heap */ 3599a2dd95SBruce Richardson static void 3699a2dd95SBruce Richardson mem_free(void *addr, const bool trace_ena) 3799a2dd95SBruce Richardson { 3899a2dd95SBruce Richardson if (trace_ena) 3999a2dd95SBruce Richardson rte_eal_trace_mem_free(addr); 4099a2dd95SBruce Richardson 4199a2dd95SBruce Richardson if (addr == NULL) return; 4299a2dd95SBruce Richardson if (malloc_heap_free(malloc_elem_from_data(addr)) < 0) 4399a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Error: Invalid memory\n"); 4499a2dd95SBruce Richardson } 4599a2dd95SBruce Richardson 4699a2dd95SBruce Richardson void 4799a2dd95SBruce Richardson rte_free(void *addr) 4899a2dd95SBruce Richardson { 4999a2dd95SBruce Richardson return mem_free(addr, true); 5099a2dd95SBruce Richardson } 5199a2dd95SBruce Richardson 5299a2dd95SBruce Richardson void 5399a2dd95SBruce Richardson eal_free_no_trace(void *addr) 5499a2dd95SBruce Richardson { 5599a2dd95SBruce Richardson return mem_free(addr, false); 5699a2dd95SBruce Richardson } 5799a2dd95SBruce Richardson 5899a2dd95SBruce Richardson static void * 5999a2dd95SBruce Richardson malloc_socket(const char *type, size_t size, unsigned int align, 6099a2dd95SBruce Richardson int socket_arg, const bool trace_ena) 6199a2dd95SBruce Richardson { 6299a2dd95SBruce Richardson void *ptr; 6399a2dd95SBruce Richardson 6499a2dd95SBruce Richardson /* return NULL if size is 0 or alignment is not power-of-2 */ 6599a2dd95SBruce Richardson if (size == 0 || (align && !rte_is_power_of_2(align))) 6699a2dd95SBruce Richardson return NULL; 6799a2dd95SBruce Richardson 6899a2dd95SBruce Richardson /* if there are no hugepages and if we are not allocating from an 6999a2dd95SBruce Richardson * external heap, use memory from any socket available. checking for 7099a2dd95SBruce Richardson * socket being external may return -1 in case of invalid socket, but 7199a2dd95SBruce Richardson * that's OK - if there are no hugepages, it doesn't matter. 7299a2dd95SBruce Richardson */ 7399a2dd95SBruce Richardson if (rte_malloc_heap_socket_is_external(socket_arg) != 1 && 7499a2dd95SBruce Richardson !rte_eal_has_hugepages()) 7599a2dd95SBruce Richardson socket_arg = SOCKET_ID_ANY; 7699a2dd95SBruce Richardson 7799a2dd95SBruce Richardson ptr = malloc_heap_alloc(type, size, socket_arg, 0, 7899a2dd95SBruce Richardson align == 0 ? 1 : align, 0, false); 7999a2dd95SBruce Richardson 8099a2dd95SBruce Richardson if (trace_ena) 8199a2dd95SBruce Richardson rte_eal_trace_mem_malloc(type, size, align, socket_arg, ptr); 8299a2dd95SBruce Richardson return ptr; 8399a2dd95SBruce Richardson } 8499a2dd95SBruce Richardson 8599a2dd95SBruce Richardson /* 8699a2dd95SBruce Richardson * Allocate memory on specified heap. 8799a2dd95SBruce Richardson */ 8899a2dd95SBruce Richardson void * 8999a2dd95SBruce Richardson rte_malloc_socket(const char *type, size_t size, unsigned int align, 9099a2dd95SBruce Richardson int socket_arg) 9199a2dd95SBruce Richardson { 9299a2dd95SBruce Richardson return malloc_socket(type, size, align, socket_arg, true); 9399a2dd95SBruce Richardson } 9499a2dd95SBruce Richardson 9599a2dd95SBruce Richardson void * 9699a2dd95SBruce Richardson eal_malloc_no_trace(const char *type, size_t size, unsigned int align) 9799a2dd95SBruce Richardson { 9899a2dd95SBruce Richardson return malloc_socket(type, size, align, SOCKET_ID_ANY, false); 9999a2dd95SBruce Richardson } 10099a2dd95SBruce Richardson 10199a2dd95SBruce Richardson /* 10299a2dd95SBruce Richardson * Allocate memory on default heap. 10399a2dd95SBruce Richardson */ 10499a2dd95SBruce Richardson void * 10599a2dd95SBruce Richardson rte_malloc(const char *type, size_t size, unsigned align) 10699a2dd95SBruce Richardson { 10799a2dd95SBruce Richardson return rte_malloc_socket(type, size, align, SOCKET_ID_ANY); 10899a2dd95SBruce Richardson } 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson /* 11199a2dd95SBruce Richardson * Allocate zero'd memory on specified heap. 11299a2dd95SBruce Richardson */ 11399a2dd95SBruce Richardson void * 11499a2dd95SBruce Richardson rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket) 11599a2dd95SBruce Richardson { 11699a2dd95SBruce Richardson void *ptr = rte_malloc_socket(type, size, align, socket); 11799a2dd95SBruce Richardson 11899a2dd95SBruce Richardson #ifdef RTE_MALLOC_DEBUG 11999a2dd95SBruce Richardson /* 12099a2dd95SBruce Richardson * If DEBUG is enabled, then freed memory is marked with poison 12199a2dd95SBruce Richardson * value and set to zero on allocation. 12299a2dd95SBruce Richardson * If DEBUG is not enabled then memory is already zeroed. 12399a2dd95SBruce Richardson */ 12499a2dd95SBruce Richardson if (ptr != NULL) 12599a2dd95SBruce Richardson memset(ptr, 0, size); 12699a2dd95SBruce Richardson #endif 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson rte_eal_trace_mem_zmalloc(type, size, align, socket, ptr); 12999a2dd95SBruce Richardson return ptr; 13099a2dd95SBruce Richardson } 13199a2dd95SBruce Richardson 13299a2dd95SBruce Richardson /* 13399a2dd95SBruce Richardson * Allocate zero'd memory on default heap. 13499a2dd95SBruce Richardson */ 13599a2dd95SBruce Richardson void * 13699a2dd95SBruce Richardson rte_zmalloc(const char *type, size_t size, unsigned align) 13799a2dd95SBruce Richardson { 13899a2dd95SBruce Richardson return rte_zmalloc_socket(type, size, align, SOCKET_ID_ANY); 13999a2dd95SBruce Richardson } 14099a2dd95SBruce Richardson 14199a2dd95SBruce Richardson /* 14299a2dd95SBruce Richardson * Allocate zero'd memory on specified heap. 14399a2dd95SBruce Richardson */ 14499a2dd95SBruce Richardson void * 14599a2dd95SBruce Richardson rte_calloc_socket(const char *type, size_t num, size_t size, unsigned align, int socket) 14699a2dd95SBruce Richardson { 14799a2dd95SBruce Richardson return rte_zmalloc_socket(type, num * size, align, socket); 14899a2dd95SBruce Richardson } 14999a2dd95SBruce Richardson 15099a2dd95SBruce Richardson /* 15199a2dd95SBruce Richardson * Allocate zero'd memory on default heap. 15299a2dd95SBruce Richardson */ 15399a2dd95SBruce Richardson void * 15499a2dd95SBruce Richardson rte_calloc(const char *type, size_t num, size_t size, unsigned align) 15599a2dd95SBruce Richardson { 15699a2dd95SBruce Richardson return rte_zmalloc(type, num * size, align); 15799a2dd95SBruce Richardson } 15899a2dd95SBruce Richardson 15999a2dd95SBruce Richardson /* 16099a2dd95SBruce Richardson * Resize allocated memory on specified heap. 16199a2dd95SBruce Richardson */ 16299a2dd95SBruce Richardson void * 16399a2dd95SBruce Richardson rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket) 16499a2dd95SBruce Richardson { 165*6cc51b12SZhihong Peng size_t user_size; 166*6cc51b12SZhihong Peng 16799a2dd95SBruce Richardson if (ptr == NULL) 16899a2dd95SBruce Richardson return rte_malloc_socket(NULL, size, align, socket); 16999a2dd95SBruce Richardson 17099a2dd95SBruce Richardson struct malloc_elem *elem = malloc_elem_from_data(ptr); 17199a2dd95SBruce Richardson if (elem == NULL) { 17299a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Error: memory corruption detected\n"); 17399a2dd95SBruce Richardson return NULL; 17499a2dd95SBruce Richardson } 17599a2dd95SBruce Richardson 176*6cc51b12SZhihong Peng user_size = size; 177*6cc51b12SZhihong Peng 17899a2dd95SBruce Richardson size = RTE_CACHE_LINE_ROUNDUP(size), align = RTE_CACHE_LINE_ROUNDUP(align); 17999a2dd95SBruce Richardson 18099a2dd95SBruce Richardson /* check requested socket id and alignment matches first, and if ok, 18199a2dd95SBruce Richardson * see if we can resize block 18299a2dd95SBruce Richardson */ 18399a2dd95SBruce Richardson if ((socket == SOCKET_ID_ANY || 18499a2dd95SBruce Richardson (unsigned int)socket == elem->heap->socket_id) && 18599a2dd95SBruce Richardson RTE_PTR_ALIGN(ptr, align) == ptr && 18699a2dd95SBruce Richardson malloc_heap_resize(elem, size) == 0) { 18799a2dd95SBruce Richardson rte_eal_trace_mem_realloc(size, align, socket, ptr); 188*6cc51b12SZhihong Peng 189*6cc51b12SZhihong Peng asan_set_redzone(elem, user_size); 190*6cc51b12SZhihong Peng 19199a2dd95SBruce Richardson return ptr; 19299a2dd95SBruce Richardson } 19399a2dd95SBruce Richardson 19499a2dd95SBruce Richardson /* either requested socket id doesn't match, alignment is off 19599a2dd95SBruce Richardson * or we have no room to expand, 19699a2dd95SBruce Richardson * so move the data. 19799a2dd95SBruce Richardson */ 19899a2dd95SBruce Richardson void *new_ptr = rte_malloc_socket(NULL, size, align, socket); 19999a2dd95SBruce Richardson if (new_ptr == NULL) 20099a2dd95SBruce Richardson return NULL; 20199a2dd95SBruce Richardson /* elem: |pad|data_elem|data|trailer| */ 202*6cc51b12SZhihong Peng const size_t old_size = old_malloc_size(elem); 20399a2dd95SBruce Richardson rte_memcpy(new_ptr, ptr, old_size < size ? old_size : size); 20499a2dd95SBruce Richardson rte_free(ptr); 20599a2dd95SBruce Richardson 20699a2dd95SBruce Richardson rte_eal_trace_mem_realloc(size, align, socket, new_ptr); 20799a2dd95SBruce Richardson return new_ptr; 20899a2dd95SBruce Richardson } 20999a2dd95SBruce Richardson 21099a2dd95SBruce Richardson /* 21199a2dd95SBruce Richardson * Resize allocated memory. 21299a2dd95SBruce Richardson */ 21399a2dd95SBruce Richardson void * 21499a2dd95SBruce Richardson rte_realloc(void *ptr, size_t size, unsigned int align) 21599a2dd95SBruce Richardson { 21699a2dd95SBruce Richardson return rte_realloc_socket(ptr, size, align, SOCKET_ID_ANY); 21799a2dd95SBruce Richardson } 21899a2dd95SBruce Richardson 21999a2dd95SBruce Richardson int 22099a2dd95SBruce Richardson rte_malloc_validate(const void *ptr, size_t *size) 22199a2dd95SBruce Richardson { 22299a2dd95SBruce Richardson const struct malloc_elem *elem = malloc_elem_from_data(ptr); 22399a2dd95SBruce Richardson if (!malloc_elem_cookies_ok(elem)) 22499a2dd95SBruce Richardson return -1; 22599a2dd95SBruce Richardson if (size != NULL) 22699a2dd95SBruce Richardson *size = elem->size - elem->pad - MALLOC_ELEM_OVERHEAD; 22799a2dd95SBruce Richardson return 0; 22899a2dd95SBruce Richardson } 22999a2dd95SBruce Richardson 23099a2dd95SBruce Richardson /* 23199a2dd95SBruce Richardson * Function to retrieve data for heap on given socket 23299a2dd95SBruce Richardson */ 23399a2dd95SBruce Richardson int 23499a2dd95SBruce Richardson rte_malloc_get_socket_stats(int socket, 23599a2dd95SBruce Richardson struct rte_malloc_socket_stats *socket_stats) 23699a2dd95SBruce Richardson { 23799a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 23899a2dd95SBruce Richardson int heap_idx; 23999a2dd95SBruce Richardson 24099a2dd95SBruce Richardson heap_idx = malloc_socket_to_heap_id(socket); 24199a2dd95SBruce Richardson if (heap_idx < 0) 24299a2dd95SBruce Richardson return -1; 24399a2dd95SBruce Richardson 24499a2dd95SBruce Richardson return malloc_heap_get_stats(&mcfg->malloc_heaps[heap_idx], 24599a2dd95SBruce Richardson socket_stats); 24699a2dd95SBruce Richardson } 24799a2dd95SBruce Richardson 24899a2dd95SBruce Richardson /* 24999a2dd95SBruce Richardson * Function to dump contents of all heaps 25099a2dd95SBruce Richardson */ 25199a2dd95SBruce Richardson void 25299a2dd95SBruce Richardson rte_malloc_dump_heaps(FILE *f) 25399a2dd95SBruce Richardson { 25499a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 25599a2dd95SBruce Richardson unsigned int idx; 25699a2dd95SBruce Richardson 25799a2dd95SBruce Richardson for (idx = 0; idx < RTE_MAX_HEAPS; idx++) { 25899a2dd95SBruce Richardson fprintf(f, "Heap id: %u\n", idx); 25999a2dd95SBruce Richardson malloc_heap_dump(&mcfg->malloc_heaps[idx], f); 26099a2dd95SBruce Richardson } 26199a2dd95SBruce Richardson } 26299a2dd95SBruce Richardson 26399a2dd95SBruce Richardson int 26499a2dd95SBruce Richardson rte_malloc_heap_get_socket(const char *name) 26599a2dd95SBruce Richardson { 26699a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 26799a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 26899a2dd95SBruce Richardson unsigned int idx; 26999a2dd95SBruce Richardson int ret; 27099a2dd95SBruce Richardson 27199a2dd95SBruce Richardson if (name == NULL || 27299a2dd95SBruce Richardson strnlen(name, RTE_HEAP_NAME_MAX_LEN) == 0 || 27399a2dd95SBruce Richardson strnlen(name, RTE_HEAP_NAME_MAX_LEN) == 27499a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 27599a2dd95SBruce Richardson rte_errno = EINVAL; 27699a2dd95SBruce Richardson return -1; 27799a2dd95SBruce Richardson } 27899a2dd95SBruce Richardson rte_mcfg_mem_read_lock(); 27999a2dd95SBruce Richardson for (idx = 0; idx < RTE_MAX_HEAPS; idx++) { 28099a2dd95SBruce Richardson struct malloc_heap *tmp = &mcfg->malloc_heaps[idx]; 28199a2dd95SBruce Richardson 28299a2dd95SBruce Richardson if (!strncmp(name, tmp->name, RTE_HEAP_NAME_MAX_LEN)) { 28399a2dd95SBruce Richardson heap = tmp; 28499a2dd95SBruce Richardson break; 28599a2dd95SBruce Richardson } 28699a2dd95SBruce Richardson } 28799a2dd95SBruce Richardson 28899a2dd95SBruce Richardson if (heap != NULL) { 28999a2dd95SBruce Richardson ret = heap->socket_id; 29099a2dd95SBruce Richardson } else { 29199a2dd95SBruce Richardson rte_errno = ENOENT; 29299a2dd95SBruce Richardson ret = -1; 29399a2dd95SBruce Richardson } 29499a2dd95SBruce Richardson rte_mcfg_mem_read_unlock(); 29599a2dd95SBruce Richardson 29699a2dd95SBruce Richardson return ret; 29799a2dd95SBruce Richardson } 29899a2dd95SBruce Richardson 29999a2dd95SBruce Richardson int 30099a2dd95SBruce Richardson rte_malloc_heap_socket_is_external(int socket_id) 30199a2dd95SBruce Richardson { 30299a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 30399a2dd95SBruce Richardson unsigned int idx; 30499a2dd95SBruce Richardson int ret = -1; 30599a2dd95SBruce Richardson 30699a2dd95SBruce Richardson if (socket_id == SOCKET_ID_ANY) 30799a2dd95SBruce Richardson return 0; 30899a2dd95SBruce Richardson 30999a2dd95SBruce Richardson rte_mcfg_mem_read_lock(); 31099a2dd95SBruce Richardson for (idx = 0; idx < RTE_MAX_HEAPS; idx++) { 31199a2dd95SBruce Richardson struct malloc_heap *tmp = &mcfg->malloc_heaps[idx]; 31299a2dd95SBruce Richardson 31399a2dd95SBruce Richardson if ((int)tmp->socket_id == socket_id) { 31499a2dd95SBruce Richardson /* external memory always has large socket ID's */ 31599a2dd95SBruce Richardson ret = tmp->socket_id >= RTE_MAX_NUMA_NODES; 31699a2dd95SBruce Richardson break; 31799a2dd95SBruce Richardson } 31899a2dd95SBruce Richardson } 31999a2dd95SBruce Richardson rte_mcfg_mem_read_unlock(); 32099a2dd95SBruce Richardson 32199a2dd95SBruce Richardson return ret; 32299a2dd95SBruce Richardson } 32399a2dd95SBruce Richardson 32499a2dd95SBruce Richardson /* 32599a2dd95SBruce Richardson * Print stats on memory type. If type is NULL, info on all types is printed 32699a2dd95SBruce Richardson */ 32799a2dd95SBruce Richardson void 32899a2dd95SBruce Richardson rte_malloc_dump_stats(FILE *f, __rte_unused const char *type) 32999a2dd95SBruce Richardson { 33099a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 33199a2dd95SBruce Richardson unsigned int heap_id; 33299a2dd95SBruce Richardson struct rte_malloc_socket_stats sock_stats; 33399a2dd95SBruce Richardson 33499a2dd95SBruce Richardson /* Iterate through all initialised heaps */ 33599a2dd95SBruce Richardson for (heap_id = 0; heap_id < RTE_MAX_HEAPS; heap_id++) { 33699a2dd95SBruce Richardson struct malloc_heap *heap = &mcfg->malloc_heaps[heap_id]; 33799a2dd95SBruce Richardson 33899a2dd95SBruce Richardson malloc_heap_get_stats(heap, &sock_stats); 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson fprintf(f, "Heap id:%u\n", heap_id); 34199a2dd95SBruce Richardson fprintf(f, "\tHeap name:%s\n", heap->name); 34299a2dd95SBruce Richardson fprintf(f, "\tHeap_size:%zu,\n", sock_stats.heap_totalsz_bytes); 34399a2dd95SBruce Richardson fprintf(f, "\tFree_size:%zu,\n", sock_stats.heap_freesz_bytes); 34499a2dd95SBruce Richardson fprintf(f, "\tAlloc_size:%zu,\n", sock_stats.heap_allocsz_bytes); 34599a2dd95SBruce Richardson fprintf(f, "\tGreatest_free_size:%zu,\n", 34699a2dd95SBruce Richardson sock_stats.greatest_free_size); 34799a2dd95SBruce Richardson fprintf(f, "\tAlloc_count:%u,\n",sock_stats.alloc_count); 34899a2dd95SBruce Richardson fprintf(f, "\tFree_count:%u,\n", sock_stats.free_count); 34999a2dd95SBruce Richardson } 35099a2dd95SBruce Richardson return; 35199a2dd95SBruce Richardson } 35299a2dd95SBruce Richardson 35399a2dd95SBruce Richardson /* 35499a2dd95SBruce Richardson * TODO: Set limit to memory that can be allocated to memory type 35599a2dd95SBruce Richardson */ 35699a2dd95SBruce Richardson int 35799a2dd95SBruce Richardson rte_malloc_set_limit(__rte_unused const char *type, 35899a2dd95SBruce Richardson __rte_unused size_t max) 35999a2dd95SBruce Richardson { 36099a2dd95SBruce Richardson return 0; 36199a2dd95SBruce Richardson } 36299a2dd95SBruce Richardson 36399a2dd95SBruce Richardson /* 36499a2dd95SBruce Richardson * Return the IO address of a virtual address obtained through rte_malloc 36599a2dd95SBruce Richardson */ 36699a2dd95SBruce Richardson rte_iova_t 36799a2dd95SBruce Richardson rte_malloc_virt2iova(const void *addr) 36899a2dd95SBruce Richardson { 36999a2dd95SBruce Richardson const struct rte_memseg *ms; 37099a2dd95SBruce Richardson struct malloc_elem *elem = malloc_elem_from_data(addr); 37199a2dd95SBruce Richardson 37299a2dd95SBruce Richardson if (elem == NULL) 37399a2dd95SBruce Richardson return RTE_BAD_IOVA; 37499a2dd95SBruce Richardson 37599a2dd95SBruce Richardson if (!elem->msl->external && rte_eal_iova_mode() == RTE_IOVA_VA) 37699a2dd95SBruce Richardson return (uintptr_t) addr; 37799a2dd95SBruce Richardson 37899a2dd95SBruce Richardson ms = rte_mem_virt2memseg(addr, elem->msl); 37999a2dd95SBruce Richardson if (ms == NULL) 38099a2dd95SBruce Richardson return RTE_BAD_IOVA; 38199a2dd95SBruce Richardson 38299a2dd95SBruce Richardson if (ms->iova == RTE_BAD_IOVA) 38399a2dd95SBruce Richardson return RTE_BAD_IOVA; 38499a2dd95SBruce Richardson 38599a2dd95SBruce Richardson return ms->iova + RTE_PTR_DIFF(addr, ms->addr); 38699a2dd95SBruce Richardson } 38799a2dd95SBruce Richardson 38899a2dd95SBruce Richardson static struct malloc_heap * 38999a2dd95SBruce Richardson find_named_heap(const char *name) 39099a2dd95SBruce Richardson { 39199a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 39299a2dd95SBruce Richardson unsigned int i; 39399a2dd95SBruce Richardson 39499a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_HEAPS; i++) { 39599a2dd95SBruce Richardson struct malloc_heap *heap = &mcfg->malloc_heaps[i]; 39699a2dd95SBruce Richardson 39799a2dd95SBruce Richardson if (!strncmp(name, heap->name, RTE_HEAP_NAME_MAX_LEN)) 39899a2dd95SBruce Richardson return heap; 39999a2dd95SBruce Richardson } 40099a2dd95SBruce Richardson return NULL; 40199a2dd95SBruce Richardson } 40299a2dd95SBruce Richardson 40399a2dd95SBruce Richardson int 40499a2dd95SBruce Richardson rte_malloc_heap_memory_add(const char *heap_name, void *va_addr, size_t len, 40599a2dd95SBruce Richardson rte_iova_t iova_addrs[], unsigned int n_pages, size_t page_sz) 40699a2dd95SBruce Richardson { 40799a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 40899a2dd95SBruce Richardson struct rte_memseg_list *msl; 40999a2dd95SBruce Richardson unsigned int n; 41099a2dd95SBruce Richardson int ret; 41199a2dd95SBruce Richardson 41299a2dd95SBruce Richardson if (heap_name == NULL || va_addr == NULL || 41399a2dd95SBruce Richardson page_sz == 0 || !rte_is_power_of_2(page_sz) || 41499a2dd95SBruce Richardson RTE_ALIGN(len, page_sz) != len || 41599a2dd95SBruce Richardson !rte_is_aligned(va_addr, page_sz) || 41699a2dd95SBruce Richardson ((len / page_sz) != n_pages && iova_addrs != NULL) || 41799a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || 41899a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 41999a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 42099a2dd95SBruce Richardson rte_errno = EINVAL; 42199a2dd95SBruce Richardson return -1; 42299a2dd95SBruce Richardson } 42399a2dd95SBruce Richardson rte_mcfg_mem_write_lock(); 42499a2dd95SBruce Richardson 42599a2dd95SBruce Richardson /* find our heap */ 42699a2dd95SBruce Richardson heap = find_named_heap(heap_name); 42799a2dd95SBruce Richardson if (heap == NULL) { 42899a2dd95SBruce Richardson rte_errno = ENOENT; 42999a2dd95SBruce Richardson ret = -1; 43099a2dd95SBruce Richardson goto unlock; 43199a2dd95SBruce Richardson } 43299a2dd95SBruce Richardson if (heap->socket_id < RTE_MAX_NUMA_NODES) { 43399a2dd95SBruce Richardson /* cannot add memory to internal heaps */ 43499a2dd95SBruce Richardson rte_errno = EPERM; 43599a2dd95SBruce Richardson ret = -1; 43699a2dd95SBruce Richardson goto unlock; 43799a2dd95SBruce Richardson } 43899a2dd95SBruce Richardson n = len / page_sz; 43999a2dd95SBruce Richardson 44099a2dd95SBruce Richardson msl = malloc_heap_create_external_seg(va_addr, iova_addrs, n, page_sz, 44199a2dd95SBruce Richardson heap_name, heap->socket_id); 44299a2dd95SBruce Richardson if (msl == NULL) { 44399a2dd95SBruce Richardson ret = -1; 44499a2dd95SBruce Richardson goto unlock; 44599a2dd95SBruce Richardson } 44699a2dd95SBruce Richardson 44799a2dd95SBruce Richardson rte_spinlock_lock(&heap->lock); 44899a2dd95SBruce Richardson ret = malloc_heap_add_external_memory(heap, msl); 44999a2dd95SBruce Richardson msl->heap = 1; /* mark it as heap segment */ 45099a2dd95SBruce Richardson rte_spinlock_unlock(&heap->lock); 45199a2dd95SBruce Richardson 45299a2dd95SBruce Richardson unlock: 45399a2dd95SBruce Richardson rte_mcfg_mem_write_unlock(); 45499a2dd95SBruce Richardson 45599a2dd95SBruce Richardson return ret; 45699a2dd95SBruce Richardson } 45799a2dd95SBruce Richardson 45899a2dd95SBruce Richardson int 45999a2dd95SBruce Richardson rte_malloc_heap_memory_remove(const char *heap_name, void *va_addr, size_t len) 46099a2dd95SBruce Richardson { 46199a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 46299a2dd95SBruce Richardson struct rte_memseg_list *msl; 46399a2dd95SBruce Richardson int ret; 46499a2dd95SBruce Richardson 46599a2dd95SBruce Richardson if (heap_name == NULL || va_addr == NULL || len == 0 || 46699a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || 46799a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 46899a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 46999a2dd95SBruce Richardson rte_errno = EINVAL; 47099a2dd95SBruce Richardson return -1; 47199a2dd95SBruce Richardson } 47299a2dd95SBruce Richardson rte_mcfg_mem_write_lock(); 47399a2dd95SBruce Richardson /* find our heap */ 47499a2dd95SBruce Richardson heap = find_named_heap(heap_name); 47599a2dd95SBruce Richardson if (heap == NULL) { 47699a2dd95SBruce Richardson rte_errno = ENOENT; 47799a2dd95SBruce Richardson ret = -1; 47899a2dd95SBruce Richardson goto unlock; 47999a2dd95SBruce Richardson } 48099a2dd95SBruce Richardson if (heap->socket_id < RTE_MAX_NUMA_NODES) { 48199a2dd95SBruce Richardson /* cannot remove memory from internal heaps */ 48299a2dd95SBruce Richardson rte_errno = EPERM; 48399a2dd95SBruce Richardson ret = -1; 48499a2dd95SBruce Richardson goto unlock; 48599a2dd95SBruce Richardson } 48699a2dd95SBruce Richardson 48799a2dd95SBruce Richardson msl = malloc_heap_find_external_seg(va_addr, len); 48899a2dd95SBruce Richardson if (msl == NULL) { 48999a2dd95SBruce Richardson ret = -1; 49099a2dd95SBruce Richardson goto unlock; 49199a2dd95SBruce Richardson } 49299a2dd95SBruce Richardson 49399a2dd95SBruce Richardson rte_spinlock_lock(&heap->lock); 49499a2dd95SBruce Richardson ret = malloc_heap_remove_external_memory(heap, va_addr, len); 49599a2dd95SBruce Richardson rte_spinlock_unlock(&heap->lock); 49699a2dd95SBruce Richardson if (ret != 0) 49799a2dd95SBruce Richardson goto unlock; 49899a2dd95SBruce Richardson 49999a2dd95SBruce Richardson ret = malloc_heap_destroy_external_seg(msl); 50099a2dd95SBruce Richardson 50199a2dd95SBruce Richardson unlock: 50299a2dd95SBruce Richardson rte_mcfg_mem_write_unlock(); 50399a2dd95SBruce Richardson 50499a2dd95SBruce Richardson return ret; 50599a2dd95SBruce Richardson } 50699a2dd95SBruce Richardson 50799a2dd95SBruce Richardson static int 50899a2dd95SBruce Richardson sync_memory(const char *heap_name, void *va_addr, size_t len, bool attach) 50999a2dd95SBruce Richardson { 51099a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 51199a2dd95SBruce Richardson struct rte_memseg_list *msl; 51299a2dd95SBruce Richardson int ret; 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson if (heap_name == NULL || va_addr == NULL || len == 0 || 51599a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || 51699a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 51799a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 51899a2dd95SBruce Richardson rte_errno = EINVAL; 51999a2dd95SBruce Richardson return -1; 52099a2dd95SBruce Richardson } 52199a2dd95SBruce Richardson rte_mcfg_mem_read_lock(); 52299a2dd95SBruce Richardson 52399a2dd95SBruce Richardson /* find our heap */ 52499a2dd95SBruce Richardson heap = find_named_heap(heap_name); 52599a2dd95SBruce Richardson if (heap == NULL) { 52699a2dd95SBruce Richardson rte_errno = ENOENT; 52799a2dd95SBruce Richardson ret = -1; 52899a2dd95SBruce Richardson goto unlock; 52999a2dd95SBruce Richardson } 53099a2dd95SBruce Richardson /* we shouldn't be able to sync to internal heaps */ 53199a2dd95SBruce Richardson if (heap->socket_id < RTE_MAX_NUMA_NODES) { 53299a2dd95SBruce Richardson rte_errno = EPERM; 53399a2dd95SBruce Richardson ret = -1; 53499a2dd95SBruce Richardson goto unlock; 53599a2dd95SBruce Richardson } 53699a2dd95SBruce Richardson 53799a2dd95SBruce Richardson /* find corresponding memseg list to sync to */ 53899a2dd95SBruce Richardson msl = malloc_heap_find_external_seg(va_addr, len); 53999a2dd95SBruce Richardson if (msl == NULL) { 54099a2dd95SBruce Richardson ret = -1; 54199a2dd95SBruce Richardson goto unlock; 54299a2dd95SBruce Richardson } 54399a2dd95SBruce Richardson 54499a2dd95SBruce Richardson if (attach) { 54599a2dd95SBruce Richardson ret = rte_fbarray_attach(&msl->memseg_arr); 54699a2dd95SBruce Richardson if (ret == 0) { 54799a2dd95SBruce Richardson /* notify all subscribers that a new memory area was 54899a2dd95SBruce Richardson * added. 54999a2dd95SBruce Richardson */ 55099a2dd95SBruce Richardson eal_memalloc_mem_event_notify(RTE_MEM_EVENT_ALLOC, 55199a2dd95SBruce Richardson va_addr, len); 55299a2dd95SBruce Richardson } else { 55399a2dd95SBruce Richardson ret = -1; 55499a2dd95SBruce Richardson goto unlock; 55599a2dd95SBruce Richardson } 55699a2dd95SBruce Richardson } else { 55799a2dd95SBruce Richardson /* notify all subscribers that a memory area is about to 55899a2dd95SBruce Richardson * be removed. 55999a2dd95SBruce Richardson */ 56099a2dd95SBruce Richardson eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, 56199a2dd95SBruce Richardson msl->base_va, msl->len); 56299a2dd95SBruce Richardson ret = rte_fbarray_detach(&msl->memseg_arr); 56399a2dd95SBruce Richardson if (ret < 0) { 56499a2dd95SBruce Richardson ret = -1; 56599a2dd95SBruce Richardson goto unlock; 56699a2dd95SBruce Richardson } 56799a2dd95SBruce Richardson } 56899a2dd95SBruce Richardson unlock: 56999a2dd95SBruce Richardson rte_mcfg_mem_read_unlock(); 57099a2dd95SBruce Richardson return ret; 57199a2dd95SBruce Richardson } 57299a2dd95SBruce Richardson 57399a2dd95SBruce Richardson int 57499a2dd95SBruce Richardson rte_malloc_heap_memory_attach(const char *heap_name, void *va_addr, size_t len) 57599a2dd95SBruce Richardson { 57699a2dd95SBruce Richardson return sync_memory(heap_name, va_addr, len, true); 57799a2dd95SBruce Richardson } 57899a2dd95SBruce Richardson 57999a2dd95SBruce Richardson int 58099a2dd95SBruce Richardson rte_malloc_heap_memory_detach(const char *heap_name, void *va_addr, size_t len) 58199a2dd95SBruce Richardson { 58299a2dd95SBruce Richardson return sync_memory(heap_name, va_addr, len, false); 58399a2dd95SBruce Richardson } 58499a2dd95SBruce Richardson 58599a2dd95SBruce Richardson int 58699a2dd95SBruce Richardson rte_malloc_heap_create(const char *heap_name) 58799a2dd95SBruce Richardson { 58899a2dd95SBruce Richardson struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 58999a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 59099a2dd95SBruce Richardson int i, ret; 59199a2dd95SBruce Richardson 59299a2dd95SBruce Richardson if (heap_name == NULL || 59399a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || 59499a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 59599a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 59699a2dd95SBruce Richardson rte_errno = EINVAL; 59799a2dd95SBruce Richardson return -1; 59899a2dd95SBruce Richardson } 59999a2dd95SBruce Richardson /* check if there is space in the heap list, or if heap with this name 60099a2dd95SBruce Richardson * already exists. 60199a2dd95SBruce Richardson */ 60299a2dd95SBruce Richardson rte_mcfg_mem_write_lock(); 60399a2dd95SBruce Richardson 60499a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_HEAPS; i++) { 60599a2dd95SBruce Richardson struct malloc_heap *tmp = &mcfg->malloc_heaps[i]; 60699a2dd95SBruce Richardson /* existing heap */ 60799a2dd95SBruce Richardson if (strncmp(heap_name, tmp->name, 60899a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) == 0) { 60999a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Heap %s already exists\n", 61099a2dd95SBruce Richardson heap_name); 61199a2dd95SBruce Richardson rte_errno = EEXIST; 61299a2dd95SBruce Richardson ret = -1; 61399a2dd95SBruce Richardson goto unlock; 61499a2dd95SBruce Richardson } 61599a2dd95SBruce Richardson /* empty heap */ 61699a2dd95SBruce Richardson if (strnlen(tmp->name, RTE_HEAP_NAME_MAX_LEN) == 0) { 61799a2dd95SBruce Richardson heap = tmp; 61899a2dd95SBruce Richardson break; 61999a2dd95SBruce Richardson } 62099a2dd95SBruce Richardson } 62199a2dd95SBruce Richardson if (heap == NULL) { 62299a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Cannot create new heap: no space\n"); 62399a2dd95SBruce Richardson rte_errno = ENOSPC; 62499a2dd95SBruce Richardson ret = -1; 62599a2dd95SBruce Richardson goto unlock; 62699a2dd95SBruce Richardson } 62799a2dd95SBruce Richardson 62899a2dd95SBruce Richardson /* we're sure that we can create a new heap, so do it */ 62999a2dd95SBruce Richardson ret = malloc_heap_create(heap, heap_name); 63099a2dd95SBruce Richardson unlock: 63199a2dd95SBruce Richardson rte_mcfg_mem_write_unlock(); 63299a2dd95SBruce Richardson 63399a2dd95SBruce Richardson return ret; 63499a2dd95SBruce Richardson } 63599a2dd95SBruce Richardson 63699a2dd95SBruce Richardson int 63799a2dd95SBruce Richardson rte_malloc_heap_destroy(const char *heap_name) 63899a2dd95SBruce Richardson { 63999a2dd95SBruce Richardson struct malloc_heap *heap = NULL; 64099a2dd95SBruce Richardson int ret; 64199a2dd95SBruce Richardson 64299a2dd95SBruce Richardson if (heap_name == NULL || 64399a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 || 64499a2dd95SBruce Richardson strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 64599a2dd95SBruce Richardson RTE_HEAP_NAME_MAX_LEN) { 64699a2dd95SBruce Richardson rte_errno = EINVAL; 64799a2dd95SBruce Richardson return -1; 64899a2dd95SBruce Richardson } 64999a2dd95SBruce Richardson rte_mcfg_mem_write_lock(); 65099a2dd95SBruce Richardson 65199a2dd95SBruce Richardson /* start from non-socket heaps */ 65299a2dd95SBruce Richardson heap = find_named_heap(heap_name); 65399a2dd95SBruce Richardson if (heap == NULL) { 65499a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Heap %s not found\n", heap_name); 65599a2dd95SBruce Richardson rte_errno = ENOENT; 65699a2dd95SBruce Richardson ret = -1; 65799a2dd95SBruce Richardson goto unlock; 65899a2dd95SBruce Richardson } 65999a2dd95SBruce Richardson /* we shouldn't be able to destroy internal heaps */ 66099a2dd95SBruce Richardson if (heap->socket_id < RTE_MAX_NUMA_NODES) { 66199a2dd95SBruce Richardson rte_errno = EPERM; 66299a2dd95SBruce Richardson ret = -1; 66399a2dd95SBruce Richardson goto unlock; 66499a2dd95SBruce Richardson } 66599a2dd95SBruce Richardson /* sanity checks done, now we can destroy the heap */ 66699a2dd95SBruce Richardson rte_spinlock_lock(&heap->lock); 66799a2dd95SBruce Richardson ret = malloc_heap_destroy(heap); 66899a2dd95SBruce Richardson 66999a2dd95SBruce Richardson /* if we failed, lock is still active */ 67099a2dd95SBruce Richardson if (ret < 0) 67199a2dd95SBruce Richardson rte_spinlock_unlock(&heap->lock); 67299a2dd95SBruce Richardson unlock: 67399a2dd95SBruce Richardson rte_mcfg_mem_write_unlock(); 67499a2dd95SBruce Richardson 67599a2dd95SBruce Richardson return ret; 67699a2dd95SBruce Richardson } 677