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} 210