xref: /dpdk/lib/eal/common/eal_common_memzone.c (revision 17bb60044bae68c0f062755527ad8febe9f448d1)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <stdint.h>
799a2dd95SBruce Richardson #include <inttypes.h>
899a2dd95SBruce Richardson #include <string.h>
999a2dd95SBruce Richardson #include <errno.h>
1099a2dd95SBruce Richardson 
1145a685caSAnkur Dwivedi #include <eal_trace_internal.h>
1299a2dd95SBruce Richardson #include <rte_log.h>
1399a2dd95SBruce Richardson #include <rte_memory.h>
1499a2dd95SBruce Richardson #include <rte_memzone.h>
1599a2dd95SBruce Richardson #include <rte_eal.h>
1699a2dd95SBruce Richardson #include <rte_errno.h>
1799a2dd95SBruce Richardson #include <rte_string_fns.h>
1899a2dd95SBruce Richardson #include <rte_common.h>
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson #include "malloc_heap.h"
2199a2dd95SBruce Richardson #include "malloc_elem.h"
2299a2dd95SBruce Richardson #include "eal_private.h"
2399a2dd95SBruce Richardson #include "eal_memcfg.h"
2499a2dd95SBruce Richardson 
2538689022SOphir Munk /* Default count used until rte_memzone_max_set() is called */
2638689022SOphir Munk #define DEFAULT_MAX_MEMZONE_COUNT 2560
2738689022SOphir Munk 
2838689022SOphir Munk int
2938689022SOphir Munk rte_memzone_max_set(size_t max)
3038689022SOphir Munk {
3138689022SOphir Munk 	struct rte_mem_config *mcfg;
3238689022SOphir Munk 
3338689022SOphir Munk 	if (eal_get_internal_configuration()->init_complete > 0) {
34ae67895bSDavid Marchand 		EAL_LOG(ERR, "Max memzone cannot be set after EAL init");
3538689022SOphir Munk 		return -1;
3638689022SOphir Munk 	}
3738689022SOphir Munk 
3838689022SOphir Munk 	mcfg = rte_eal_get_configuration()->mem_config;
3938689022SOphir Munk 	if (mcfg == NULL) {
40ae67895bSDavid Marchand 		EAL_LOG(ERR, "Failed to set max memzone count");
4138689022SOphir Munk 		return -1;
4238689022SOphir Munk 	}
4338689022SOphir Munk 
4438689022SOphir Munk 	mcfg->max_memzone = max;
4538689022SOphir Munk 
4638689022SOphir Munk 	return 0;
4738689022SOphir Munk }
4838689022SOphir Munk 
4938689022SOphir Munk size_t
5038689022SOphir Munk rte_memzone_max_get(void)
5138689022SOphir Munk {
5238689022SOphir Munk 	struct rte_mem_config *mcfg;
5338689022SOphir Munk 
5438689022SOphir Munk 	mcfg = rte_eal_get_configuration()->mem_config;
5538689022SOphir Munk 	if (mcfg == NULL || mcfg->max_memzone == 0)
5638689022SOphir Munk 		return DEFAULT_MAX_MEMZONE_COUNT;
5738689022SOphir Munk 
5838689022SOphir Munk 	return mcfg->max_memzone;
5938689022SOphir Munk }
6038689022SOphir Munk 
6199a2dd95SBruce Richardson static inline const struct rte_memzone *
6299a2dd95SBruce Richardson memzone_lookup_thread_unsafe(const char *name)
6399a2dd95SBruce Richardson {
6499a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
6599a2dd95SBruce Richardson 	struct rte_fbarray *arr;
6699a2dd95SBruce Richardson 	const struct rte_memzone *mz;
6799a2dd95SBruce Richardson 	int i = 0;
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	/* get pointer to global configuration */
7099a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
7199a2dd95SBruce Richardson 	arr = &mcfg->memzones;
7299a2dd95SBruce Richardson 
7399a2dd95SBruce Richardson 	/*
7499a2dd95SBruce Richardson 	 * the algorithm is not optimal (linear), but there are few
7599a2dd95SBruce Richardson 	 * zones and this function should be called at init only
7699a2dd95SBruce Richardson 	 */
7799a2dd95SBruce Richardson 	i = rte_fbarray_find_next_used(arr, 0);
7899a2dd95SBruce Richardson 	while (i >= 0) {
7999a2dd95SBruce Richardson 		mz = rte_fbarray_get(arr, i);
8099a2dd95SBruce Richardson 		if (mz->addr != NULL &&
8199a2dd95SBruce Richardson 				!strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
8299a2dd95SBruce Richardson 			return mz;
8399a2dd95SBruce Richardson 		i = rte_fbarray_find_next_used(arr, i + 1);
8499a2dd95SBruce Richardson 	}
8599a2dd95SBruce Richardson 	return NULL;
8699a2dd95SBruce Richardson }
8799a2dd95SBruce Richardson 
88bc1a35fbSDavid Marchand #define MEMZONE_KNOWN_FLAGS (RTE_MEMZONE_2MB \
89bc1a35fbSDavid Marchand 	| RTE_MEMZONE_1GB \
90bc1a35fbSDavid Marchand 	| RTE_MEMZONE_16MB \
91bc1a35fbSDavid Marchand 	| RTE_MEMZONE_16GB \
92bc1a35fbSDavid Marchand 	| RTE_MEMZONE_256KB \
93bc1a35fbSDavid Marchand 	| RTE_MEMZONE_256MB \
94bc1a35fbSDavid Marchand 	| RTE_MEMZONE_512MB \
95bc1a35fbSDavid Marchand 	| RTE_MEMZONE_4GB \
96bc1a35fbSDavid Marchand 	| RTE_MEMZONE_SIZE_HINT_ONLY \
97bc1a35fbSDavid Marchand 	| RTE_MEMZONE_IOVA_CONTIG \
98bc1a35fbSDavid Marchand 	)
99bc1a35fbSDavid Marchand 
10099a2dd95SBruce Richardson static const struct rte_memzone *
10199a2dd95SBruce Richardson memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
10299a2dd95SBruce Richardson 		int socket_id, unsigned int flags, unsigned int align,
10399a2dd95SBruce Richardson 		unsigned int bound)
10499a2dd95SBruce Richardson {
10599a2dd95SBruce Richardson 	struct rte_memzone *mz;
10699a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
10799a2dd95SBruce Richardson 	struct rte_fbarray *arr;
10899a2dd95SBruce Richardson 	void *mz_addr;
10999a2dd95SBruce Richardson 	size_t requested_len;
11099a2dd95SBruce Richardson 	int mz_idx;
11199a2dd95SBruce Richardson 	bool contig;
11299a2dd95SBruce Richardson 
11399a2dd95SBruce Richardson 	/* get pointer to global configuration */
11499a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
11599a2dd95SBruce Richardson 	arr = &mcfg->memzones;
11699a2dd95SBruce Richardson 
11799a2dd95SBruce Richardson 	/* no more room in config */
11899a2dd95SBruce Richardson 	if (arr->count >= arr->len) {
119ae67895bSDavid Marchand 		EAL_LOG(ERR,
12038689022SOphir Munk 		"%s(): Number of requested memzone segments exceeds maximum "
121ae67895bSDavid Marchand 		"%u", __func__, arr->len);
12238689022SOphir Munk 
12399a2dd95SBruce Richardson 		rte_errno = ENOSPC;
12499a2dd95SBruce Richardson 		return NULL;
12599a2dd95SBruce Richardson 	}
12699a2dd95SBruce Richardson 
12799a2dd95SBruce Richardson 	if (strlen(name) > sizeof(mz->name) - 1) {
128ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "%s(): memzone <%s>: name too long",
12999a2dd95SBruce Richardson 			__func__, name);
13099a2dd95SBruce Richardson 		rte_errno = ENAMETOOLONG;
13199a2dd95SBruce Richardson 		return NULL;
13299a2dd95SBruce Richardson 	}
13399a2dd95SBruce Richardson 
13499a2dd95SBruce Richardson 	/* zone already exist */
13599a2dd95SBruce Richardson 	if ((memzone_lookup_thread_unsafe(name)) != NULL) {
136ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "%s(): memzone <%s> already exists",
13799a2dd95SBruce Richardson 			__func__, name);
13899a2dd95SBruce Richardson 		rte_errno = EEXIST;
13999a2dd95SBruce Richardson 		return NULL;
14099a2dd95SBruce Richardson 	}
14199a2dd95SBruce Richardson 
14299a2dd95SBruce Richardson 	/* if alignment is not a power of two */
14399a2dd95SBruce Richardson 	if (align && !rte_is_power_of_2(align)) {
144ae67895bSDavid Marchand 		EAL_LOG(ERR, "%s(): Invalid alignment: %u", __func__,
14599a2dd95SBruce Richardson 				align);
14699a2dd95SBruce Richardson 		rte_errno = EINVAL;
14799a2dd95SBruce Richardson 		return NULL;
14899a2dd95SBruce Richardson 	}
14999a2dd95SBruce Richardson 
15099a2dd95SBruce Richardson 	/* alignment less than cache size is not allowed */
15199a2dd95SBruce Richardson 	if (align < RTE_CACHE_LINE_SIZE)
15299a2dd95SBruce Richardson 		align = RTE_CACHE_LINE_SIZE;
15399a2dd95SBruce Richardson 
15499a2dd95SBruce Richardson 	/* align length on cache boundary. Check for overflow before doing so */
15599a2dd95SBruce Richardson 	if (len > SIZE_MAX - RTE_CACHE_LINE_MASK) {
15699a2dd95SBruce Richardson 		rte_errno = EINVAL; /* requested size too big */
15799a2dd95SBruce Richardson 		return NULL;
15899a2dd95SBruce Richardson 	}
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 	len = RTE_ALIGN_CEIL(len, RTE_CACHE_LINE_SIZE);
16199a2dd95SBruce Richardson 
16299a2dd95SBruce Richardson 	/* save minimal requested  length */
16399a2dd95SBruce Richardson 	requested_len = RTE_MAX((size_t)RTE_CACHE_LINE_SIZE,  len);
16499a2dd95SBruce Richardson 
16599a2dd95SBruce Richardson 	/* check that boundary condition is valid */
16699a2dd95SBruce Richardson 	if (bound != 0 && (requested_len > bound || !rte_is_power_of_2(bound))) {
16799a2dd95SBruce Richardson 		rte_errno = EINVAL;
16899a2dd95SBruce Richardson 		return NULL;
16999a2dd95SBruce Richardson 	}
17099a2dd95SBruce Richardson 
17199a2dd95SBruce Richardson 	if ((socket_id != SOCKET_ID_ANY) && socket_id < 0) {
17299a2dd95SBruce Richardson 		rte_errno = EINVAL;
17399a2dd95SBruce Richardson 		return NULL;
17499a2dd95SBruce Richardson 	}
17599a2dd95SBruce Richardson 
176bc1a35fbSDavid Marchand 	if ((flags & ~MEMZONE_KNOWN_FLAGS) != 0) {
177bc1a35fbSDavid Marchand 		rte_errno = EINVAL;
178bc1a35fbSDavid Marchand 		return NULL;
179bc1a35fbSDavid Marchand 	}
180bc1a35fbSDavid Marchand 
18199a2dd95SBruce Richardson 	/* only set socket to SOCKET_ID_ANY if we aren't allocating for an
18299a2dd95SBruce Richardson 	 * external heap.
18399a2dd95SBruce Richardson 	 */
18499a2dd95SBruce Richardson 	if (!rte_eal_has_hugepages() && socket_id < RTE_MAX_NUMA_NODES)
18599a2dd95SBruce Richardson 		socket_id = SOCKET_ID_ANY;
18699a2dd95SBruce Richardson 
18799a2dd95SBruce Richardson 	contig = (flags & RTE_MEMZONE_IOVA_CONTIG) != 0;
18899a2dd95SBruce Richardson 	/* malloc only cares about size flags, remove contig flag from flags */
18999a2dd95SBruce Richardson 	flags &= ~RTE_MEMZONE_IOVA_CONTIG;
19099a2dd95SBruce Richardson 
19199a2dd95SBruce Richardson 	if (len == 0 && bound == 0) {
19299a2dd95SBruce Richardson 		/* no size constraints were placed, so use malloc elem len */
19399a2dd95SBruce Richardson 		requested_len = 0;
19462ea63a6SStephen Hemminger 		mz_addr = malloc_heap_alloc_biggest(socket_id, flags, align, contig);
19599a2dd95SBruce Richardson 	} else {
19699a2dd95SBruce Richardson 		if (len == 0)
19799a2dd95SBruce Richardson 			requested_len = bound;
19899a2dd95SBruce Richardson 		/* allocate memory on heap */
19962ea63a6SStephen Hemminger 		mz_addr = malloc_heap_alloc(requested_len, socket_id, flags, align, bound, contig);
20099a2dd95SBruce Richardson 	}
20199a2dd95SBruce Richardson 	if (mz_addr == NULL) {
20299a2dd95SBruce Richardson 		rte_errno = ENOMEM;
20399a2dd95SBruce Richardson 		return NULL;
20499a2dd95SBruce Richardson 	}
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson 	struct malloc_elem *elem = malloc_elem_from_data(mz_addr);
20799a2dd95SBruce Richardson 
20899a2dd95SBruce Richardson 	/* fill the zone in config */
20999a2dd95SBruce Richardson 	mz_idx = rte_fbarray_find_next_free(arr, 0);
21099a2dd95SBruce Richardson 
21199a2dd95SBruce Richardson 	if (mz_idx < 0) {
21299a2dd95SBruce Richardson 		mz = NULL;
21399a2dd95SBruce Richardson 	} else {
21499a2dd95SBruce Richardson 		rte_fbarray_set_used(arr, mz_idx);
21599a2dd95SBruce Richardson 		mz = rte_fbarray_get(arr, mz_idx);
21699a2dd95SBruce Richardson 	}
21799a2dd95SBruce Richardson 
21899a2dd95SBruce Richardson 	if (mz == NULL) {
219ae67895bSDavid Marchand 		EAL_LOG(ERR, "%s(): Cannot find free memzone", __func__);
22099a2dd95SBruce Richardson 		malloc_heap_free(elem);
22199a2dd95SBruce Richardson 		rte_errno = ENOSPC;
22299a2dd95SBruce Richardson 		return NULL;
22399a2dd95SBruce Richardson 	}
22499a2dd95SBruce Richardson 
22599a2dd95SBruce Richardson 	strlcpy(mz->name, name, sizeof(mz->name));
22699a2dd95SBruce Richardson 	mz->iova = rte_malloc_virt2iova(mz_addr);
22799a2dd95SBruce Richardson 	mz->addr = mz_addr;
22899a2dd95SBruce Richardson 	mz->len = requested_len == 0 ?
22999a2dd95SBruce Richardson 			elem->size - elem->pad - MALLOC_ELEM_OVERHEAD :
23099a2dd95SBruce Richardson 			requested_len;
23199a2dd95SBruce Richardson 	mz->hugepage_sz = elem->msl->page_sz;
23299a2dd95SBruce Richardson 	mz->socket_id = elem->msl->socket_id;
23399a2dd95SBruce Richardson 	mz->flags = 0;
23499a2dd95SBruce Richardson 
23599a2dd95SBruce Richardson 	return mz;
23699a2dd95SBruce Richardson }
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson static const struct rte_memzone *
23999a2dd95SBruce Richardson rte_memzone_reserve_thread_safe(const char *name, size_t len, int socket_id,
24099a2dd95SBruce Richardson 		unsigned int flags, unsigned int align, unsigned int bound)
24199a2dd95SBruce Richardson {
24299a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
24399a2dd95SBruce Richardson 	const struct rte_memzone *mz = NULL;
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 	/* get pointer to global configuration */
24699a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
24799a2dd95SBruce Richardson 
24899a2dd95SBruce Richardson 	rte_rwlock_write_lock(&mcfg->mlock);
24999a2dd95SBruce Richardson 
25099a2dd95SBruce Richardson 	mz = memzone_reserve_aligned_thread_unsafe(
25199a2dd95SBruce Richardson 		name, len, socket_id, flags, align, bound);
25299a2dd95SBruce Richardson 
25399a2dd95SBruce Richardson 	rte_eal_trace_memzone_reserve(name, len, socket_id, flags, align,
25499a2dd95SBruce Richardson 		bound, mz);
25599a2dd95SBruce Richardson 
25699a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&mcfg->mlock);
25799a2dd95SBruce Richardson 
25899a2dd95SBruce Richardson 	return mz;
25999a2dd95SBruce Richardson }
26099a2dd95SBruce Richardson 
26199a2dd95SBruce Richardson /*
26299a2dd95SBruce Richardson  * Return a pointer to a correctly filled memzone descriptor (with a
26399a2dd95SBruce Richardson  * specified alignment and boundary). If the allocation cannot be done,
26499a2dd95SBruce Richardson  * return NULL.
26599a2dd95SBruce Richardson  */
26699a2dd95SBruce Richardson const struct rte_memzone *
26799a2dd95SBruce Richardson rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id,
26899a2dd95SBruce Richardson 			    unsigned flags, unsigned align, unsigned bound)
26999a2dd95SBruce Richardson {
27099a2dd95SBruce Richardson 	return rte_memzone_reserve_thread_safe(name, len, socket_id, flags,
27199a2dd95SBruce Richardson 					       align, bound);
27299a2dd95SBruce Richardson }
27399a2dd95SBruce Richardson 
27499a2dd95SBruce Richardson /*
27599a2dd95SBruce Richardson  * Return a pointer to a correctly filled memzone descriptor (with a
27699a2dd95SBruce Richardson  * specified alignment). If the allocation cannot be done, return NULL.
27799a2dd95SBruce Richardson  */
27899a2dd95SBruce Richardson const struct rte_memzone *
27999a2dd95SBruce Richardson rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id,
28099a2dd95SBruce Richardson 			    unsigned flags, unsigned align)
28199a2dd95SBruce Richardson {
28299a2dd95SBruce Richardson 	return rte_memzone_reserve_thread_safe(name, len, socket_id, flags,
28399a2dd95SBruce Richardson 					       align, 0);
28499a2dd95SBruce Richardson }
28599a2dd95SBruce Richardson 
28699a2dd95SBruce Richardson /*
28799a2dd95SBruce Richardson  * Return a pointer to a correctly filled memzone descriptor. If the
28899a2dd95SBruce Richardson  * allocation cannot be done, return NULL.
28999a2dd95SBruce Richardson  */
29099a2dd95SBruce Richardson const struct rte_memzone *
29199a2dd95SBruce Richardson rte_memzone_reserve(const char *name, size_t len, int socket_id,
29299a2dd95SBruce Richardson 		    unsigned flags)
29399a2dd95SBruce Richardson {
29499a2dd95SBruce Richardson 	return rte_memzone_reserve_thread_safe(name, len, socket_id,
29599a2dd95SBruce Richardson 					       flags, RTE_CACHE_LINE_SIZE, 0);
29699a2dd95SBruce Richardson }
29799a2dd95SBruce Richardson 
29899a2dd95SBruce Richardson int
29999a2dd95SBruce Richardson rte_memzone_free(const struct rte_memzone *mz)
30099a2dd95SBruce Richardson {
30199a2dd95SBruce Richardson 	char name[RTE_MEMZONE_NAMESIZE];
30299a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
30399a2dd95SBruce Richardson 	struct rte_fbarray *arr;
30499a2dd95SBruce Richardson 	struct rte_memzone *found_mz;
30599a2dd95SBruce Richardson 	int ret = 0;
30699a2dd95SBruce Richardson 	void *addr = NULL;
30799a2dd95SBruce Richardson 	unsigned idx;
30899a2dd95SBruce Richardson 
30999a2dd95SBruce Richardson 	if (mz == NULL)
31099a2dd95SBruce Richardson 		return -EINVAL;
31199a2dd95SBruce Richardson 
31299a2dd95SBruce Richardson 	rte_strlcpy(name, mz->name, RTE_MEMZONE_NAMESIZE);
31399a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
31499a2dd95SBruce Richardson 	arr = &mcfg->memzones;
31599a2dd95SBruce Richardson 
31699a2dd95SBruce Richardson 	rte_rwlock_write_lock(&mcfg->mlock);
31799a2dd95SBruce Richardson 
31899a2dd95SBruce Richardson 	idx = rte_fbarray_find_idx(arr, mz);
31999a2dd95SBruce Richardson 	found_mz = rte_fbarray_get(arr, idx);
32099a2dd95SBruce Richardson 
32199a2dd95SBruce Richardson 	if (found_mz == NULL) {
32299a2dd95SBruce Richardson 		ret = -EINVAL;
32399a2dd95SBruce Richardson 	} else if (found_mz->addr == NULL) {
324ae67895bSDavid Marchand 		EAL_LOG(ERR, "Memzone is not allocated");
32599a2dd95SBruce Richardson 		ret = -EINVAL;
32699a2dd95SBruce Richardson 	} else {
32799a2dd95SBruce Richardson 		addr = found_mz->addr;
32899a2dd95SBruce Richardson 		memset(found_mz, 0, sizeof(*found_mz));
32999a2dd95SBruce Richardson 		rte_fbarray_set_free(arr, idx);
33099a2dd95SBruce Richardson 	}
33199a2dd95SBruce Richardson 
33299a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&mcfg->mlock);
33399a2dd95SBruce Richardson 
334a306620eSStephen Hemminger 	rte_eal_trace_memzone_free(name, addr, ret);
335a306620eSStephen Hemminger 
33699a2dd95SBruce Richardson 	rte_free(addr);
33799a2dd95SBruce Richardson 
33899a2dd95SBruce Richardson 	return ret;
33999a2dd95SBruce Richardson }
34099a2dd95SBruce Richardson 
34199a2dd95SBruce Richardson /*
34299a2dd95SBruce Richardson  * Lookup for the memzone identified by the given name
34399a2dd95SBruce Richardson  */
34499a2dd95SBruce Richardson const struct rte_memzone *
34599a2dd95SBruce Richardson rte_memzone_lookup(const char *name)
34699a2dd95SBruce Richardson {
34799a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
34899a2dd95SBruce Richardson 	const struct rte_memzone *memzone = NULL;
34999a2dd95SBruce Richardson 
35099a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
35199a2dd95SBruce Richardson 
35299a2dd95SBruce Richardson 	rte_rwlock_read_lock(&mcfg->mlock);
35399a2dd95SBruce Richardson 
35499a2dd95SBruce Richardson 	memzone = memzone_lookup_thread_unsafe(name);
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&mcfg->mlock);
35799a2dd95SBruce Richardson 
35899a2dd95SBruce Richardson 	rte_eal_trace_memzone_lookup(name, memzone);
35999a2dd95SBruce Richardson 	return memzone;
36099a2dd95SBruce Richardson }
36199a2dd95SBruce Richardson 
362*17bb6004SGagandeep Singh struct memzone_info {
363*17bb6004SGagandeep Singh 	FILE *f;
364*17bb6004SGagandeep Singh 	uint64_t total_size;
365*17bb6004SGagandeep Singh };
366*17bb6004SGagandeep Singh 
36799a2dd95SBruce Richardson static void
36899a2dd95SBruce Richardson dump_memzone(const struct rte_memzone *mz, void *arg)
36999a2dd95SBruce Richardson {
37099a2dd95SBruce Richardson 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
37199a2dd95SBruce Richardson 	struct rte_memseg_list *msl = NULL;
372*17bb6004SGagandeep Singh 	struct memzone_info *info = arg;
37399a2dd95SBruce Richardson 	void *cur_addr, *mz_end;
37499a2dd95SBruce Richardson 	struct rte_memseg *ms;
37599a2dd95SBruce Richardson 	int mz_idx, ms_idx;
376*17bb6004SGagandeep Singh 	FILE *f = info->f;
37799a2dd95SBruce Richardson 	size_t page_sz;
37899a2dd95SBruce Richardson 
37999a2dd95SBruce Richardson 	mz_idx = rte_fbarray_find_idx(&mcfg->memzones, mz);
380*17bb6004SGagandeep Singh 	info->total_size += mz->len;
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson 	fprintf(f, "Zone %u: name:<%s>, len:0x%zx, virt:%p, "
38399a2dd95SBruce Richardson 				"socket_id:%"PRId32", flags:%"PRIx32"\n",
38499a2dd95SBruce Richardson 			mz_idx,
38599a2dd95SBruce Richardson 			mz->name,
38699a2dd95SBruce Richardson 			mz->len,
38799a2dd95SBruce Richardson 			mz->addr,
38899a2dd95SBruce Richardson 			mz->socket_id,
38999a2dd95SBruce Richardson 			mz->flags);
39099a2dd95SBruce Richardson 
39199a2dd95SBruce Richardson 	/* go through each page occupied by this memzone */
39299a2dd95SBruce Richardson 	msl = rte_mem_virt2memseg_list(mz->addr);
39399a2dd95SBruce Richardson 	if (!msl) {
394ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "Skipping bad memzone");
39599a2dd95SBruce Richardson 		return;
39699a2dd95SBruce Richardson 	}
39799a2dd95SBruce Richardson 	page_sz = (size_t)mz->hugepage_sz;
39899a2dd95SBruce Richardson 	cur_addr = RTE_PTR_ALIGN_FLOOR(mz->addr, page_sz);
39999a2dd95SBruce Richardson 	mz_end = RTE_PTR_ADD(cur_addr, mz->len);
40099a2dd95SBruce Richardson 
40199a2dd95SBruce Richardson 	fprintf(f, "physical segments used:\n");
40299a2dd95SBruce Richardson 	ms_idx = RTE_PTR_DIFF(mz->addr, msl->base_va) / page_sz;
40399a2dd95SBruce Richardson 	ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson 	do {
40699a2dd95SBruce Richardson 		fprintf(f, "  addr: %p iova: 0x%" PRIx64 " "
40799a2dd95SBruce Richardson 				"len: 0x%zx "
40899a2dd95SBruce Richardson 				"pagesz: 0x%zx\n",
40999a2dd95SBruce Richardson 			cur_addr, ms->iova, ms->len, page_sz);
41099a2dd95SBruce Richardson 
41199a2dd95SBruce Richardson 		/* advance VA to next page */
41299a2dd95SBruce Richardson 		cur_addr = RTE_PTR_ADD(cur_addr, page_sz);
41399a2dd95SBruce Richardson 
41499a2dd95SBruce Richardson 		/* memzones occupy contiguous segments */
41599a2dd95SBruce Richardson 		++ms;
41699a2dd95SBruce Richardson 	} while (cur_addr < mz_end);
41799a2dd95SBruce Richardson }
41899a2dd95SBruce Richardson 
41999a2dd95SBruce Richardson /* Dump all reserved memory zones on console */
42099a2dd95SBruce Richardson void
42199a2dd95SBruce Richardson rte_memzone_dump(FILE *f)
42299a2dd95SBruce Richardson {
423*17bb6004SGagandeep Singh 	struct memzone_info info = { .f = f };
424*17bb6004SGagandeep Singh 
425*17bb6004SGagandeep Singh 	rte_memzone_walk(dump_memzone, &info);
426*17bb6004SGagandeep Singh 	fprintf(f, "Total Memory Zones size = %"PRIu64"M\n",
427*17bb6004SGagandeep Singh 		info.total_size / (1024 * 1024));
42899a2dd95SBruce Richardson }
42999a2dd95SBruce Richardson 
43099a2dd95SBruce Richardson /*
43199a2dd95SBruce Richardson  * Init the memzone subsystem
43299a2dd95SBruce Richardson  */
43399a2dd95SBruce Richardson int
43499a2dd95SBruce Richardson rte_eal_memzone_init(void)
43599a2dd95SBruce Richardson {
43699a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
43799a2dd95SBruce Richardson 	int ret = 0;
43899a2dd95SBruce Richardson 
43999a2dd95SBruce Richardson 	/* get pointer to global configuration */
44099a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
44199a2dd95SBruce Richardson 
44299a2dd95SBruce Richardson 	rte_rwlock_write_lock(&mcfg->mlock);
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
44599a2dd95SBruce Richardson 			rte_fbarray_init(&mcfg->memzones, "memzone",
44638689022SOphir Munk 			rte_memzone_max_get(), sizeof(struct rte_memzone))) {
447ae67895bSDavid Marchand 		EAL_LOG(ERR, "Cannot allocate memzone list");
44899a2dd95SBruce Richardson 		ret = -1;
44999a2dd95SBruce Richardson 	} else if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
45099a2dd95SBruce Richardson 			rte_fbarray_attach(&mcfg->memzones)) {
451ae67895bSDavid Marchand 		EAL_LOG(ERR, "Cannot attach to memzone list");
45299a2dd95SBruce Richardson 		ret = -1;
45399a2dd95SBruce Richardson 	}
45499a2dd95SBruce Richardson 
45599a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&mcfg->mlock);
45699a2dd95SBruce Richardson 
45799a2dd95SBruce Richardson 	return ret;
45899a2dd95SBruce Richardson }
45999a2dd95SBruce Richardson 
46099a2dd95SBruce Richardson /* Walk all reserved memory zones */
46199a2dd95SBruce Richardson void rte_memzone_walk(void (*func)(const struct rte_memzone *, void *),
46299a2dd95SBruce Richardson 		      void *arg)
46399a2dd95SBruce Richardson {
46499a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
46599a2dd95SBruce Richardson 	struct rte_fbarray *arr;
46699a2dd95SBruce Richardson 	int i;
46799a2dd95SBruce Richardson 
46899a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
46999a2dd95SBruce Richardson 	arr = &mcfg->memzones;
47099a2dd95SBruce Richardson 
47199a2dd95SBruce Richardson 	rte_rwlock_read_lock(&mcfg->mlock);
47299a2dd95SBruce Richardson 	i = rte_fbarray_find_next_used(arr, 0);
47399a2dd95SBruce Richardson 	while (i >= 0) {
47499a2dd95SBruce Richardson 		struct rte_memzone *mz = rte_fbarray_get(arr, i);
47599a2dd95SBruce Richardson 		(*func)(mz, arg);
47699a2dd95SBruce Richardson 		i = rte_fbarray_find_next_used(arr, i + 1);
47799a2dd95SBruce Richardson 	}
47899a2dd95SBruce Richardson 	rte_rwlock_read_unlock(&mcfg->mlock);
47999a2dd95SBruce Richardson }
480