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