Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2#include "tests/common.h"
  3#include <string.h>
  4#include <getopt.h>
  5#include <linux/memory_hotplug.h>
  6#include <linux/build_bug.h>
  7
  8#define PREFIXES_MAX				15
  9#define DELIM					": "
 10#define BASIS					10000
 11
 12static struct test_memory memory_block;
 13static const char __maybe_unused *prefixes[PREFIXES_MAX];
 14static int __maybe_unused nr_prefixes;
 15
 16static const char *short_opts = "hmv";
 17static const struct option long_opts[] = {
 18	{"help", 0, NULL, 'h'},
 19	{"movable-node", 0, NULL, 'm'},
 20	{"verbose", 0, NULL, 'v'},
 21	{NULL, 0, NULL, 0}
 22};
 23
 24static const char * const help_opts[] = {
 25	"display this help message and exit",
 26	"disallow allocations from regions marked as hotplugged\n\t\t\t"
 27		"by simulating enabling the \"movable_node\" kernel\n\t\t\t"
 28		"parameter",
 29	"enable verbose output, which includes the name of the\n\t\t\t"
 30		"memblock function being tested, the name of the test,\n\t\t\t"
 31		"and whether the test passed or failed."
 32};
 33
 34static int verbose;
 35
 36/* sets global variable returned by movable_node_is_enabled() stub */
 37bool movable_node_enabled;
 38
 39void reset_memblock_regions(void)
 40{
 41	memset(memblock.memory.regions, 0,
 42	       memblock.memory.cnt * sizeof(struct memblock_region));
 43	memblock.memory.cnt	= 1;
 44	memblock.memory.max	= INIT_MEMBLOCK_REGIONS;
 45	memblock.memory.total_size = 0;
 46
 47	memset(memblock.reserved.regions, 0,
 48	       memblock.reserved.cnt * sizeof(struct memblock_region));
 49	memblock.reserved.cnt	= 1;
 50	memblock.reserved.max	= INIT_MEMBLOCK_RESERVED_REGIONS;
 51	memblock.reserved.total_size = 0;
 52}
 53
 54void reset_memblock_attributes(void)
 55{
 56	memblock.memory.name	= "memory";
 57	memblock.reserved.name	= "reserved";
 58	memblock.bottom_up	= false;
 59	memblock.current_limit	= MEMBLOCK_ALLOC_ANYWHERE;
 60}
 61
 62static inline void fill_memblock(void)
 63{
 64	memset(memory_block.base, 1, MEM_SIZE);
 65}
 66
 67void setup_memblock(void)
 68{
 69	reset_memblock_regions();
 70	memblock_add((phys_addr_t)memory_block.base, MEM_SIZE);
 71	fill_memblock();
 72}
 73
 74/**
 75 * setup_numa_memblock:
 76 * Set up a memory layout with multiple NUMA nodes in a previously allocated
 77 * dummy physical memory.
 78 * @node_fracs: an array representing the fraction of MEM_SIZE contained in
 79 *              each node in basis point units (one hundredth of 1% or 1/10000).
 80 *              For example, if node 0 should contain 1/8 of MEM_SIZE,
 81 *              node_fracs[0] = 1250.
 82 *
 83 * The nids will be set to 0 through NUMA_NODES - 1.
 84 */
 85void setup_numa_memblock(const unsigned int node_fracs[])
 86{
 87	phys_addr_t base;
 88	int flags;
 89
 90	reset_memblock_regions();
 91	base = (phys_addr_t)memory_block.base;
 92	flags = (movable_node_is_enabled()) ? MEMBLOCK_NONE : MEMBLOCK_HOTPLUG;
 93
 94	for (int i = 0; i < NUMA_NODES; i++) {
 95		assert(node_fracs[i] <= BASIS);
 96		phys_addr_t size = MEM_SIZE * node_fracs[i] / BASIS;
 97
 98		memblock_add_node(base, size, i, flags);
 99		base += size;
100	}
101	fill_memblock();
102}
103
104void dummy_physical_memory_init(void)
105{
106	memory_block.base = malloc(MEM_SIZE);
107	assert(memory_block.base);
108	fill_memblock();
109}
110
111void dummy_physical_memory_cleanup(void)
112{
113	free(memory_block.base);
114}
115
116phys_addr_t dummy_physical_memory_base(void)
117{
118	return (phys_addr_t)memory_block.base;
119}
120
121static void usage(const char *prog)
122{
123	BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1);
124
125	printf("Usage: %s [-%s]\n", prog, short_opts);
126
127	for (int i = 0; long_opts[i].name; i++) {
128		printf("  -%c, --%-12s\t%s\n", long_opts[i].val,
129		       long_opts[i].name, help_opts[i]);
130	}
131
132	exit(1);
133}
134
135void parse_args(int argc, char **argv)
136{
137	int c;
138
139	while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
140				     NULL)) != -1) {
141		switch (c) {
142		case 'm':
143			movable_node_enabled = true;
144			break;
145		case 'v':
146			verbose = 1;
147			break;
148		default:
149			usage(argv[0]);
150		}
151	}
152}
153
154void print_prefixes(const char *postfix)
155{
156	for (int i = 0; i < nr_prefixes; i++)
157		test_print("%s%s", prefixes[i], DELIM);
158	test_print(postfix);
159}
160
161void test_fail(void)
162{
163	if (verbose) {
164		ksft_test_result_fail(": ");
165		print_prefixes("failed\n");
166	}
167}
168
169void test_pass(void)
170{
171	if (verbose) {
172		ksft_test_result_pass(": ");
173		print_prefixes("passed\n");
174	}
175}
176
177void test_print(const char *fmt, ...)
178{
179	if (verbose) {
180		int saved_errno = errno;
181		va_list args;
182
183		va_start(args, fmt);
184		errno = saved_errno;
185		vprintf(fmt, args);
186		va_end(args);
187	}
188}
189
190void prefix_reset(void)
191{
192	memset(prefixes, 0, PREFIXES_MAX * sizeof(char *));
193	nr_prefixes = 0;
194}
195
196void prefix_push(const char *prefix)
197{
198	assert(nr_prefixes < PREFIXES_MAX);
199	prefixes[nr_prefixes] = prefix;
200	nr_prefixes++;
201}
202
203void prefix_pop(void)
204{
205	if (nr_prefixes > 0) {
206		prefixes[nr_prefixes - 1] = 0;
207		nr_prefixes--;
208	}
209}