xref: /dpdk/lib/eal/freebsd/eal_memory.c (revision ae67895b507bb6af22263c79ba0d5c374b396485)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson #include <sys/mman.h>
599a2dd95SBruce Richardson #include <unistd.h>
699a2dd95SBruce Richardson #include <sys/types.h>
799a2dd95SBruce Richardson #include <sys/sysctl.h>
899a2dd95SBruce Richardson #include <inttypes.h>
999a2dd95SBruce Richardson #include <errno.h>
1099a2dd95SBruce Richardson #include <string.h>
1199a2dd95SBruce Richardson #include <fcntl.h>
1299a2dd95SBruce Richardson 
1399a2dd95SBruce Richardson #include <rte_eal.h>
1499a2dd95SBruce Richardson #include <rte_errno.h>
1599a2dd95SBruce Richardson #include <rte_log.h>
1699a2dd95SBruce Richardson #include <rte_string_fns.h>
1799a2dd95SBruce Richardson 
1899a2dd95SBruce Richardson #include "eal_private.h"
1999a2dd95SBruce Richardson #include "eal_internal_cfg.h"
2099a2dd95SBruce Richardson #include "eal_filesystem.h"
2199a2dd95SBruce Richardson #include "eal_memcfg.h"
2299a2dd95SBruce Richardson #include "eal_options.h"
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson #define EAL_PAGE_SIZE (sysconf(_SC_PAGESIZE))
2599a2dd95SBruce Richardson 
eal_get_baseaddr(void)2699a2dd95SBruce Richardson uint64_t eal_get_baseaddr(void)
2799a2dd95SBruce Richardson {
2899a2dd95SBruce Richardson 	/*
2999a2dd95SBruce Richardson 	 * FreeBSD may allocate something in the space we will be mapping things
3099a2dd95SBruce Richardson 	 * before we get a chance to do that, so use a base address that's far
3199a2dd95SBruce Richardson 	 * away from where malloc() et al usually map things.
3299a2dd95SBruce Richardson 	 */
3399a2dd95SBruce Richardson 	return 0x1000000000ULL;
3499a2dd95SBruce Richardson }
3599a2dd95SBruce Richardson 
3699a2dd95SBruce Richardson /*
3799a2dd95SBruce Richardson  * Get physical address of any mapped virtual address in the current process.
3899a2dd95SBruce Richardson  */
3999a2dd95SBruce Richardson phys_addr_t
rte_mem_virt2phy(const void * virtaddr)4099a2dd95SBruce Richardson rte_mem_virt2phy(const void *virtaddr)
4199a2dd95SBruce Richardson {
4299a2dd95SBruce Richardson 	/* XXX not implemented. This function is only used by
4399a2dd95SBruce Richardson 	 * rte_mempool_virt2iova() when hugepages are disabled. */
4499a2dd95SBruce Richardson 	(void)virtaddr;
4599a2dd95SBruce Richardson 	return RTE_BAD_IOVA;
4699a2dd95SBruce Richardson }
4799a2dd95SBruce Richardson rte_iova_t
rte_mem_virt2iova(const void * virtaddr)4899a2dd95SBruce Richardson rte_mem_virt2iova(const void *virtaddr)
4999a2dd95SBruce Richardson {
5099a2dd95SBruce Richardson 	return rte_mem_virt2phy(virtaddr);
5199a2dd95SBruce Richardson }
5299a2dd95SBruce Richardson 
5399a2dd95SBruce Richardson int
rte_eal_hugepage_init(void)5499a2dd95SBruce Richardson rte_eal_hugepage_init(void)
5599a2dd95SBruce Richardson {
5699a2dd95SBruce Richardson 	struct rte_mem_config *mcfg;
5799a2dd95SBruce Richardson 	uint64_t total_mem = 0;
5899a2dd95SBruce Richardson 	void *addr;
5999a2dd95SBruce Richardson 	unsigned int i, j, seg_idx = 0;
6099a2dd95SBruce Richardson 	struct internal_config *internal_conf =
6199a2dd95SBruce Richardson 		eal_get_internal_configuration();
6299a2dd95SBruce Richardson 
6399a2dd95SBruce Richardson 	/* get pointer to global configuration */
6499a2dd95SBruce Richardson 	mcfg = rte_eal_get_configuration()->mem_config;
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson 	/* for debug purposes, hugetlbfs can be disabled */
6799a2dd95SBruce Richardson 	if (internal_conf->no_hugetlbfs) {
6899a2dd95SBruce Richardson 		struct rte_memseg_list *msl;
6999a2dd95SBruce Richardson 		uint64_t mem_sz, page_sz;
7099a2dd95SBruce Richardson 		int n_segs;
7199a2dd95SBruce Richardson 
7299a2dd95SBruce Richardson 		/* create a memseg list */
7399a2dd95SBruce Richardson 		msl = &mcfg->memsegs[0];
7499a2dd95SBruce Richardson 
7599a2dd95SBruce Richardson 		mem_sz = internal_conf->memory;
7699a2dd95SBruce Richardson 		page_sz = RTE_PGSIZE_4K;
7799a2dd95SBruce Richardson 		n_segs = mem_sz / page_sz;
7899a2dd95SBruce Richardson 
7999a2dd95SBruce Richardson 		if (eal_memseg_list_init_named(
8099a2dd95SBruce Richardson 				msl, "nohugemem", page_sz, n_segs, 0, true)) {
8199a2dd95SBruce Richardson 			return -1;
8299a2dd95SBruce Richardson 		}
8399a2dd95SBruce Richardson 
8499a2dd95SBruce Richardson 		addr = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
8599a2dd95SBruce Richardson 				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
8699a2dd95SBruce Richardson 		if (addr == MAP_FAILED) {
87*ae67895bSDavid Marchand 			EAL_LOG(ERR, "%s: mmap() failed: %s", __func__,
8899a2dd95SBruce Richardson 					strerror(errno));
8999a2dd95SBruce Richardson 			return -1;
9099a2dd95SBruce Richardson 		}
9199a2dd95SBruce Richardson 
9299a2dd95SBruce Richardson 		msl->base_va = addr;
9399a2dd95SBruce Richardson 		msl->len = mem_sz;
9499a2dd95SBruce Richardson 
9599a2dd95SBruce Richardson 		eal_memseg_list_populate(msl, addr, n_segs);
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson 		return 0;
9899a2dd95SBruce Richardson 	}
9999a2dd95SBruce Richardson 
10099a2dd95SBruce Richardson 	/* map all hugepages and sort them */
10199a2dd95SBruce Richardson 	for (i = 0; i < internal_conf->num_hugepage_sizes; i++) {
10299a2dd95SBruce Richardson 		struct hugepage_info *hpi;
10399a2dd95SBruce Richardson 		rte_iova_t prev_end = 0;
10499a2dd95SBruce Richardson 		int prev_ms_idx = -1;
10599a2dd95SBruce Richardson 		uint64_t page_sz, mem_needed;
10699a2dd95SBruce Richardson 		unsigned int n_pages, max_pages;
10799a2dd95SBruce Richardson 
10899a2dd95SBruce Richardson 		hpi = &internal_conf->hugepage_info[i];
10999a2dd95SBruce Richardson 		page_sz = hpi->hugepage_sz;
11099a2dd95SBruce Richardson 		max_pages = hpi->num_pages[0];
11199a2dd95SBruce Richardson 		mem_needed = RTE_ALIGN_CEIL(internal_conf->memory - total_mem,
11299a2dd95SBruce Richardson 				page_sz);
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 		n_pages = RTE_MIN(mem_needed / page_sz, max_pages);
11599a2dd95SBruce Richardson 
11699a2dd95SBruce Richardson 		for (j = 0; j < n_pages; j++) {
11799a2dd95SBruce Richardson 			struct rte_memseg_list *msl;
11899a2dd95SBruce Richardson 			struct rte_fbarray *arr;
11999a2dd95SBruce Richardson 			struct rte_memseg *seg;
12099a2dd95SBruce Richardson 			int msl_idx, ms_idx;
12199a2dd95SBruce Richardson 			rte_iova_t physaddr;
12299a2dd95SBruce Richardson 			int error;
12399a2dd95SBruce Richardson 			size_t sysctl_size = sizeof(physaddr);
12499a2dd95SBruce Richardson 			char physaddr_str[64];
12599a2dd95SBruce Richardson 			bool is_adjacent;
12699a2dd95SBruce Richardson 
12799a2dd95SBruce Richardson 			/* first, check if this segment is IOVA-adjacent to
12899a2dd95SBruce Richardson 			 * the previous one.
12999a2dd95SBruce Richardson 			 */
13099a2dd95SBruce Richardson 			snprintf(physaddr_str, sizeof(physaddr_str),
13199a2dd95SBruce Richardson 					"hw.contigmem.physaddr.%d", j);
13299a2dd95SBruce Richardson 			error = sysctlbyname(physaddr_str, &physaddr,
13399a2dd95SBruce Richardson 					&sysctl_size, NULL, 0);
13499a2dd95SBruce Richardson 			if (error < 0) {
135*ae67895bSDavid Marchand 				EAL_LOG(ERR, "Failed to get physical addr for buffer %u "
136*ae67895bSDavid Marchand 						"from %s", j, hpi->hugedir);
13799a2dd95SBruce Richardson 				return -1;
13899a2dd95SBruce Richardson 			}
13999a2dd95SBruce Richardson 
14099a2dd95SBruce Richardson 			is_adjacent = prev_end != 0 && physaddr == prev_end;
14199a2dd95SBruce Richardson 			prev_end = physaddr + hpi->hugepage_sz;
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 			for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS;
14499a2dd95SBruce Richardson 					msl_idx++) {
14599a2dd95SBruce Richardson 				bool empty, need_hole;
14699a2dd95SBruce Richardson 				msl = &mcfg->memsegs[msl_idx];
14799a2dd95SBruce Richardson 				arr = &msl->memseg_arr;
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson 				if (msl->page_sz != page_sz)
15099a2dd95SBruce Richardson 					continue;
15199a2dd95SBruce Richardson 
15299a2dd95SBruce Richardson 				empty = arr->count == 0;
15399a2dd95SBruce Richardson 
15499a2dd95SBruce Richardson 				/* we need a hole if this isn't an empty memseg
15599a2dd95SBruce Richardson 				 * list, and if previous segment was not
15699a2dd95SBruce Richardson 				 * adjacent to current one.
15799a2dd95SBruce Richardson 				 */
15899a2dd95SBruce Richardson 				need_hole = !empty && !is_adjacent;
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson 				/* we need 1, plus hole if not adjacent */
16199a2dd95SBruce Richardson 				ms_idx = rte_fbarray_find_next_n_free(arr,
16299a2dd95SBruce Richardson 						0, 1 + (need_hole ? 1 : 0));
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson 				/* memseg list is full? */
16599a2dd95SBruce Richardson 				if (ms_idx < 0)
16699a2dd95SBruce Richardson 					continue;
16799a2dd95SBruce Richardson 
16899a2dd95SBruce Richardson 				if (need_hole && prev_ms_idx == ms_idx - 1)
16999a2dd95SBruce Richardson 					ms_idx++;
17099a2dd95SBruce Richardson 				prev_ms_idx = ms_idx;
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson 				break;
17399a2dd95SBruce Richardson 			}
17499a2dd95SBruce Richardson 			if (msl_idx == RTE_MAX_MEMSEG_LISTS) {
175*ae67895bSDavid Marchand 				EAL_LOG(ERR, "Could not find space for memseg. Please increase RTE_MAX_MEMSEG_PER_LIST "
176*ae67895bSDavid Marchand 					"RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
17799a2dd95SBruce Richardson 				return -1;
17899a2dd95SBruce Richardson 			}
17999a2dd95SBruce Richardson 			arr = &msl->memseg_arr;
18099a2dd95SBruce Richardson 			seg = rte_fbarray_get(arr, ms_idx);
18199a2dd95SBruce Richardson 
18299a2dd95SBruce Richardson 			addr = RTE_PTR_ADD(msl->base_va,
18399a2dd95SBruce Richardson 					(size_t)msl->page_sz * ms_idx);
18499a2dd95SBruce Richardson 
18599a2dd95SBruce Richardson 			/* address is already mapped in memseg list, so using
18699a2dd95SBruce Richardson 			 * MAP_FIXED here is safe.
18799a2dd95SBruce Richardson 			 */
18899a2dd95SBruce Richardson 			addr = mmap(addr, page_sz, PROT_READ|PROT_WRITE,
18999a2dd95SBruce Richardson 					MAP_SHARED | MAP_FIXED,
19099a2dd95SBruce Richardson 					hpi->lock_descriptor,
19199a2dd95SBruce Richardson 					j * EAL_PAGE_SIZE);
19299a2dd95SBruce Richardson 			if (addr == MAP_FAILED) {
193*ae67895bSDavid Marchand 				EAL_LOG(ERR, "Failed to mmap buffer %u from %s",
19499a2dd95SBruce Richardson 						j, hpi->hugedir);
19599a2dd95SBruce Richardson 				return -1;
19699a2dd95SBruce Richardson 			}
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 			seg->addr = addr;
19999a2dd95SBruce Richardson 			seg->iova = physaddr;
20099a2dd95SBruce Richardson 			seg->hugepage_sz = page_sz;
20199a2dd95SBruce Richardson 			seg->len = page_sz;
20299a2dd95SBruce Richardson 			seg->nchannel = mcfg->nchannel;
20399a2dd95SBruce Richardson 			seg->nrank = mcfg->nrank;
20499a2dd95SBruce Richardson 			seg->socket_id = 0;
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson 			rte_fbarray_set_used(arr, ms_idx);
20799a2dd95SBruce Richardson 
208*ae67895bSDavid Marchand 			EAL_LOG(INFO, "Mapped memory segment %u @ %p: physaddr:0x%"
209*ae67895bSDavid Marchand 					PRIx64", len %zu",
21099a2dd95SBruce Richardson 					seg_idx++, addr, physaddr, page_sz);
21199a2dd95SBruce Richardson 
21299a2dd95SBruce Richardson 			total_mem += seg->len;
21399a2dd95SBruce Richardson 		}
21499a2dd95SBruce Richardson 		if (total_mem >= internal_conf->memory)
21599a2dd95SBruce Richardson 			break;
21699a2dd95SBruce Richardson 	}
21799a2dd95SBruce Richardson 	if (total_mem < internal_conf->memory) {
218*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Couldn't reserve requested memory, "
21999a2dd95SBruce Richardson 				"requested: %" PRIu64 "M "
220*ae67895bSDavid Marchand 				"available: %" PRIu64 "M",
22199a2dd95SBruce Richardson 				internal_conf->memory >> 20, total_mem >> 20);
22299a2dd95SBruce Richardson 		return -1;
22399a2dd95SBruce Richardson 	}
22499a2dd95SBruce Richardson 	return 0;
22599a2dd95SBruce Richardson }
22699a2dd95SBruce Richardson 
22799a2dd95SBruce Richardson struct attach_walk_args {
22899a2dd95SBruce Richardson 	int fd_hugepage;
22999a2dd95SBruce Richardson 	int seg_idx;
23099a2dd95SBruce Richardson };
23199a2dd95SBruce Richardson static int
attach_segment(const struct rte_memseg_list * msl,const struct rte_memseg * ms,void * arg)23299a2dd95SBruce Richardson attach_segment(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
23399a2dd95SBruce Richardson 		void *arg)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 	struct attach_walk_args *wa = arg;
23699a2dd95SBruce Richardson 	void *addr;
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 	if (msl->external)
23999a2dd95SBruce Richardson 		return 0;
24099a2dd95SBruce Richardson 
24199a2dd95SBruce Richardson 	addr = mmap(ms->addr, ms->len, PROT_READ | PROT_WRITE,
24299a2dd95SBruce Richardson 			MAP_SHARED | MAP_FIXED, wa->fd_hugepage,
24399a2dd95SBruce Richardson 			wa->seg_idx * EAL_PAGE_SIZE);
24499a2dd95SBruce Richardson 	if (addr == MAP_FAILED || addr != ms->addr)
24599a2dd95SBruce Richardson 		return -1;
24699a2dd95SBruce Richardson 	wa->seg_idx++;
24799a2dd95SBruce Richardson 
24899a2dd95SBruce Richardson 	return 0;
24999a2dd95SBruce Richardson }
25099a2dd95SBruce Richardson 
25199a2dd95SBruce Richardson int
rte_eal_hugepage_attach(void)25299a2dd95SBruce Richardson rte_eal_hugepage_attach(void)
25399a2dd95SBruce Richardson {
25499a2dd95SBruce Richardson 	struct hugepage_info *hpi;
25599a2dd95SBruce Richardson 	int fd_hugepage = -1;
25699a2dd95SBruce Richardson 	unsigned int i;
25799a2dd95SBruce Richardson 	struct internal_config *internal_conf =
25899a2dd95SBruce Richardson 		eal_get_internal_configuration();
25999a2dd95SBruce Richardson 
26099a2dd95SBruce Richardson 	hpi = &internal_conf->hugepage_info[0];
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson 	for (i = 0; i < internal_conf->num_hugepage_sizes; i++) {
26399a2dd95SBruce Richardson 		const struct hugepage_info *cur_hpi = &hpi[i];
26499a2dd95SBruce Richardson 		struct attach_walk_args wa;
26599a2dd95SBruce Richardson 
26699a2dd95SBruce Richardson 		memset(&wa, 0, sizeof(wa));
26799a2dd95SBruce Richardson 
26899a2dd95SBruce Richardson 		/* Obtain a file descriptor for contiguous memory */
26999a2dd95SBruce Richardson 		fd_hugepage = open(cur_hpi->hugedir, O_RDWR);
27099a2dd95SBruce Richardson 		if (fd_hugepage < 0) {
271*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Could not open %s",
27299a2dd95SBruce Richardson 					cur_hpi->hugedir);
27399a2dd95SBruce Richardson 			goto error;
27499a2dd95SBruce Richardson 		}
27599a2dd95SBruce Richardson 		wa.fd_hugepage = fd_hugepage;
27699a2dd95SBruce Richardson 		wa.seg_idx = 0;
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson 		/* Map the contiguous memory into each memory segment */
27999a2dd95SBruce Richardson 		if (rte_memseg_walk(attach_segment, &wa) < 0) {
280*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Failed to mmap buffer %u from %s",
28199a2dd95SBruce Richardson 				wa.seg_idx, cur_hpi->hugedir);
28299a2dd95SBruce Richardson 			goto error;
28399a2dd95SBruce Richardson 		}
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson 		close(fd_hugepage);
28699a2dd95SBruce Richardson 		fd_hugepage = -1;
28799a2dd95SBruce Richardson 	}
28899a2dd95SBruce Richardson 
28999a2dd95SBruce Richardson 	/* hugepage_info is no longer required */
29099a2dd95SBruce Richardson 	return 0;
29199a2dd95SBruce Richardson 
29299a2dd95SBruce Richardson error:
29399a2dd95SBruce Richardson 	if (fd_hugepage >= 0)
29499a2dd95SBruce Richardson 		close(fd_hugepage);
29599a2dd95SBruce Richardson 	return -1;
29699a2dd95SBruce Richardson }
29799a2dd95SBruce Richardson 
29899a2dd95SBruce Richardson int
rte_eal_using_phys_addrs(void)29999a2dd95SBruce Richardson rte_eal_using_phys_addrs(void)
30099a2dd95SBruce Richardson {
30199a2dd95SBruce Richardson 	return 0;
30299a2dd95SBruce Richardson }
30399a2dd95SBruce Richardson 
30499a2dd95SBruce Richardson static uint64_t
get_mem_amount(uint64_t page_sz,uint64_t max_mem)30599a2dd95SBruce Richardson get_mem_amount(uint64_t page_sz, uint64_t max_mem)
30699a2dd95SBruce Richardson {
30799a2dd95SBruce Richardson 	uint64_t area_sz, max_pages;
30899a2dd95SBruce Richardson 
30999a2dd95SBruce Richardson 	/* limit to RTE_MAX_MEMSEG_PER_LIST pages or RTE_MAX_MEM_MB_PER_LIST */
31099a2dd95SBruce Richardson 	max_pages = RTE_MAX_MEMSEG_PER_LIST;
31199a2dd95SBruce Richardson 	max_mem = RTE_MIN((uint64_t)RTE_MAX_MEM_MB_PER_LIST << 20, max_mem);
31299a2dd95SBruce Richardson 
31399a2dd95SBruce Richardson 	area_sz = RTE_MIN(page_sz * max_pages, max_mem);
31499a2dd95SBruce Richardson 
31599a2dd95SBruce Richardson 	/* make sure the list isn't smaller than the page size */
31699a2dd95SBruce Richardson 	area_sz = RTE_MAX(area_sz, page_sz);
31799a2dd95SBruce Richardson 
31899a2dd95SBruce Richardson 	return RTE_ALIGN(area_sz, page_sz);
31999a2dd95SBruce Richardson }
32099a2dd95SBruce Richardson 
32199a2dd95SBruce Richardson static int
memseg_list_alloc(struct rte_memseg_list * msl)32299a2dd95SBruce Richardson memseg_list_alloc(struct rte_memseg_list *msl)
32399a2dd95SBruce Richardson {
32499a2dd95SBruce Richardson 	int flags = 0;
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson #ifdef RTE_ARCH_PPC_64
32799a2dd95SBruce Richardson 	flags |= EAL_RESERVE_HUGEPAGES;
32899a2dd95SBruce Richardson #endif
32999a2dd95SBruce Richardson 	return eal_memseg_list_alloc(msl, flags);
33099a2dd95SBruce Richardson }
33199a2dd95SBruce Richardson 
33299a2dd95SBruce Richardson static int
memseg_primary_init(void)33399a2dd95SBruce Richardson memseg_primary_init(void)
33499a2dd95SBruce Richardson {
33599a2dd95SBruce Richardson 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
33699a2dd95SBruce Richardson 	int hpi_idx, msl_idx = 0;
33799a2dd95SBruce Richardson 	struct rte_memseg_list *msl;
33899a2dd95SBruce Richardson 	uint64_t max_mem, total_mem;
33999a2dd95SBruce Richardson 	struct internal_config *internal_conf =
34099a2dd95SBruce Richardson 		eal_get_internal_configuration();
34199a2dd95SBruce Richardson 
34299a2dd95SBruce Richardson 	/* no-huge does not need this at all */
34399a2dd95SBruce Richardson 	if (internal_conf->no_hugetlbfs)
34499a2dd95SBruce Richardson 		return 0;
34599a2dd95SBruce Richardson 
34699a2dd95SBruce Richardson 	/* FreeBSD has an issue where core dump will dump the entire memory
34799a2dd95SBruce Richardson 	 * contents, including anonymous zero-page memory. Therefore, while we
34899a2dd95SBruce Richardson 	 * will be limiting total amount of memory to RTE_MAX_MEM_MB, we will
34999a2dd95SBruce Richardson 	 * also be further limiting total memory amount to whatever memory is
35099a2dd95SBruce Richardson 	 * available to us through contigmem driver (plus spacing blocks).
35199a2dd95SBruce Richardson 	 *
35299a2dd95SBruce Richardson 	 * so, at each stage, we will be checking how much memory we are
35399a2dd95SBruce Richardson 	 * preallocating, and adjust all the values accordingly.
35499a2dd95SBruce Richardson 	 */
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson 	max_mem = (uint64_t)RTE_MAX_MEM_MB << 20;
35799a2dd95SBruce Richardson 	total_mem = 0;
35899a2dd95SBruce Richardson 
35999a2dd95SBruce Richardson 	/* create memseg lists */
36099a2dd95SBruce Richardson 	for (hpi_idx = 0; hpi_idx < (int) internal_conf->num_hugepage_sizes;
36199a2dd95SBruce Richardson 			hpi_idx++) {
36299a2dd95SBruce Richardson 		uint64_t max_type_mem, total_type_mem = 0;
36399a2dd95SBruce Richardson 		uint64_t avail_mem;
36499a2dd95SBruce Richardson 		int type_msl_idx, max_segs, avail_segs, total_segs = 0;
36599a2dd95SBruce Richardson 		struct hugepage_info *hpi;
36699a2dd95SBruce Richardson 		uint64_t hugepage_sz;
36799a2dd95SBruce Richardson 
36899a2dd95SBruce Richardson 		hpi = &internal_conf->hugepage_info[hpi_idx];
36999a2dd95SBruce Richardson 		hugepage_sz = hpi->hugepage_sz;
37099a2dd95SBruce Richardson 
37199a2dd95SBruce Richardson 		/* no NUMA support on FreeBSD */
37299a2dd95SBruce Richardson 
37399a2dd95SBruce Richardson 		/* check if we've already exceeded total memory amount */
37499a2dd95SBruce Richardson 		if (total_mem >= max_mem)
37599a2dd95SBruce Richardson 			break;
37699a2dd95SBruce Richardson 
37799a2dd95SBruce Richardson 		/* first, calculate theoretical limits according to config */
37899a2dd95SBruce Richardson 		max_type_mem = RTE_MIN(max_mem - total_mem,
37999a2dd95SBruce Richardson 			(uint64_t)RTE_MAX_MEM_MB_PER_TYPE << 20);
38099a2dd95SBruce Richardson 		max_segs = RTE_MAX_MEMSEG_PER_TYPE;
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson 		/* now, limit all of that to whatever will actually be
38399a2dd95SBruce Richardson 		 * available to us, because without dynamic allocation support,
38499a2dd95SBruce Richardson 		 * all of that extra memory will be sitting there being useless
38599a2dd95SBruce Richardson 		 * and slowing down core dumps in case of a crash.
38699a2dd95SBruce Richardson 		 *
38799a2dd95SBruce Richardson 		 * we need (N*2)-1 segments because we cannot guarantee that
38899a2dd95SBruce Richardson 		 * each segment will be IOVA-contiguous with the previous one,
38999a2dd95SBruce Richardson 		 * so we will allocate more and put spaces between segments
39099a2dd95SBruce Richardson 		 * that are non-contiguous.
39199a2dd95SBruce Richardson 		 */
39299a2dd95SBruce Richardson 		avail_segs = (hpi->num_pages[0] * 2) - 1;
39399a2dd95SBruce Richardson 		avail_mem = avail_segs * hugepage_sz;
39499a2dd95SBruce Richardson 
39599a2dd95SBruce Richardson 		max_type_mem = RTE_MIN(avail_mem, max_type_mem);
39699a2dd95SBruce Richardson 		max_segs = RTE_MIN(avail_segs, max_segs);
39799a2dd95SBruce Richardson 
39899a2dd95SBruce Richardson 		type_msl_idx = 0;
39999a2dd95SBruce Richardson 		while (total_type_mem < max_type_mem &&
40099a2dd95SBruce Richardson 				total_segs < max_segs) {
40199a2dd95SBruce Richardson 			uint64_t cur_max_mem, cur_mem;
40299a2dd95SBruce Richardson 			unsigned int n_segs;
40399a2dd95SBruce Richardson 
40499a2dd95SBruce Richardson 			if (msl_idx >= RTE_MAX_MEMSEG_LISTS) {
405*ae67895bSDavid Marchand 				EAL_LOG(ERR,
406*ae67895bSDavid Marchand 					"No more space in memseg lists, please increase RTE_MAX_MEMSEG_LISTS");
40799a2dd95SBruce Richardson 				return -1;
40899a2dd95SBruce Richardson 			}
40999a2dd95SBruce Richardson 
41099a2dd95SBruce Richardson 			msl = &mcfg->memsegs[msl_idx++];
41199a2dd95SBruce Richardson 
41299a2dd95SBruce Richardson 			cur_max_mem = max_type_mem - total_type_mem;
41399a2dd95SBruce Richardson 
41499a2dd95SBruce Richardson 			cur_mem = get_mem_amount(hugepage_sz,
41599a2dd95SBruce Richardson 					cur_max_mem);
41699a2dd95SBruce Richardson 			n_segs = cur_mem / hugepage_sz;
41799a2dd95SBruce Richardson 
41899a2dd95SBruce Richardson 			if (eal_memseg_list_init(msl, hugepage_sz, n_segs,
41999a2dd95SBruce Richardson 					0, type_msl_idx, false))
42099a2dd95SBruce Richardson 				return -1;
42199a2dd95SBruce Richardson 
42299a2dd95SBruce Richardson 			total_segs += msl->memseg_arr.len;
42399a2dd95SBruce Richardson 			total_type_mem = total_segs * hugepage_sz;
42499a2dd95SBruce Richardson 			type_msl_idx++;
42599a2dd95SBruce Richardson 
42699a2dd95SBruce Richardson 			if (memseg_list_alloc(msl)) {
427*ae67895bSDavid Marchand 				EAL_LOG(ERR, "Cannot allocate VA space for memseg list");
42899a2dd95SBruce Richardson 				return -1;
42999a2dd95SBruce Richardson 			}
43099a2dd95SBruce Richardson 		}
43199a2dd95SBruce Richardson 		total_mem += total_type_mem;
43299a2dd95SBruce Richardson 	}
43399a2dd95SBruce Richardson 	return 0;
43499a2dd95SBruce Richardson }
43599a2dd95SBruce Richardson 
43699a2dd95SBruce Richardson static int
memseg_secondary_init(void)43799a2dd95SBruce Richardson memseg_secondary_init(void)
43899a2dd95SBruce Richardson {
43999a2dd95SBruce Richardson 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
44099a2dd95SBruce Richardson 	int msl_idx = 0;
44199a2dd95SBruce Richardson 	struct rte_memseg_list *msl;
44299a2dd95SBruce Richardson 
44399a2dd95SBruce Richardson 	for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS; msl_idx++) {
44499a2dd95SBruce Richardson 
44599a2dd95SBruce Richardson 		msl = &mcfg->memsegs[msl_idx];
44699a2dd95SBruce Richardson 
44790bf3f89SDeepak Khandelwal 		/* skip empty and external memseg lists */
44890bf3f89SDeepak Khandelwal 		if (msl->memseg_arr.len == 0 || msl->external)
44999a2dd95SBruce Richardson 			continue;
45099a2dd95SBruce Richardson 
45199a2dd95SBruce Richardson 		if (rte_fbarray_attach(&msl->memseg_arr)) {
452*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Cannot attach to primary process memseg lists");
45399a2dd95SBruce Richardson 			return -1;
45499a2dd95SBruce Richardson 		}
45599a2dd95SBruce Richardson 
45699a2dd95SBruce Richardson 		/* preallocate VA space */
45799a2dd95SBruce Richardson 		if (memseg_list_alloc(msl)) {
458*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Cannot preallocate VA space for hugepage memory");
45999a2dd95SBruce Richardson 			return -1;
46099a2dd95SBruce Richardson 		}
46199a2dd95SBruce Richardson 	}
46299a2dd95SBruce Richardson 
46399a2dd95SBruce Richardson 	return 0;
46499a2dd95SBruce Richardson }
46599a2dd95SBruce Richardson 
46699a2dd95SBruce Richardson int
rte_eal_memseg_init(void)46799a2dd95SBruce Richardson rte_eal_memseg_init(void)
46899a2dd95SBruce Richardson {
46999a2dd95SBruce Richardson 	return rte_eal_process_type() == RTE_PROC_PRIMARY ?
47099a2dd95SBruce Richardson 			memseg_primary_init() :
47199a2dd95SBruce Richardson 			memseg_secondary_init();
47299a2dd95SBruce Richardson }
473