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
mem_free(void * addr,const bool trace_ena)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)
38ae67895bSDavid Marchand EAL_LOG(ERR, "Error: Invalid memory");
3999a2dd95SBruce Richardson }
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson void
rte_free(void * addr)4299a2dd95SBruce Richardson rte_free(void *addr)
4399a2dd95SBruce Richardson {
44732ba1beSTyler Retzlaff mem_free(addr, true);
4599a2dd95SBruce Richardson }
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson void
eal_free_no_trace(void * addr)4899a2dd95SBruce Richardson eal_free_no_trace(void *addr)
4999a2dd95SBruce Richardson {
50732ba1beSTyler Retzlaff mem_free(addr, false);
5199a2dd95SBruce Richardson }
5299a2dd95SBruce Richardson
5399a2dd95SBruce Richardson static void *
malloc_socket(const char * type,size_t size,unsigned int align,int socket_arg,const bool trace_ena)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
72*62ea63a6SStephen Hemminger ptr = malloc_heap_alloc(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 *
rte_malloc_socket(const char * type,size_t size,unsigned int align,int socket_arg)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 *
eal_malloc_no_trace(const char * type,size_t size,unsigned int align)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 *
rte_malloc(const char * type,size_t size,unsigned align)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 *
rte_zmalloc_socket(const char * type,size_t size,unsigned align,int socket)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 *
rte_zmalloc(const char * type,size_t size,unsigned align)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 *
rte_calloc_socket(const char * type,size_t num,size_t size,unsigned align,int socket)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 *
rte_calloc(const char * type,size_t num,size_t size,unsigned align)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 *
rte_realloc_socket(void * ptr,size_t size,unsigned int align,int socket)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) {
174ae67895bSDavid Marchand EAL_LOG(ERR, "Error: memory corruption detected");
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 *
rte_realloc(void * ptr,size_t size,unsigned int align)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
rte_malloc_validate(const void * ptr,size_t * size)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
rte_malloc_get_socket_stats(int socket,struct rte_malloc_socket_stats * socket_stats)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
rte_malloc_dump_heaps(FILE * f)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
rte_malloc_heap_get_socket(const char * name)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
rte_malloc_heap_socket_is_external(int socket_id)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
rte_malloc_dump_stats(FILE * f,__rte_unused const char * type)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
rte_malloc_virt2iova(const void * addr)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 *
find_named_heap(const char * name)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
rte_malloc_heap_memory_add(const char * heap_name,void * va_addr,size_t len,rte_iova_t iova_addrs[],unsigned int n_pages,size_t page_sz)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
rte_malloc_heap_memory_remove(const char * heap_name,void * va_addr,size_t len)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
sync_memory(const char * heap_name,void * va_addr,size_t len,bool attach)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
rte_malloc_heap_memory_attach(const char * heap_name,void * va_addr,size_t len)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
rte_malloc_heap_memory_detach(const char * heap_name,void * va_addr,size_t len)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
rte_malloc_heap_create(const char * heap_name)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) {
601ae67895bSDavid Marchand EAL_LOG(ERR, "Heap %s already exists",
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) {
614ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot create new heap: no space");
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
rte_malloc_heap_destroy(const char * heap_name)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) {
646ae67895bSDavid Marchand EAL_LOG(ERR, "Heap %s not found", 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