diff options
Diffstat (limited to 'tools/testing/memblock')
| -rw-r--r-- | tools/testing/memblock/linux/mmzone.h | 2 | ||||
| -rw-r--r-- | tools/testing/memblock/scripts/Makefile.include | 2 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/alloc_api.c | 223 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/alloc_helpers_api.c | 52 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/alloc_nid_api.c | 1810 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/alloc_nid_api.h | 16 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/basic_api.c | 767 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/common.c | 42 | ||||
| -rw-r--r-- | tools/testing/memblock/tests/common.h | 86 | 
9 files changed, 2664 insertions, 336 deletions
| diff --git a/tools/testing/memblock/linux/mmzone.h b/tools/testing/memblock/linux/mmzone.h index 7c2eb5c9bb54..e65f89b12f1c 100644 --- a/tools/testing/memblock/linux/mmzone.h +++ b/tools/testing/memblock/linux/mmzone.h @@ -22,6 +22,8 @@ enum zone_type {  #define pageblock_order		(MAX_ORDER - 1)  #define pageblock_nr_pages	BIT(pageblock_order) +#define pageblock_align(pfn)	ALIGN((pfn), pageblock_nr_pages) +#define pageblock_start_pfn(pfn)	ALIGN_DOWN((pfn), pageblock_nr_pages)  struct zone {  	atomic_long_t		managed_pages; diff --git a/tools/testing/memblock/scripts/Makefile.include b/tools/testing/memblock/scripts/Makefile.include index aa6d82d56a23..998281723590 100644 --- a/tools/testing/memblock/scripts/Makefile.include +++ b/tools/testing/memblock/scripts/Makefile.include @@ -3,7 +3,7 @@  # Simulate CONFIG_NUMA=y  ifeq ($(NUMA), 1) -	CFLAGS += -D CONFIG_NUMA +	CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4  endif  # Use 32 bit physical addresses. diff --git a/tools/testing/memblock/tests/alloc_api.c b/tools/testing/memblock/tests/alloc_api.c index a14f38eb8a89..68f1a75cd72c 100644 --- a/tools/testing/memblock/tests/alloc_api.c +++ b/tools/testing/memblock/tests/alloc_api.c @@ -1,6 +1,22 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "alloc_api.h" +static int alloc_test_flags = TEST_F_NONE; + +static inline const char * const get_memblock_alloc_name(int flags) +{ +	if (flags & TEST_F_RAW) +		return "memblock_alloc_raw"; +	return "memblock_alloc"; +} + +static inline void *run_memblock_alloc(phys_addr_t size, phys_addr_t align) +{ +	if (alloc_test_flags & TEST_F_RAW) +		return memblock_alloc_raw(size, align); +	return memblock_alloc(size, align); +} +  /*   * A simple test that tries to allocate a small memory region.   * Expect to allocate an aligned region near the end of the available memory. @@ -9,19 +25,19 @@ static int alloc_top_down_simple_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_2;  	phys_addr_t expected_start; +	PREFIX_PUSH();  	setup_memblock();  	expected_start = memblock_end_of_DRAM() - SMP_CACHE_BYTES; -	allocated_ptr = memblock_alloc(size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, expected_start); @@ -58,15 +74,13 @@ static int alloc_top_down_disjoint_check(void)  	struct memblock_region *rgn2 = &memblock.reserved.regions[0];  	struct region r1;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r2_size = SZ_16;  	/* Use custom alignment */  	phys_addr_t alignment = SMP_CACHE_BYTES * 2;  	phys_addr_t total_size;  	phys_addr_t expected_start; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SZ_2; @@ -77,9 +91,11 @@ static int alloc_top_down_disjoint_check(void)  	memblock_reserve(r1.base, r1.size); -	allocated_ptr = memblock_alloc(r2_size, alignment); +	allocated_ptr = run_memblock_alloc(r2_size, alignment);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r2_size, alloc_test_flags); +  	ASSERT_EQ(rgn1->size, r1.size);  	ASSERT_EQ(rgn1->base, r1.base); @@ -108,9 +124,6 @@ static int alloc_top_down_before_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	/*  	 * The first region ends at the aligned address to test region merging  	 */ @@ -118,13 +131,16 @@ static int alloc_top_down_before_check(void)  	phys_addr_t r2_size = SZ_512;  	phys_addr_t total_size = r1_size + r2_size; +	PREFIX_PUSH();  	setup_memblock();  	memblock_reserve(memblock_end_of_DRAM() - total_size, r1_size); -	allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r2_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - total_size); @@ -152,12 +168,10 @@ static int alloc_top_down_after_check(void)  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	struct region r1;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r2_size = SZ_512;  	phys_addr_t total_size; +	PREFIX_PUSH();  	setup_memblock();  	/* @@ -170,9 +184,11 @@ static int alloc_top_down_after_check(void)  	memblock_reserve(r1.base, r1.size); -	allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r2_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, r1.base - r2_size); @@ -201,12 +217,10 @@ static int alloc_top_down_second_fit_check(void)  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	struct region r1, r2;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_1K;  	phys_addr_t total_size; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SZ_512; @@ -220,9 +234,11 @@ static int alloc_top_down_second_fit_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r3_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, r2.size + r3_size);  	ASSERT_EQ(rgn->base, r2.base - r3_size); @@ -250,9 +266,6 @@ static int alloc_in_between_generic_check(void)  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	struct region r1, r2;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t r3_size = SZ_64;  	/* @@ -261,6 +274,7 @@ static int alloc_in_between_generic_check(void)  	phys_addr_t rgn_size = (MEM_SIZE - (2 * gap_size + r3_size)) / 2;  	phys_addr_t total_size; +	PREFIX_PUSH();  	setup_memblock();  	r1.size = rgn_size; @@ -274,9 +288,11 @@ static int alloc_in_between_generic_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r3_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, r1.base - r2.size - r3_size); @@ -304,13 +320,11 @@ static int alloc_in_between_generic_check(void)  static int alloc_small_gaps_generic_check(void)  {  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t region_size = SZ_1K;  	phys_addr_t gap_size = SZ_256;  	phys_addr_t region_end; +	PREFIX_PUSH();  	setup_memblock();  	region_end = memblock_start_of_DRAM(); @@ -320,7 +334,7 @@ static int alloc_small_gaps_generic_check(void)  		region_end += gap_size + region_size;  	} -	allocated_ptr = memblock_alloc(region_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(region_size, SMP_CACHE_BYTES);  	ASSERT_EQ(allocated_ptr, NULL); @@ -338,13 +352,12 @@ static int alloc_all_reserved_generic_check(void)  	void *allocated_ptr = NULL;  	PREFIX_PUSH(); -  	setup_memblock();  	/* Simulate full memory */  	memblock_reserve(memblock_start_of_DRAM(), MEM_SIZE); -	allocated_ptr = memblock_alloc(SZ_256, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(SZ_256, SMP_CACHE_BYTES);  	ASSERT_EQ(allocated_ptr, NULL); @@ -369,18 +382,16 @@ static int alloc_all_reserved_generic_check(void)  static int alloc_no_space_generic_check(void)  {  	void *allocated_ptr = NULL; +	phys_addr_t available_size = SZ_256; +	phys_addr_t reserved_size = MEM_SIZE - available_size;  	PREFIX_PUSH(); -  	setup_memblock(); -	phys_addr_t available_size = SZ_256; -	phys_addr_t reserved_size = MEM_SIZE - available_size; -  	/* Simulate almost-full memory */  	memblock_reserve(memblock_start_of_DRAM(), reserved_size); -	allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(SZ_1K, SMP_CACHE_BYTES);  	ASSERT_EQ(allocated_ptr, NULL); @@ -404,20 +415,20 @@ static int alloc_limited_space_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t available_size = SZ_256;  	phys_addr_t reserved_size = MEM_SIZE - available_size; +	PREFIX_PUSH();  	setup_memblock();  	/* Simulate almost-full memory */  	memblock_reserve(memblock_start_of_DRAM(), reserved_size); -	allocated_ptr = memblock_alloc(available_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(available_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, available_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, MEM_SIZE);  	ASSERT_EQ(rgn->base, memblock_start_of_DRAM()); @@ -443,7 +454,40 @@ static int alloc_no_memory_generic_check(void)  	reset_memblock_regions(); -	allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(SZ_1K, SMP_CACHE_BYTES); + +	ASSERT_EQ(allocated_ptr, NULL); +	ASSERT_EQ(rgn->size, 0); +	ASSERT_EQ(rgn->base, 0); +	ASSERT_EQ(memblock.reserved.total_size, 0); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a region that is larger than the total size of + * available memory (memblock.memory): + * + *  +-----------------------------------+ + *  |                 new               | + *  +-----------------------------------+ + *  |                                 | + *  |                                 | + *  +---------------------------------+ + * + * Expect no allocation to happen. + */ +static int alloc_too_large_generic_check(void) +{ +	struct memblock_region *rgn = &memblock.reserved.regions[0]; +	void *allocated_ptr = NULL; + +	PREFIX_PUSH(); +	setup_memblock(); + +	allocated_ptr = run_memblock_alloc(MEM_SIZE + SZ_2, SMP_CACHE_BYTES);  	ASSERT_EQ(allocated_ptr, NULL);  	ASSERT_EQ(rgn->size, 0); @@ -466,12 +510,13 @@ static int alloc_bottom_up_simple_check(void)  	void *allocated_ptr = NULL;  	PREFIX_PUSH(); -  	setup_memblock(); -	allocated_ptr = memblock_alloc(SZ_2, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(SZ_2, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, SZ_2, alloc_test_flags); +  	ASSERT_EQ(rgn->size, SZ_2);  	ASSERT_EQ(rgn->base, memblock_start_of_DRAM()); @@ -506,15 +551,13 @@ static int alloc_bottom_up_disjoint_check(void)  	struct memblock_region *rgn2 = &memblock.reserved.regions[1];  	struct region r1;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r2_size = SZ_16;  	/* Use custom alignment */  	phys_addr_t alignment = SMP_CACHE_BYTES * 2;  	phys_addr_t total_size;  	phys_addr_t expected_start; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_start_of_DRAM() + SZ_2; @@ -525,9 +568,10 @@ static int alloc_bottom_up_disjoint_check(void)  	memblock_reserve(r1.base, r1.size); -	allocated_ptr = memblock_alloc(r2_size, alignment); +	allocated_ptr = run_memblock_alloc(r2_size, alignment);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);  	ASSERT_EQ(rgn1->size, r1.size);  	ASSERT_EQ(rgn1->base, r1.base); @@ -557,20 +601,20 @@ static int alloc_bottom_up_before_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_512;  	phys_addr_t r2_size = SZ_128;  	phys_addr_t total_size = r1_size + r2_size; +	PREFIX_PUSH();  	setup_memblock();  	memblock_reserve(memblock_start_of_DRAM() + r1_size, r2_size); -	allocated_ptr = memblock_alloc(r1_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r1_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r1_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, memblock_start_of_DRAM()); @@ -597,12 +641,10 @@ static int alloc_bottom_up_after_check(void)  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	struct region r1;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r2_size = SZ_512;  	phys_addr_t total_size; +	PREFIX_PUSH();  	setup_memblock();  	/* @@ -615,9 +657,11 @@ static int alloc_bottom_up_after_check(void)  	memblock_reserve(r1.base, r1.size); -	allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r2_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, r1.base); @@ -647,12 +691,10 @@ static int alloc_bottom_up_second_fit_check(void)  	struct memblock_region *rgn  = &memblock.reserved.regions[1];  	struct region r1, r2;  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_1K;  	phys_addr_t total_size; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_start_of_DRAM(); @@ -666,9 +708,11 @@ static int alloc_bottom_up_second_fit_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES); +	allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);  	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, r3_size, alloc_test_flags); +  	ASSERT_EQ(rgn->size, r2.size + r3_size);  	ASSERT_EQ(rgn->base, r2.base); @@ -728,10 +772,8 @@ static int alloc_after_check(void)  static int alloc_in_between_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_in_between_generic_check(); -	memblock_set_bottom_up(true); -	alloc_in_between_generic_check(); +	run_top_down(alloc_in_between_generic_check); +	run_bottom_up(alloc_in_between_generic_check);  	return 0;  } @@ -750,10 +792,8 @@ static int alloc_second_fit_check(void)  static int alloc_small_gaps_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_small_gaps_generic_check(); -	memblock_set_bottom_up(true); -	alloc_small_gaps_generic_check(); +	run_top_down(alloc_small_gaps_generic_check); +	run_bottom_up(alloc_small_gaps_generic_check);  	return 0;  } @@ -761,10 +801,8 @@ static int alloc_small_gaps_check(void)  static int alloc_all_reserved_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_all_reserved_generic_check(); -	memblock_set_bottom_up(true); -	alloc_all_reserved_generic_check(); +	run_top_down(alloc_all_reserved_generic_check); +	run_bottom_up(alloc_all_reserved_generic_check);  	return 0;  } @@ -772,10 +810,8 @@ static int alloc_all_reserved_check(void)  static int alloc_no_space_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_no_space_generic_check(); -	memblock_set_bottom_up(true); -	alloc_no_space_generic_check(); +	run_top_down(alloc_no_space_generic_check); +	run_bottom_up(alloc_no_space_generic_check);  	return 0;  } @@ -783,10 +819,8 @@ static int alloc_no_space_check(void)  static int alloc_limited_space_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_limited_space_generic_check(); -	memblock_set_bottom_up(true); -	alloc_limited_space_generic_check(); +	run_top_down(alloc_limited_space_generic_check); +	run_bottom_up(alloc_limited_space_generic_check);  	return 0;  } @@ -794,21 +828,29 @@ static int alloc_limited_space_check(void)  static int alloc_no_memory_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_no_memory_generic_check(); -	memblock_set_bottom_up(true); -	alloc_no_memory_generic_check(); +	run_top_down(alloc_no_memory_generic_check); +	run_bottom_up(alloc_no_memory_generic_check);  	return 0;  } -int memblock_alloc_checks(void) +static int alloc_too_large_check(void)  { -	const char *func_testing = "memblock_alloc"; +	test_print("\tRunning %s...\n", __func__); +	run_top_down(alloc_too_large_generic_check); +	run_bottom_up(alloc_too_large_generic_check); +	return 0; +} + +static int memblock_alloc_checks_internal(int flags) +{ +	const char *func = get_memblock_alloc_name(flags); + +	alloc_test_flags = flags;  	prefix_reset(); -	prefix_push(func_testing); -	test_print("Running %s tests...\n", func_testing); +	prefix_push(func); +	test_print("Running %s tests...\n", func);  	reset_memblock_attributes();  	dummy_physical_memory_init(); @@ -824,6 +866,7 @@ int memblock_alloc_checks(void)  	alloc_no_space_check();  	alloc_limited_space_check();  	alloc_no_memory_check(); +	alloc_too_large_check();  	dummy_physical_memory_cleanup(); @@ -831,3 +874,11 @@ int memblock_alloc_checks(void)  	return 0;  } + +int memblock_alloc_checks(void) +{ +	memblock_alloc_checks_internal(TEST_F_NONE); +	memblock_alloc_checks_internal(TEST_F_RAW); + +	return 0; +} diff --git a/tools/testing/memblock/tests/alloc_helpers_api.c b/tools/testing/memblock/tests/alloc_helpers_api.c index 1069b4bdd5fd..3ef9486da8a0 100644 --- a/tools/testing/memblock/tests/alloc_helpers_api.c +++ b/tools/testing/memblock/tests/alloc_helpers_api.c @@ -19,22 +19,18 @@ static int alloc_from_simple_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_16;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES;  	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr); -	b = (char *)allocated_ptr;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	ASSERT_MEM_EQ(allocated_ptr, 0, size);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, min_addr); @@ -66,23 +62,19 @@ static int alloc_from_misaligned_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_32;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	/* A misaligned address */  	min_addr = memblock_end_of_DRAM() - (SMP_CACHE_BYTES * 2 - 1);  	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr); -	b = (char *)allocated_ptr;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	ASSERT_MEM_EQ(allocated_ptr, 0, size);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES); @@ -117,12 +109,10 @@ static int alloc_from_top_down_high_addr_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_32;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	/* The address is too close to the end of the memory */ @@ -162,14 +152,12 @@ static int alloc_from_top_down_no_space_above_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_64;  	phys_addr_t r2_size = SZ_2;  	phys_addr_t total_size = r1_size + r2_size;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -201,13 +189,11 @@ static int alloc_from_top_down_min_addr_cap_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_64;  	phys_addr_t min_addr;  	phys_addr_t start_addr; +	PREFIX_PUSH();  	setup_memblock();  	start_addr = (phys_addr_t)memblock_start_of_DRAM(); @@ -249,12 +235,10 @@ static int alloc_from_bottom_up_high_addr_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_32;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	/* The address is too close to the end of the memory */ @@ -293,13 +277,11 @@ static int alloc_from_bottom_up_no_space_above_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_64;  	phys_addr_t min_addr;  	phys_addr_t r2_size; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SZ_128; @@ -331,13 +313,11 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_64;  	phys_addr_t min_addr;  	phys_addr_t start_addr; +	PREFIX_PUSH();  	setup_memblock();  	start_addr = (phys_addr_t)memblock_start_of_DRAM(); @@ -361,10 +341,8 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)  static int alloc_from_simple_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_from_simple_generic_check(); -	memblock_set_bottom_up(true); -	alloc_from_simple_generic_check(); +	run_top_down(alloc_from_simple_generic_check); +	run_bottom_up(alloc_from_simple_generic_check);  	return 0;  } @@ -372,10 +350,8 @@ static int alloc_from_simple_check(void)  static int alloc_from_misaligned_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_from_misaligned_generic_check(); -	memblock_set_bottom_up(true); -	alloc_from_misaligned_generic_check(); +	run_top_down(alloc_from_misaligned_generic_check); +	run_bottom_up(alloc_from_misaligned_generic_check);  	return 0;  } diff --git a/tools/testing/memblock/tests/alloc_nid_api.c b/tools/testing/memblock/tests/alloc_nid_api.c index 255fd514e9f5..2c2d60f4e3e3 100644 --- a/tools/testing/memblock/tests/alloc_nid_api.c +++ b/tools/testing/memblock/tests/alloc_nid_api.c @@ -1,6 +1,41 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "alloc_nid_api.h" +static int alloc_nid_test_flags = TEST_F_NONE; + +/* + * contains the fraction of MEM_SIZE contained in each node in basis point + * units (one hundredth of 1% or 1/10000) + */ +static const unsigned int node_fractions[] = { +	2500, /* 1/4  */ +	 625, /* 1/16 */ +	1250, /* 1/8  */ +	1250, /* 1/8  */ +	 625, /* 1/16 */ +	 625, /* 1/16 */ +	2500, /* 1/4  */ +	 625, /* 1/16 */ +}; + +static inline const char * const get_memblock_alloc_try_nid_name(int flags) +{ +	if (flags & TEST_F_RAW) +		return "memblock_alloc_try_nid_raw"; +	return "memblock_alloc_try_nid"; +} + +static inline void *run_memblock_alloc_try_nid(phys_addr_t size, +					       phys_addr_t align, +					       phys_addr_t min_addr, +					       phys_addr_t max_addr, int nid) +{ +	if (alloc_nid_test_flags & TEST_F_RAW) +		return memblock_alloc_try_nid_raw(size, align, min_addr, +						  max_addr, nid); +	return memblock_alloc_try_nid(size, align, min_addr, max_addr, nid); +} +  /*   * A simple test that tries to allocate a memory region within min_addr and   * max_addr range: @@ -13,33 +48,30 @@   *        |                   |   *        min_addr           max_addr   * - * Expect to allocate a cleared region that ends at max_addr. + * Expect to allocate a region that ends at max_addr.   */  static int alloc_try_nid_top_down_simple_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_128;  	phys_addr_t min_addr;  	phys_addr_t max_addr;  	phys_addr_t rgn_end; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;  	max_addr = min_addr + SZ_512; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	rgn_end = rgn->base + rgn->size;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, max_addr - size); @@ -68,34 +100,31 @@ static int alloc_try_nid_top_down_simple_check(void)   *                 Aligned address   *                 boundary   * - * Expect to allocate a cleared, aligned region that ends before max_addr. + * Expect to allocate an aligned region that ends before max_addr.   */  static int alloc_try_nid_top_down_end_misaligned_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_128;  	phys_addr_t misalign = SZ_2;  	phys_addr_t min_addr;  	phys_addr_t max_addr;  	phys_addr_t rgn_end; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;  	max_addr = min_addr + SZ_512 + misalign; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	rgn_end = rgn->base + rgn->size;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, max_addr - size - misalign); @@ -121,34 +150,31 @@ static int alloc_try_nid_top_down_end_misaligned_check(void)   *         |               |   *         min_addr        max_addr   * - * Expect to allocate a cleared region that starts at min_addr and ends at + * Expect to allocate a region that starts at min_addr and ends at   * max_addr, given that min_addr is aligned.   */  static int alloc_try_nid_exact_address_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_1K;  	phys_addr_t min_addr;  	phys_addr_t max_addr;  	phys_addr_t rgn_end; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES;  	max_addr = min_addr + size; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	rgn_end = rgn->base + rgn->size;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, min_addr); @@ -176,32 +202,29 @@ static int alloc_try_nid_exact_address_generic_check(void)   *           address    |   *           boundary   min_add   * - * Expect to drop the lower limit and allocate a cleared memory region which + * Expect to drop the lower limit and allocate a memory region which   * ends at max_addr (if the address is aligned).   */  static int alloc_try_nid_top_down_narrow_range_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_256;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SZ_512;  	max_addr = min_addr + SMP_CACHE_BYTES; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, max_addr - size); @@ -237,20 +260,19 @@ static int alloc_try_nid_top_down_narrow_range_check(void)  static int alloc_try_nid_low_max_generic_check(void)  {  	void *allocated_ptr = NULL; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_1K;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM();  	max_addr = min_addr + SMP_CACHE_BYTES; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_EQ(allocated_ptr, NULL); @@ -277,10 +299,6 @@ static int alloc_try_nid_min_reserved_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_128;  	phys_addr_t r2_size = SZ_64;  	phys_addr_t total_size = r1_size + r2_size; @@ -288,6 +306,7 @@ static int alloc_try_nid_min_reserved_generic_check(void)  	phys_addr_t max_addr;  	phys_addr_t reserved_base; +	PREFIX_PUSH();  	setup_memblock();  	max_addr = memblock_end_of_DRAM(); @@ -296,12 +315,12 @@ static int alloc_try_nid_min_reserved_generic_check(void)  	memblock_reserve(reserved_base, r1_size); -	allocated_ptr = memblock_alloc_try_nid(r2_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r2_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r2_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, reserved_base); @@ -332,16 +351,13 @@ static int alloc_try_nid_max_reserved_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t r1_size = SZ_64;  	phys_addr_t r2_size = SZ_128;  	phys_addr_t total_size = r1_size + r2_size;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	max_addr = memblock_end_of_DRAM() - r1_size; @@ -349,12 +365,12 @@ static int alloc_try_nid_max_reserved_generic_check(void)  	memblock_reserve(max_addr, r1_size); -	allocated_ptr = memblock_alloc_try_nid(r2_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r2_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r2_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, min_addr); @@ -389,17 +405,14 @@ static int alloc_try_nid_top_down_reserved_with_space_check(void)  	struct memblock_region *rgn1 = &memblock.reserved.regions[1];  	struct memblock_region *rgn2 = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_64;  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t total_size;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -415,12 +428,12 @@ static int alloc_try_nid_top_down_reserved_with_space_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r3_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn1->size, r1.size + r3_size);  	ASSERT_EQ(rgn1->base, max_addr - r3_size); @@ -456,16 +469,13 @@ static int alloc_try_nid_reserved_full_merge_generic_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_64;  	phys_addr_t total_size;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -481,12 +491,12 @@ static int alloc_try_nid_reserved_full_merge_generic_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r3_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, total_size);  	ASSERT_EQ(rgn->base, r2.base); @@ -522,17 +532,14 @@ static int alloc_try_nid_top_down_reserved_no_space_check(void)  	struct memblock_region *rgn1 = &memblock.reserved.regions[1];  	struct memblock_region *rgn2 = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_256;  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t total_size;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -548,12 +555,12 @@ static int alloc_try_nid_top_down_reserved_no_space_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r3_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn1->size, r1.size);  	ASSERT_EQ(rgn1->base, r1.base); @@ -593,14 +600,12 @@ static int alloc_try_nid_reserved_all_generic_check(void)  {  	void *allocated_ptr = NULL;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_256;  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES; @@ -615,8 +620,9 @@ static int alloc_try_nid_reserved_all_generic_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_EQ(allocated_ptr, NULL); @@ -628,31 +634,28 @@ static int alloc_try_nid_reserved_all_generic_check(void)  /*   * A test that tries to allocate a memory region, where max_addr is   * bigger than the end address of the available memory. Expect to allocate - * a cleared region that ends before the end of the memory. + * a region that ends before the end of the memory.   */  static int alloc_try_nid_top_down_cap_max_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_256;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_end_of_DRAM() - SZ_1K;  	max_addr = memblock_end_of_DRAM() + SZ_256; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size); @@ -668,31 +671,28 @@ static int alloc_try_nid_top_down_cap_max_check(void)  /*   * A test that tries to allocate a memory region, where min_addr is   * smaller than the start address of the available memory. Expect to allocate - * a cleared region that ends before the end of the memory. + * a region that ends before the end of the memory.   */  static int alloc_try_nid_top_down_cap_min_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_1K;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() - SZ_256;  	max_addr = memblock_end_of_DRAM(); -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - size); @@ -717,34 +717,30 @@ static int alloc_try_nid_top_down_cap_min_check(void)   *        |                       |   *        min_addr                max_addr   * - * Expect to allocate a cleared region that ends before max_addr. + * Expect to allocate a region that ends before max_addr.   */  static int alloc_try_nid_bottom_up_simple_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_128;  	phys_addr_t min_addr;  	phys_addr_t max_addr;  	phys_addr_t rgn_end; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SMP_CACHE_BYTES * 2;  	max_addr = min_addr + SZ_512; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	rgn_end = rgn->base + rgn->size;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, min_addr); @@ -773,35 +769,31 @@ static int alloc_try_nid_bottom_up_simple_check(void)   *                 Aligned address   *                 boundary   * - * Expect to allocate a cleared, aligned region that ends before max_addr. + * Expect to allocate an aligned region that ends before max_addr.   */  static int alloc_try_nid_bottom_up_start_misaligned_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_128;  	phys_addr_t misalign = SZ_2;  	phys_addr_t min_addr;  	phys_addr_t max_addr;  	phys_addr_t rgn_end; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + misalign;  	max_addr = min_addr + SZ_512; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	rgn_end = rgn->base + rgn->size;  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, min_addr + (SMP_CACHE_BYTES - misalign)); @@ -829,33 +821,29 @@ static int alloc_try_nid_bottom_up_start_misaligned_check(void)   *                      |   *                      min_add   * - * Expect to drop the lower limit and allocate a cleared memory region which + * Expect to drop the lower limit and allocate a memory region which   * starts at the beginning of the available memory.   */  static int alloc_try_nid_bottom_up_narrow_range_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_256;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SZ_512;  	max_addr = min_addr + SMP_CACHE_BYTES; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, memblock_start_of_DRAM()); @@ -890,17 +878,14 @@ static int alloc_try_nid_bottom_up_reserved_with_space_check(void)  	struct memblock_region *rgn1 = &memblock.reserved.regions[1];  	struct memblock_region *rgn2 = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_64;  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t total_size;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -916,13 +901,12 @@ static int alloc_try_nid_bottom_up_reserved_with_space_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r3_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn1->size, r1.size);  	ASSERT_EQ(rgn1->base, max_addr); @@ -964,17 +948,14 @@ static int alloc_try_nid_bottom_up_reserved_no_space_check(void)  	struct memblock_region *rgn2 = &memblock.reserved.regions[1];  	struct memblock_region *rgn3 = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b;  	struct region r1, r2; - -	PREFIX_PUSH(); -  	phys_addr_t r3_size = SZ_256;  	phys_addr_t gap_size = SMP_CACHE_BYTES;  	phys_addr_t total_size;  	phys_addr_t max_addr;  	phys_addr_t min_addr; +	PREFIX_PUSH();  	setup_memblock();  	r1.base = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2; @@ -990,13 +971,12 @@ static int alloc_try_nid_bottom_up_reserved_no_space_check(void)  	memblock_reserve(r1.base, r1.size);  	memblock_reserve(r2.base, r2.size); -	allocated_ptr = memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(r3_size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, r3_size, alloc_nid_test_flags);  	ASSERT_EQ(rgn3->size, r3_size);  	ASSERT_EQ(rgn3->base, memblock_start_of_DRAM()); @@ -1018,32 +998,28 @@ static int alloc_try_nid_bottom_up_reserved_no_space_check(void)  /*   * A test that tries to allocate a memory region, where max_addr is   * bigger than the end address of the available memory. Expect to allocate - * a cleared region that starts at the min_addr + * a region that starts at the min_addr.   */  static int alloc_try_nid_bottom_up_cap_max_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_256;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM() + SZ_1K;  	max_addr = memblock_end_of_DRAM() + SZ_256; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, min_addr); @@ -1059,32 +1035,28 @@ static int alloc_try_nid_bottom_up_cap_max_check(void)  /*   * A test that tries to allocate a memory region, where min_addr is   * smaller than the start address of the available memory. Expect to allocate - * a cleared region at the beginning of the available memory. + * a region at the beginning of the available memory.   */  static int alloc_try_nid_bottom_up_cap_min_check(void)  {  	struct memblock_region *rgn = &memblock.reserved.regions[0];  	void *allocated_ptr = NULL; -	char *b; - -	PREFIX_PUSH(); -  	phys_addr_t size = SZ_1K;  	phys_addr_t min_addr;  	phys_addr_t max_addr; +	PREFIX_PUSH();  	setup_memblock();  	min_addr = memblock_start_of_DRAM();  	max_addr = memblock_end_of_DRAM() - SZ_256; -	allocated_ptr = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, -					       min_addr, max_addr, -					       NUMA_NO_NODE); -	b = (char *)allocated_ptr; +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE);  	ASSERT_NE(allocated_ptr, NULL); -	ASSERT_EQ(*b, 0); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags);  	ASSERT_EQ(rgn->size, size);  	ASSERT_EQ(rgn->base, memblock_start_of_DRAM()); @@ -1097,7 +1069,7 @@ static int alloc_try_nid_bottom_up_cap_min_check(void)  	return 0;  } -/* Test case wrappers */ +/* Test case wrappers for range tests */  static int alloc_try_nid_simple_check(void)  {  	test_print("\tRunning %s...\n", __func__); @@ -1178,10 +1150,8 @@ static int alloc_try_nid_cap_min_check(void)  static int alloc_try_nid_min_reserved_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_min_reserved_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_min_reserved_generic_check(); +	run_top_down(alloc_try_nid_min_reserved_generic_check); +	run_bottom_up(alloc_try_nid_min_reserved_generic_check);  	return 0;  } @@ -1189,10 +1159,8 @@ static int alloc_try_nid_min_reserved_check(void)  static int alloc_try_nid_max_reserved_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_max_reserved_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_max_reserved_generic_check(); +	run_top_down(alloc_try_nid_max_reserved_generic_check); +	run_bottom_up(alloc_try_nid_max_reserved_generic_check);  	return 0;  } @@ -1200,10 +1168,8 @@ static int alloc_try_nid_max_reserved_check(void)  static int alloc_try_nid_exact_address_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_exact_address_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_exact_address_generic_check(); +	run_top_down(alloc_try_nid_exact_address_generic_check); +	run_bottom_up(alloc_try_nid_exact_address_generic_check);  	return 0;  } @@ -1211,10 +1177,8 @@ static int alloc_try_nid_exact_address_check(void)  static int alloc_try_nid_reserved_full_merge_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_reserved_full_merge_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_reserved_full_merge_generic_check(); +	run_top_down(alloc_try_nid_reserved_full_merge_generic_check); +	run_bottom_up(alloc_try_nid_reserved_full_merge_generic_check);  	return 0;  } @@ -1222,10 +1186,8 @@ static int alloc_try_nid_reserved_full_merge_check(void)  static int alloc_try_nid_reserved_all_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_reserved_all_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_reserved_all_generic_check(); +	run_top_down(alloc_try_nid_reserved_all_generic_check); +	run_bottom_up(alloc_try_nid_reserved_all_generic_check);  	return 0;  } @@ -1233,24 +1195,16 @@ static int alloc_try_nid_reserved_all_check(void)  static int alloc_try_nid_low_max_check(void)  {  	test_print("\tRunning %s...\n", __func__); -	memblock_set_bottom_up(false); -	alloc_try_nid_low_max_generic_check(); -	memblock_set_bottom_up(true); -	alloc_try_nid_low_max_generic_check(); +	run_top_down(alloc_try_nid_low_max_generic_check); +	run_bottom_up(alloc_try_nid_low_max_generic_check);  	return 0;  } -int memblock_alloc_nid_checks(void) +static int memblock_alloc_nid_range_checks(void)  { -	const char *func_testing = "memblock_alloc_try_nid"; - -	prefix_reset(); -	prefix_push(func_testing); -	test_print("Running %s tests...\n", func_testing); - -	reset_memblock_attributes(); -	dummy_physical_memory_init(); +	test_print("Running %s range tests...\n", +		   get_memblock_alloc_try_nid_name(alloc_nid_test_flags));  	alloc_try_nid_simple_check();  	alloc_try_nid_misaligned_check(); @@ -1267,9 +1221,1453 @@ int memblock_alloc_nid_checks(void)  	alloc_try_nid_reserved_all_check();  	alloc_try_nid_low_max_check(); +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * has enough memory to allocate a region of the requested size. + * Expect to allocate an aligned region at the end of the requested node. + */ +static int alloc_try_nid_top_down_numa_simple_check(void) +{ +	int nid_req = 3; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_4, req_node->size); +	size = req_node->size / SZ_4; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(req_node) - size); +	ASSERT_LE(req_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * does not have enough memory to allocate a region of the requested size: + * + *  |   +-----+          +------------------+     | + *  |   | req |          |     expected     |     | + *  +---+-----+----------+------------------+-----+ + * + *  |                             +---------+     | + *  |                             |   rgn   |     | + *  +-----------------------------+---------+-----+ + * + * Expect to allocate an aligned region at the end of the last node that has + * enough memory (in this case, nid = 6) after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_top_down_numa_small_node_check(void) +{ +	int nid_req = 1; +	int nid_exp = 6; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = SZ_2 * req_node->size; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(exp_node) - size); +	ASSERT_LE(exp_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is fully reserved: + * + *  |              +---------+            +------------------+     | + *  |              |requested|            |     expected     |     | + *  +--------------+---------+------------+------------------+-----+ + * + *  |              +---------+                     +---------+     | + *  |              | reserved|                     |   new   |     | + *  +--------------+---------+---------------------+---------+-----+ + * + * Expect to allocate an aligned region at the end of the last node that is + * large enough and has enough unreserved memory (in this case, nid = 6) after + * falling back to NUMA_NO_NODE. The region count and total size get updated. + */ +static int alloc_try_nid_top_down_numa_node_reserved_check(void) +{ +	int nid_req = 2; +	int nid_exp = 6; +	struct memblock_region *new_rgn = &memblock.reserved.regions[1]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = req_node->size; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	memblock_reserve(req_node->base, req_node->size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(exp_node) - size); +	ASSERT_LE(exp_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, size + req_node->size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is partially reserved but has enough memory for the allocated region: + * + *  |           +---------------------------------------+          | + *  |           |               requested               |          | + *  +-----------+---------------------------------------+----------+ + * + *  |           +------------------+              +-----+          | + *  |           |     reserved     |              | new |          | + *  +-----------+------------------+--------------+-----+----------+ + * + * Expect to allocate an aligned region at the end of the requested node. The + * region count and total size get updated. + */ +static int alloc_try_nid_top_down_numa_part_reserved_check(void) +{ +	int nid_req = 4; +	struct memblock_region *new_rgn = &memblock.reserved.regions[1]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	struct region r1; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_8, req_node->size); +	r1.base = req_node->base; +	r1.size = req_node->size / SZ_2; +	size = r1.size / SZ_4; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	memblock_reserve(r1.base, r1.size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(req_node) - size); +	ASSERT_LE(req_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, size + r1.size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is partially reserved and does not have enough contiguous memory for the + * allocated region: + * + *  |           +-----------------------+         +----------------------| + *  |           |       requested       |         |       expected       | + *  +-----------+-----------------------+---------+----------------------+ + * + *  |                 +----------+                           +-----------| + *  |                 | reserved |                           |    new    | + *  +-----------------+----------+---------------------------+-----------+ + * + * Expect to allocate an aligned region at the end of the last node that is + * large enough and has enough unreserved memory (in this case, + * nid = NUMA_NODES - 1) after falling back to NUMA_NO_NODE. The region count + * and total size get updated. + */ +static int alloc_try_nid_top_down_numa_part_reserved_fallback_check(void) +{ +	int nid_req = 4; +	int nid_exp = NUMA_NODES - 1; +	struct memblock_region *new_rgn = &memblock.reserved.regions[1]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	struct region r1; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_4, req_node->size); +	size = req_node->size / SZ_2; +	r1.base = req_node->base + (size / SZ_2); +	r1.size = size; + +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	memblock_reserve(r1.base, r1.size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(exp_node) - size); +	ASSERT_LE(exp_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, size + r1.size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the first + * node is the requested node: + * + *                                min_addr + *                                |           max_addr + *                                |           | + *                                v           v + *  |           +-----------------------+-----------+              | + *  |           |       requested       |   node3   |              | + *  +-----------+-----------------------+-----------+--------------+ + *                                +           + + *  |                       +-----------+                          | + *  |                       |    rgn    |                          | + *  +-----------------------+-----------+--------------------------+ + * + * Expect to drop the lower limit and allocate a memory region that ends at + * the end of the requested node. + */ +static int alloc_try_nid_top_down_numa_split_range_low_check(void) +{ +	int nid_req = 2; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_512; +	phys_addr_t min_addr; +	phys_addr_t max_addr; +	phys_addr_t req_node_end; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	req_node_end = region_end(req_node); +	min_addr = req_node_end - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, req_node_end - size); +	ASSERT_LE(req_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the second + * node is the requested node: + * + *                               min_addr + *                               |         max_addr + *                               |         | + *                               v         v + *  |      +--------------------------+---------+                | + *  |      |         expected         |requested|                | + *  +------+--------------------------+---------+----------------+ + *                               +         + + *  |                       +---------+                          | + *  |                       |   rgn   |                          | + *  +-----------------------+---------+--------------------------+ + * + * Expect to drop the lower limit and allocate a memory region that + * ends at the end of the first node that overlaps with the range. + */ +static int alloc_try_nid_top_down_numa_split_range_high_check(void) +{ +	int nid_req = 3; +	int nid_exp = nid_req - 1; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_512; +	phys_addr_t min_addr; +	phys_addr_t max_addr; +	phys_addr_t exp_node_end; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	exp_node_end = region_end(exp_node); +	min_addr = exp_node_end - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, exp_node_end - size); +	ASSERT_LE(exp_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the requested + * node ends before min_addr: + * + *                                         min_addr + *                                         |         max_addr + *                                         |         | + *                                         v         v + *  |    +---------------+        +-------------+---------+          | + *  |    |   requested   |        |    node1    |  node2  |          | + *  +----+---------------+--------+-------------+---------+----------+ + *                                         +         + + *  |          +---------+                                           | + *  |          |   rgn   |                                           | + *  +----------+---------+-------------------------------------------+ + * + * Expect to drop the lower limit and allocate a memory region that ends at + * the end of the requested node. + */ +static int alloc_try_nid_top_down_numa_no_overlap_split_check(void) +{ +	int nid_req = 2; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *node2 = &memblock.memory.regions[6]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = SZ_512; +	min_addr = node2->base - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, region_end(req_node) - size); +	ASSERT_LE(req_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_add range when + * the requested node and the range do not overlap, and requested node ends + * before min_addr. The range overlaps with multiple nodes along node + * boundaries: + * + *                          min_addr + *                          |                                 max_addr + *                          |                                 | + *                          v                                 v + *  |-----------+           +----------+----...----+----------+      | + *  | requested |           | min node |    ...    | max node |      | + *  +-----------+-----------+----------+----...----+----------+------+ + *                          +                                 + + *  |                                                   +-----+      | + *  |                                                   | rgn |      | + *  +---------------------------------------------------+-----+------+ + * + * Expect to allocate a memory region at the end of the final node in + * the range after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_top_down_numa_no_overlap_low_check(void) +{ +	int nid_req = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *min_node = &memblock.memory.regions[2]; +	struct memblock_region *max_node = &memblock.memory.regions[5]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_64; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	min_addr = min_node->base; +	max_addr = region_end(max_node); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, max_addr - size); +	ASSERT_LE(max_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_add range when + * the requested node and the range do not overlap, and requested node starts + * after max_addr. The range overlaps with multiple nodes along node + * boundaries: + * + *        min_addr + *        |                                 max_addr + *        |                                 | + *        v                                 v + *  |     +----------+----...----+----------+        +-----------+   | + *  |     | min node |    ...    | max node |        | requested |   | + *  +-----+----------+----...----+----------+--------+-----------+---+ + *        +                                 + + *  |                                 +-----+                        | + *  |                                 | rgn |                        | + *  +---------------------------------+-----+------------------------+ + * + * Expect to allocate a memory region at the end of the final node in + * the range after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_top_down_numa_no_overlap_high_check(void) +{ +	int nid_req = 7; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *min_node = &memblock.memory.regions[2]; +	struct memblock_region *max_node = &memblock.memory.regions[5]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_64; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	min_addr = min_node->base; +	max_addr = region_end(max_node); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, max_addr - size); +	ASSERT_LE(max_node->base, new_rgn->base); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * has enough memory to allocate a region of the requested size. + * Expect to allocate an aligned region at the beginning of the requested node. + */ +static int alloc_try_nid_bottom_up_numa_simple_check(void) +{ +	int nid_req = 3; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_4, req_node->size); +	size = req_node->size / SZ_4; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, req_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(req_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * does not have enough memory to allocate a region of the requested size: + * + *  |----------------------+-----+                | + *  |       expected       | req |                | + *  +----------------------+-----+----------------+ + * + *  |---------+                                   | + *  |   rgn   |                                   | + *  +---------+-----------------------------------+ + * + * Expect to allocate an aligned region at the beginning of the first node that + * has enough memory (in this case, nid = 0) after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_bottom_up_numa_small_node_check(void) +{ +	int nid_req = 1; +	int nid_exp = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = SZ_2 * req_node->size; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, exp_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(exp_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is fully reserved: + * + *  |----------------------+     +-----------+                    | + *  |       expected       |     | requested |                    | + *  +----------------------+-----+-----------+--------------------+ + * + *  |-----------+                +-----------+                    | + *  |    new    |                |  reserved |                    | + *  +-----------+----------------+-----------+--------------------+ + * + * Expect to allocate an aligned region at the beginning of the first node that + * is large enough and has enough unreserved memory (in this case, nid = 0) + * after falling back to NUMA_NO_NODE. The region count and total size get + * updated. + */ +static int alloc_try_nid_bottom_up_numa_node_reserved_check(void) +{ +	int nid_req = 2; +	int nid_exp = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = req_node->size; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	memblock_reserve(req_node->base, req_node->size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, exp_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(exp_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, size + req_node->size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is partially reserved but has enough memory for the allocated region: + * + *  |           +---------------------------------------+         | + *  |           |               requested               |         | + *  +-----------+---------------------------------------+---------+ + * + *  |           +------------------+-----+                        | + *  |           |     reserved     | new |                        | + *  +-----------+------------------+-----+------------------------+ + * + * Expect to allocate an aligned region in the requested node that merges with + * the existing reserved region. The total size gets updated. + */ +static int alloc_try_nid_bottom_up_numa_part_reserved_check(void) +{ +	int nid_req = 4; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	struct region r1; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; +	phys_addr_t total_size; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_8, req_node->size); +	r1.base = req_node->base; +	r1.size = req_node->size / SZ_2; +	size = r1.size / SZ_4; +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); +	total_size = size + r1.size; + +	memblock_reserve(r1.base, r1.size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, total_size); +	ASSERT_EQ(new_rgn->base, req_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(req_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * is partially reserved and does not have enough contiguous memory for the + * allocated region: + * + *  |----------------------+       +-----------------------+         | + *  |       expected       |       |       requested       |         | + *  +----------------------+-------+-----------------------+---------+ + * + *  |-----------+                        +----------+                | + *  |    new    |                        | reserved |                | + *  +-----------+------------------------+----------+----------------+ + * + * Expect to allocate an aligned region at the beginning of the first + * node that is large enough and has enough unreserved memory (in this case, + * nid = 0) after falling back to NUMA_NO_NODE. The region count and total size + * get updated. + */ +static int alloc_try_nid_bottom_up_numa_part_reserved_fallback_check(void) +{ +	int nid_req = 4; +	int nid_exp = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	struct region r1; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	ASSERT_LE(SZ_4, req_node->size); +	size = req_node->size / SZ_2; +	r1.base = req_node->base + (size / SZ_2); +	r1.size = size; + +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	memblock_reserve(r1.base, r1.size); +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, exp_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(exp_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, size + r1.size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the first + * node is the requested node: + * + *                                min_addr + *                                |           max_addr + *                                |           | + *                                v           v + *  |           +-----------------------+-----------+              | + *  |           |       requested       |   node3   |              | + *  +-----------+-----------------------+-----------+--------------+ + *                                +           + + *  |           +-----------+                                      | + *  |           |    rgn    |                                      | + *  +-----------+-----------+--------------------------------------+ + * + * Expect to drop the lower limit and allocate a memory region at the beginning + * of the requested node. + */ +static int alloc_try_nid_bottom_up_numa_split_range_low_check(void) +{ +	int nid_req = 2; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_512; +	phys_addr_t min_addr; +	phys_addr_t max_addr; +	phys_addr_t req_node_end; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	req_node_end = region_end(req_node); +	min_addr = req_node_end - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, req_node->base); +	ASSERT_LE(region_end(new_rgn), req_node_end); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the second + * node is the requested node: + * + *                                                min_addr + *                                                |         max_addr + *                                                |         | + *                                                v         v + *  |------------------+        +----------------------+---------+      | + *  |     expected     |        |       previous       |requested|      | + *  +------------------+--------+----------------------+---------+------+ + *                                                +         + + *  |---------+                                                         | + *  |   rgn   |                                                         | + *  +---------+---------------------------------------------------------+ + * + * Expect to drop the lower limit and allocate a memory region at the beginning + * of the first node that has enough memory. + */ +static int alloc_try_nid_bottom_up_numa_split_range_high_check(void) +{ +	int nid_req = 3; +	int nid_exp = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *exp_node = &memblock.memory.regions[nid_exp]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_512; +	phys_addr_t min_addr; +	phys_addr_t max_addr; +	phys_addr_t exp_node_end; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	exp_node_end = region_end(req_node); +	min_addr = req_node->base - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, exp_node->base); +	ASSERT_LE(region_end(new_rgn), exp_node_end); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region that spans over the min_addr + * and max_addr range and overlaps with two different nodes, where the requested + * node ends before min_addr: + * + *                                          min_addr + *                                         |         max_addr + *                                         |         | + *                                         v         v + *  |    +---------------+        +-------------+---------+         | + *  |    |   requested   |        |    node1    |  node2  |         | + *  +----+---------------+--------+-------------+---------+---------+ + *                                         +         + + *  |    +---------+                                                | + *  |    |   rgn   |                                                | + *  +----+---------+------------------------------------------------+ + * + * Expect to drop the lower limit and allocate a memory region that starts at + * the beginning of the requested node. + */ +static int alloc_try_nid_bottom_up_numa_no_overlap_split_check(void) +{ +	int nid_req = 2; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *node2 = &memblock.memory.regions[6]; +	void *allocated_ptr = NULL; +	phys_addr_t size; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	size = SZ_512; +	min_addr = node2->base - SZ_256; +	max_addr = min_addr + size; + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, req_node->base); +	ASSERT_LE(region_end(new_rgn), region_end(req_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_add range when + * the requested node and the range do not overlap, and requested node ends + * before min_addr. The range overlaps with multiple nodes along node + * boundaries: + * + *                          min_addr + *                          |                                 max_addr + *                          |                                 | + *                          v                                 v + *  |-----------+           +----------+----...----+----------+      | + *  | requested |           | min node |    ...    | max node |      | + *  +-----------+-----------+----------+----...----+----------+------+ + *                          +                                 + + *  |                       +-----+                                  | + *  |                       | rgn |                                  | + *  +-----------------------+-----+----------------------------------+ + * + * Expect to allocate a memory region at the beginning of the first node + * in the range after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_bottom_up_numa_no_overlap_low_check(void) +{ +	int nid_req = 0; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *min_node = &memblock.memory.regions[2]; +	struct memblock_region *max_node = &memblock.memory.regions[5]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_64; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	min_addr = min_node->base; +	max_addr = region_end(max_node); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, min_addr); +	ASSERT_LE(region_end(new_rgn), region_end(min_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_add range when + * the requested node and the range do not overlap, and requested node starts + * after max_addr. The range overlaps with multiple nodes along node + * boundaries: + * + *        min_addr + *        |                                 max_addr + *        |                                 | + *        v                                 v + *  |     +----------+----...----+----------+         +---------+   | + *  |     | min node |    ...    | max node |         |requested|   | + *  +-----+----------+----...----+----------+---------+---------+---+ + *        +                                 + + *  |     +-----+                                                   | + *  |     | rgn |                                                   | + *  +-----+-----+---------------------------------------------------+ + * + * Expect to allocate a memory region at the beginning of the first node + * in the range after falling back to NUMA_NO_NODE. + */ +static int alloc_try_nid_bottom_up_numa_no_overlap_high_check(void) +{ +	int nid_req = 7; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *min_node = &memblock.memory.regions[2]; +	struct memblock_region *max_node = &memblock.memory.regions[5]; +	void *allocated_ptr = NULL; +	phys_addr_t size = SZ_64; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	min_addr = min_node->base; +	max_addr = region_end(max_node); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, size); +	ASSERT_EQ(new_rgn->base, min_addr); +	ASSERT_LE(region_end(new_rgn), region_end(min_node)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate a memory region in a specific NUMA node that + * does not have enough memory to allocate a region of the requested size. + * Additionally, none of the nodes have enough memory to allocate the region: + * + * +-----------------------------------+ + * |                new                | + * +-----------------------------------+ + *     |-------+-------+-------+-------+-------+-------+-------+-------| + *     | node0 | node1 | node2 | node3 | node4 | node5 | node6 | node7 | + *     +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * Expect no allocation to happen. + */ +static int alloc_try_nid_numa_large_region_generic_check(void) +{ +	int nid_req = 3; +	void *allocated_ptr = NULL; +	phys_addr_t size = MEM_SIZE / SZ_2; +	phys_addr_t min_addr; +	phys_addr_t max_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	min_addr = memblock_start_of_DRAM(); +	max_addr = memblock_end_of_DRAM(); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); +	ASSERT_EQ(allocated_ptr, NULL); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_addr range when + * there are two reserved regions at the borders. The requested node starts at + * min_addr and ends at max_addr and is the same size as the region to be + * allocated: + * + *                     min_addr + *                     |                       max_addr + *                     |                       | + *                     v                       v + *  |      +-----------+-----------------------+-----------------------| + *  |      |   node5   |       requested       |         node7         | + *  +------+-----------+-----------------------+-----------------------+ + *                     +                       + + *  |             +----+-----------------------+----+                  | + *  |             | r2 |          new          | r1 |                  | + *  +-------------+----+-----------------------+----+------------------+ + * + * Expect to merge all of the regions into one. The region counter and total + * size fields get updated. + */ +static int alloc_try_nid_numa_reserved_full_merge_generic_check(void) +{ +	int nid_req = 6; +	int nid_next = nid_req + 1; +	struct memblock_region *new_rgn = &memblock.reserved.regions[0]; +	struct memblock_region *req_node = &memblock.memory.regions[nid_req]; +	struct memblock_region *next_node = &memblock.memory.regions[nid_next]; +	void *allocated_ptr = NULL; +	struct region r1, r2; +	phys_addr_t size = req_node->size; +	phys_addr_t total_size; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	r1.base = next_node->base; +	r1.size = SZ_128; + +	r2.size = SZ_128; +	r2.base = r1.base - (size + r2.size); + +	total_size = r1.size + r2.size + size; +	min_addr = r2.base + r2.size; +	max_addr = r1.base; + +	memblock_reserve(r1.base, r1.size); +	memblock_reserve(r2.base, r2.size); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, nid_req); + +	ASSERT_NE(allocated_ptr, NULL); +	assert_mem_content(allocated_ptr, size, alloc_nid_test_flags); + +	ASSERT_EQ(new_rgn->size, total_size); +	ASSERT_EQ(new_rgn->base, r2.base); + +	ASSERT_LE(new_rgn->base, req_node->base); +	ASSERT_LE(region_end(req_node), region_end(new_rgn)); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to allocate memory within min_addr and max_add range, + * where the total range can fit the region, but it is split between two nodes + * and everything else is reserved. Additionally, nid is set to NUMA_NO_NODE + * instead of requesting a specific node: + * + *                         +-----------+ + *                         |    new    | + *                         +-----------+ + *  |      +---------------------+-----------| + *  |      |      prev node      | next node | + *  +------+---------------------+-----------+ + *                         +           + + *  |----------------------+           +-----| + *  |          r1          |           |  r2 | + *  +----------------------+-----------+-----+ + *                         ^           ^ + *                         |           | + *                         |           max_addr + *                         | + *                         min_addr + * + * Expect no allocation to happen. + */ +static int alloc_try_nid_numa_split_all_reserved_generic_check(void) +{ +	void *allocated_ptr = NULL; +	struct memblock_region *next_node = &memblock.memory.regions[7]; +	struct region r1, r2; +	phys_addr_t size = SZ_256; +	phys_addr_t max_addr; +	phys_addr_t min_addr; + +	PREFIX_PUSH(); +	setup_numa_memblock(node_fractions); + +	r2.base = next_node->base + SZ_128; +	r2.size = memblock_end_of_DRAM() - r2.base; + +	r1.size = MEM_SIZE - (r2.size + size); +	r1.base = memblock_start_of_DRAM(); + +	min_addr = r1.base + r1.size; +	max_addr = r2.base; + +	memblock_reserve(r1.base, r1.size); +	memblock_reserve(r2.base, r2.size); + +	allocated_ptr = run_memblock_alloc_try_nid(size, SMP_CACHE_BYTES, +						   min_addr, max_addr, +						   NUMA_NO_NODE); + +	ASSERT_EQ(allocated_ptr, NULL); + +	test_pass_pop(); + +	return 0; +} + +/* Test case wrappers for NUMA tests */ +static int alloc_try_nid_numa_simple_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_simple_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_simple_check(); + +	return 0; +} + +static int alloc_try_nid_numa_small_node_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_small_node_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_small_node_check(); + +	return 0; +} + +static int alloc_try_nid_numa_node_reserved_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_node_reserved_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_node_reserved_check(); + +	return 0; +} + +static int alloc_try_nid_numa_part_reserved_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_part_reserved_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_part_reserved_check(); + +	return 0; +} + +static int alloc_try_nid_numa_part_reserved_fallback_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_part_reserved_fallback_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_part_reserved_fallback_check(); + +	return 0; +} + +static int alloc_try_nid_numa_split_range_low_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_split_range_low_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_split_range_low_check(); + +	return 0; +} + +static int alloc_try_nid_numa_split_range_high_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_split_range_high_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_split_range_high_check(); + +	return 0; +} + +static int alloc_try_nid_numa_no_overlap_split_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_no_overlap_split_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_no_overlap_split_check(); + +	return 0; +} + +static int alloc_try_nid_numa_no_overlap_low_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_no_overlap_low_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_no_overlap_low_check(); + +	return 0; +} + +static int alloc_try_nid_numa_no_overlap_high_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	memblock_set_bottom_up(false); +	alloc_try_nid_top_down_numa_no_overlap_high_check(); +	memblock_set_bottom_up(true); +	alloc_try_nid_bottom_up_numa_no_overlap_high_check(); + +	return 0; +} + +static int alloc_try_nid_numa_large_region_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	run_top_down(alloc_try_nid_numa_large_region_generic_check); +	run_bottom_up(alloc_try_nid_numa_large_region_generic_check); + +	return 0; +} + +static int alloc_try_nid_numa_reserved_full_merge_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	run_top_down(alloc_try_nid_numa_reserved_full_merge_generic_check); +	run_bottom_up(alloc_try_nid_numa_reserved_full_merge_generic_check); + +	return 0; +} + +static int alloc_try_nid_numa_split_all_reserved_check(void) +{ +	test_print("\tRunning %s...\n", __func__); +	run_top_down(alloc_try_nid_numa_split_all_reserved_generic_check); +	run_bottom_up(alloc_try_nid_numa_split_all_reserved_generic_check); + +	return 0; +} + +int __memblock_alloc_nid_numa_checks(void) +{ +	test_print("Running %s NUMA tests...\n", +		   get_memblock_alloc_try_nid_name(alloc_nid_test_flags)); + +	alloc_try_nid_numa_simple_check(); +	alloc_try_nid_numa_small_node_check(); +	alloc_try_nid_numa_node_reserved_check(); +	alloc_try_nid_numa_part_reserved_check(); +	alloc_try_nid_numa_part_reserved_fallback_check(); +	alloc_try_nid_numa_split_range_low_check(); +	alloc_try_nid_numa_split_range_high_check(); + +	alloc_try_nid_numa_no_overlap_split_check(); +	alloc_try_nid_numa_no_overlap_low_check(); +	alloc_try_nid_numa_no_overlap_high_check(); +	alloc_try_nid_numa_large_region_check(); +	alloc_try_nid_numa_reserved_full_merge_check(); +	alloc_try_nid_numa_split_all_reserved_check(); + +	return 0; +} + +static int memblock_alloc_nid_checks_internal(int flags) +{ +	alloc_nid_test_flags = flags; + +	prefix_reset(); +	prefix_push(get_memblock_alloc_try_nid_name(flags)); + +	reset_memblock_attributes(); +	dummy_physical_memory_init(); + +	memblock_alloc_nid_range_checks(); +	memblock_alloc_nid_numa_checks(); +  	dummy_physical_memory_cleanup();  	prefix_pop();  	return 0;  } + +int memblock_alloc_nid_checks(void) +{ +	memblock_alloc_nid_checks_internal(TEST_F_NONE); +	memblock_alloc_nid_checks_internal(TEST_F_RAW); + +	return 0; +} diff --git a/tools/testing/memblock/tests/alloc_nid_api.h b/tools/testing/memblock/tests/alloc_nid_api.h index b35cf3c3f489..92d07d230e18 100644 --- a/tools/testing/memblock/tests/alloc_nid_api.h +++ b/tools/testing/memblock/tests/alloc_nid_api.h @@ -5,5 +5,21 @@  #include "common.h"  int memblock_alloc_nid_checks(void); +int __memblock_alloc_nid_numa_checks(void); + +#ifdef CONFIG_NUMA +static inline int memblock_alloc_nid_numa_checks(void) +{ +	__memblock_alloc_nid_numa_checks(); +	return 0; +} + +#else +static inline int memblock_alloc_nid_numa_checks(void) +{ +	return 0; +} + +#endif /* CONFIG_NUMA */  #endif diff --git a/tools/testing/memblock/tests/basic_api.c b/tools/testing/memblock/tests/basic_api.c index 66f46f261e66..a13a57ba0815 100644 --- a/tools/testing/memblock/tests/basic_api.c +++ b/tools/testing/memblock/tests/basic_api.c @@ -8,6 +8,7 @@  #define FUNC_RESERVE					"memblock_reserve"  #define FUNC_REMOVE					"memblock_remove"  #define FUNC_FREE					"memblock_free" +#define FUNC_TRIM					"memblock_trim_memory"  static int memblock_initialization_check(void)  { @@ -326,6 +327,102 @@ static int memblock_add_twice_check(void)  	return 0;  } +/* + * A test that tries to add two memory blocks that don't overlap with one + * another and then add a third memory block in the space between the first two: + * + *  |        +--------+--------+--------+  | + *  |        |   r1   |   r3   |   r2   |  | + *  +--------+--------+--------+--------+--+ + * + * Expect to merge the three entries into one region that starts at r1.base + * and has size of r1.size + r2.size + r3.size. The region counter and total + * size of the available memory are updated. + */ +static int memblock_add_between_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.memory.regions[0]; + +	struct region r1 = { +		.base = SZ_1G, +		.size = SZ_8K +	}; +	struct region r2 = { +		.base = SZ_1G + SZ_16K, +		.size = SZ_8K +	}; +	struct region r3 = { +		.base = SZ_1G + SZ_8K, +		.size = SZ_8K +	}; + +	PREFIX_PUSH(); + +	total_size = r1.size + r2.size + r3.size; + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_add(r2.base, r2.size); +	memblock_add(r3.base, r3.size); + +	ASSERT_EQ(rgn->base, r1.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.memory.cnt, 1); +	ASSERT_EQ(memblock.memory.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A simple test that tries to add a memory block r when r extends past + * PHYS_ADDR_MAX: + * + *                               +--------+ + *                               |    r   | + *                               +--------+ + *  |                            +----+ + *  |                            | rgn| + *  +----------------------------+----+ + * + * Expect to add a memory block of size PHYS_ADDR_MAX - r.base. Expect the + * total size of available memory and the counter to be updated. + */ +static int memblock_add_near_max_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.memory.regions[0]; + +	struct region r = { +		.base = PHYS_ADDR_MAX - SZ_1M, +		.size = SZ_2M +	}; + +	PREFIX_PUSH(); + +	total_size = PHYS_ADDR_MAX - r.base; + +	reset_memblock_regions(); +	memblock_add(r.base, r.size); + +	ASSERT_EQ(rgn->base, r.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.memory.cnt, 1); +	ASSERT_EQ(memblock.memory.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} +  static int memblock_add_checks(void)  {  	prefix_reset(); @@ -339,6 +436,8 @@ static int memblock_add_checks(void)  	memblock_add_overlap_bottom_check();  	memblock_add_within_check();  	memblock_add_twice_check(); +	memblock_add_between_check(); +	memblock_add_near_max_check();  	prefix_pop(); @@ -604,6 +703,102 @@ static int memblock_reserve_twice_check(void)  	return 0;  } +/* + * A test that tries to mark two memory blocks that don't overlap as reserved + * and then reserve a third memory block in the space between the first two: + * + *  |        +--------+--------+--------+  | + *  |        |   r1   |   r3   |   r2   |  | + *  +--------+--------+--------+--------+--+ + * + * Expect to merge the three entries into one reserved region that starts at + * r1.base and has size of r1.size + r2.size + r3.size. The region counter and + * total for memblock.reserved are updated. + */ +static int memblock_reserve_between_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.reserved.regions[0]; + +	struct region r1 = { +		.base = SZ_1G, +		.size = SZ_8K +	}; +	struct region r2 = { +		.base = SZ_1G + SZ_16K, +		.size = SZ_8K +	}; +	struct region r3 = { +		.base = SZ_1G + SZ_8K, +		.size = SZ_8K +	}; + +	PREFIX_PUSH(); + +	total_size = r1.size + r2.size + r3.size; + +	reset_memblock_regions(); +	memblock_reserve(r1.base, r1.size); +	memblock_reserve(r2.base, r2.size); +	memblock_reserve(r3.base, r3.size); + +	ASSERT_EQ(rgn->base, r1.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A simple test that tries to reserve a memory block r when r extends past + * PHYS_ADDR_MAX: + * + *                               +--------+ + *                               |    r   | + *                               +--------+ + *  |                            +----+ + *  |                            | rgn| + *  +----------------------------+----+ + * + * Expect to reserve a memory block of size PHYS_ADDR_MAX - r.base. Expect the + * total size of reserved memory and the counter to be updated. + */ +static int memblock_reserve_near_max_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.reserved.regions[0]; + +	struct region r = { +		.base = PHYS_ADDR_MAX - SZ_1M, +		.size = SZ_2M +	}; + +	PREFIX_PUSH(); + +	total_size = PHYS_ADDR_MAX - r.base; + +	reset_memblock_regions(); +	memblock_reserve(r.base, r.size); + +	ASSERT_EQ(rgn->base, r.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} +  static int memblock_reserve_checks(void)  {  	prefix_reset(); @@ -616,6 +811,8 @@ static int memblock_reserve_checks(void)  	memblock_reserve_overlap_bottom_check();  	memblock_reserve_within_check();  	memblock_reserve_twice_check(); +	memblock_reserve_between_check(); +	memblock_reserve_near_max_check();  	prefix_pop(); @@ -887,6 +1084,155 @@ static int memblock_remove_within_check(void)  	return 0;  } +/* + * A simple test that tries to remove a region r1 from the array of + * available memory regions when r1 is the only available region. + * Expect to add a memory block r1 and then remove r1 so that a dummy + * region is added. The region counter stays the same, and the total size + * is updated. + */ +static int memblock_remove_only_region_check(void) +{ +	struct memblock_region *rgn; + +	rgn = &memblock.memory.regions[0]; + +	struct region r1 = { +		.base = SZ_2K, +		.size = SZ_4K +	}; + +	PREFIX_PUSH(); + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_remove(r1.base, r1.size); + +	ASSERT_EQ(rgn->base, 0); +	ASSERT_EQ(rgn->size, 0); + +	ASSERT_EQ(memblock.memory.cnt, 1); +	ASSERT_EQ(memblock.memory.total_size, 0); + +	test_pass_pop(); + +	return 0; +} + +/* + * A simple test that tries remove a region r2 from the array of available + * memory regions when r2 extends past PHYS_ADDR_MAX: + * + *                               +--------+ + *                               |   r2   | + *                               +--------+ + *  |                        +---+....+ + *  |                        |rgn|    | + *  +------------------------+---+----+ + * + * Expect that only the portion between PHYS_ADDR_MAX and r2.base is removed. + * Expect the total size of available memory to be updated and the counter to + * not be updated. + */ +static int memblock_remove_near_max_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.memory.regions[0]; + +	struct region r1 = { +		.base = PHYS_ADDR_MAX - SZ_2M, +		.size = SZ_2M +	}; + +	struct region r2 = { +		.base = PHYS_ADDR_MAX - SZ_1M, +		.size = SZ_2M +	}; + +	PREFIX_PUSH(); + +	total_size = r1.size - (PHYS_ADDR_MAX - r2.base); + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_remove(r2.base, r2.size); + +	ASSERT_EQ(rgn->base, r1.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.memory.cnt, 1); +	ASSERT_EQ(memblock.memory.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to remove a region r3 that overlaps with two existing + * regions r1 and r2: + * + *            +----------------+ + *            |       r3       | + *            +----------------+ + *  |    +----+.....   ........+--------+ + *  |    |    |r1  :   :       |r2      |     | + *  +----+----+----+---+-------+--------+-----+ + * + * Expect that only the intersections of r1 with r3 and r2 with r3 are removed + * from the available memory pool. Expect the total size of available memory to + * be updated and the counter to not be updated. + */ +static int memblock_remove_overlap_two_check(void) +{ +	struct memblock_region *rgn1, *rgn2; +	phys_addr_t new_r1_size, new_r2_size, r2_end, r3_end, total_size; + +	rgn1 = &memblock.memory.regions[0]; +	rgn2 = &memblock.memory.regions[1]; + +	struct region r1 = { +		.base = SZ_16M, +		.size = SZ_32M +	}; +	struct region r2 = { +		.base = SZ_64M, +		.size = SZ_64M +	}; +	struct region r3 = { +		.base = SZ_32M, +		.size = SZ_64M +	}; + +	PREFIX_PUSH(); + +	r2_end = r2.base + r2.size; +	r3_end = r3.base + r3.size; +	new_r1_size = r3.base - r1.base; +	new_r2_size = r2_end - r3_end; +	total_size = new_r1_size + new_r2_size; + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_add(r2.base, r2.size); +	memblock_remove(r3.base, r3.size); + +	ASSERT_EQ(rgn1->base, r1.base); +	ASSERT_EQ(rgn1->size, new_r1_size); + +	ASSERT_EQ(rgn2->base, r3_end); +	ASSERT_EQ(rgn2->size, new_r2_size); + +	ASSERT_EQ(memblock.memory.cnt, 2); +	ASSERT_EQ(memblock.memory.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} +  static int memblock_remove_checks(void)  {  	prefix_reset(); @@ -898,6 +1244,9 @@ static int memblock_remove_checks(void)  	memblock_remove_overlap_top_check();  	memblock_remove_overlap_bottom_check();  	memblock_remove_within_check(); +	memblock_remove_only_region_check(); +	memblock_remove_near_max_check(); +	memblock_remove_overlap_two_check();  	prefix_pop(); @@ -1163,6 +1512,154 @@ static int memblock_free_within_check(void)  	return 0;  } +/* + * A simple test that tries to free a memory block r1 that was marked + * earlier as reserved when r1 is the only available region. + * Expect to reserve a memory block r1 and then free r1 so that r1 is + * overwritten with a dummy region. The region counter stays the same, + * and the total size is updated. + */ +static int memblock_free_only_region_check(void) +{ +	struct memblock_region *rgn; + +	rgn = &memblock.reserved.regions[0]; + +	struct region r1 = { +		.base = SZ_2K, +		.size = SZ_4K +	}; + +	PREFIX_PUSH(); + +	reset_memblock_regions(); +	memblock_reserve(r1.base, r1.size); +	memblock_free((void *)r1.base, r1.size); + +	ASSERT_EQ(rgn->base, 0); +	ASSERT_EQ(rgn->size, 0); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, 0); + +	test_pass_pop(); + +	return 0; +} + +/* + * A simple test that tries free a region r2 when r2 extends past PHYS_ADDR_MAX: + * + *                               +--------+ + *                               |   r2   | + *                               +--------+ + *  |                        +---+....+ + *  |                        |rgn|    | + *  +------------------------+---+----+ + * + * Expect that only the portion between PHYS_ADDR_MAX and r2.base is freed. + * Expect the total size of reserved memory to be updated and the counter to + * not be updated. + */ +static int memblock_free_near_max_check(void) +{ +	struct memblock_region *rgn; +	phys_addr_t total_size; + +	rgn = &memblock.reserved.regions[0]; + +	struct region r1 = { +		.base = PHYS_ADDR_MAX - SZ_2M, +		.size = SZ_2M +	}; + +	struct region r2 = { +		.base = PHYS_ADDR_MAX - SZ_1M, +		.size = SZ_2M +	}; + +	PREFIX_PUSH(); + +	total_size = r1.size - (PHYS_ADDR_MAX - r2.base); + +	reset_memblock_regions(); +	memblock_reserve(r1.base, r1.size); +	memblock_free((void *)r2.base, r2.size); + +	ASSERT_EQ(rgn->base, r1.base); +	ASSERT_EQ(rgn->size, total_size); + +	ASSERT_EQ(memblock.reserved.cnt, 1); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to free a reserved region r3 that overlaps with two + * existing reserved regions r1 and r2: + * + *            +----------------+ + *            |       r3       | + *            +----------------+ + *  |    +----+.....   ........+--------+ + *  |    |    |r1  :   :       |r2      |     | + *  +----+----+----+---+-------+--------+-----+ + * + * Expect that only the intersections of r1 with r3 and r2 with r3 are freed + * from the collection of reserved memory. Expect the total size of reserved + * memory to be updated and the counter to not be updated. + */ +static int memblock_free_overlap_two_check(void) +{ +	struct memblock_region *rgn1, *rgn2; +	phys_addr_t new_r1_size, new_r2_size, r2_end, r3_end, total_size; + +	rgn1 = &memblock.reserved.regions[0]; +	rgn2 = &memblock.reserved.regions[1]; + +	struct region r1 = { +		.base = SZ_16M, +		.size = SZ_32M +	}; +	struct region r2 = { +		.base = SZ_64M, +		.size = SZ_64M +	}; +	struct region r3 = { +		.base = SZ_32M, +		.size = SZ_64M +	}; + +	PREFIX_PUSH(); + +	r2_end = r2.base + r2.size; +	r3_end = r3.base + r3.size; +	new_r1_size = r3.base - r1.base; +	new_r2_size = r2_end - r3_end; +	total_size = new_r1_size + new_r2_size; + +	reset_memblock_regions(); +	memblock_reserve(r1.base, r1.size); +	memblock_reserve(r2.base, r2.size); +	memblock_free((void *)r3.base, r3.size); + +	ASSERT_EQ(rgn1->base, r1.base); +	ASSERT_EQ(rgn1->size, new_r1_size); + +	ASSERT_EQ(rgn2->base, r3_end); +	ASSERT_EQ(rgn2->size, new_r2_size); + +	ASSERT_EQ(memblock.reserved.cnt, 2); +	ASSERT_EQ(memblock.reserved.total_size, total_size); + +	test_pass_pop(); + +	return 0; +} +  static int memblock_free_checks(void)  {  	prefix_reset(); @@ -1174,6 +1671,274 @@ static int memblock_free_checks(void)  	memblock_free_overlap_top_check();  	memblock_free_overlap_bottom_check();  	memblock_free_within_check(); +	memblock_free_only_region_check(); +	memblock_free_near_max_check(); +	memblock_free_overlap_two_check(); + +	prefix_pop(); + +	return 0; +} + +static int memblock_set_bottom_up_check(void) +{ +	prefix_push("memblock_set_bottom_up"); + +	memblock_set_bottom_up(false); +	ASSERT_EQ(memblock.bottom_up, false); +	memblock_set_bottom_up(true); +	ASSERT_EQ(memblock.bottom_up, true); + +	reset_memblock_attributes(); +	test_pass_pop(); + +	return 0; +} + +static int memblock_bottom_up_check(void) +{ +	prefix_push("memblock_bottom_up"); + +	memblock_set_bottom_up(false); +	ASSERT_EQ(memblock_bottom_up(), memblock.bottom_up); +	ASSERT_EQ(memblock_bottom_up(), false); +	memblock_set_bottom_up(true); +	ASSERT_EQ(memblock_bottom_up(), memblock.bottom_up); +	ASSERT_EQ(memblock_bottom_up(), true); + +	reset_memblock_attributes(); +	test_pass_pop(); + +	return 0; +} + +static int memblock_bottom_up_checks(void) +{ +	test_print("Running memblock_*bottom_up tests...\n"); + +	prefix_reset(); +	memblock_set_bottom_up_check(); +	prefix_reset(); +	memblock_bottom_up_check(); + +	return 0; +} + +/* + * A test that tries to trim memory when both ends of the memory region are + * aligned. Expect that the memory will not be trimmed. Expect the counter to + * not be updated. + */ +static int memblock_trim_memory_aligned_check(void) +{ +	struct memblock_region *rgn; +	const phys_addr_t alignment = SMP_CACHE_BYTES; + +	rgn = &memblock.memory.regions[0]; + +	struct region r = { +		.base = alignment, +		.size = alignment * 4 +	}; + +	PREFIX_PUSH(); + +	reset_memblock_regions(); +	memblock_add(r.base, r.size); +	memblock_trim_memory(alignment); + +	ASSERT_EQ(rgn->base, r.base); +	ASSERT_EQ(rgn->size, r.size); + +	ASSERT_EQ(memblock.memory.cnt, 1); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to trim memory when there are two available regions, r1 and + * r2. Region r1 is aligned on both ends and region r2 is unaligned on one end + * and smaller than the alignment: + * + *                                     alignment + *                                     |--------| + * |        +-----------------+        +------+   | + * |        |        r1       |        |  r2  |   | + * +--------+-----------------+--------+------+---+ + *          ^        ^        ^        ^      ^ + *          |________|________|________|      | + *                            |               Unaligned address + *                Aligned addresses + * + * Expect that r1 will not be trimmed and r2 will be removed. Expect the + * counter to be updated. + */ +static int memblock_trim_memory_too_small_check(void) +{ +	struct memblock_region *rgn; +	const phys_addr_t alignment = SMP_CACHE_BYTES; + +	rgn = &memblock.memory.regions[0]; + +	struct region r1 = { +		.base = alignment, +		.size = alignment * 2 +	}; +	struct region r2 = { +		.base = alignment * 4, +		.size = alignment - SZ_2 +	}; + +	PREFIX_PUSH(); + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_add(r2.base, r2.size); +	memblock_trim_memory(alignment); + +	ASSERT_EQ(rgn->base, r1.base); +	ASSERT_EQ(rgn->size, r1.size); + +	ASSERT_EQ(memblock.memory.cnt, 1); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to trim memory when there are two available regions, r1 and + * r2. Region r1 is aligned on both ends and region r2 is unaligned at the base + * and aligned at the end: + * + *                               Unaligned address + *                                       | + *                                       v + * |        +-----------------+          +---------------+   | + * |        |        r1       |          |      r2       |   | + * +--------+-----------------+----------+---------------+---+ + *          ^        ^        ^        ^        ^        ^ + *          |________|________|________|________|________| + *                            | + *                    Aligned addresses + * + * Expect that r1 will not be trimmed and r2 will be trimmed at the base. + * Expect the counter to not be updated. + */ +static int memblock_trim_memory_unaligned_base_check(void) +{ +	struct memblock_region *rgn1, *rgn2; +	const phys_addr_t alignment = SMP_CACHE_BYTES; +	phys_addr_t offset = SZ_2; +	phys_addr_t new_r2_base, new_r2_size; + +	rgn1 = &memblock.memory.regions[0]; +	rgn2 = &memblock.memory.regions[1]; + +	struct region r1 = { +		.base = alignment, +		.size = alignment * 2 +	}; +	struct region r2 = { +		.base = alignment * 4 + offset, +		.size = alignment * 2 - offset +	}; + +	PREFIX_PUSH(); + +	new_r2_base = r2.base + (alignment - offset); +	new_r2_size = r2.size - (alignment - offset); + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_add(r2.base, r2.size); +	memblock_trim_memory(alignment); + +	ASSERT_EQ(rgn1->base, r1.base); +	ASSERT_EQ(rgn1->size, r1.size); + +	ASSERT_EQ(rgn2->base, new_r2_base); +	ASSERT_EQ(rgn2->size, new_r2_size); + +	ASSERT_EQ(memblock.memory.cnt, 2); + +	test_pass_pop(); + +	return 0; +} + +/* + * A test that tries to trim memory when there are two available regions, r1 and + * r2. Region r1 is aligned on both ends and region r2 is aligned at the base + * and unaligned at the end: + * + *                                             Unaligned address + *                                                     | + *                                                     v + * |        +-----------------+        +---------------+   | + * |        |        r1       |        |      r2       |   | + * +--------+-----------------+--------+---------------+---+ + *          ^        ^        ^        ^        ^        ^ + *          |________|________|________|________|________| + *                            | + *                    Aligned addresses + * + * Expect that r1 will not be trimmed and r2 will be trimmed at the end. + * Expect the counter to not be updated. + */ +static int memblock_trim_memory_unaligned_end_check(void) +{ +	struct memblock_region *rgn1, *rgn2; +	const phys_addr_t alignment = SMP_CACHE_BYTES; +	phys_addr_t offset = SZ_2; +	phys_addr_t new_r2_size; + +	rgn1 = &memblock.memory.regions[0]; +	rgn2 = &memblock.memory.regions[1]; + +	struct region r1 = { +		.base = alignment, +		.size = alignment * 2 +	}; +	struct region r2 = { +		.base = alignment * 4, +		.size = alignment * 2 - offset +	}; + +	PREFIX_PUSH(); + +	new_r2_size = r2.size - (alignment - offset); + +	reset_memblock_regions(); +	memblock_add(r1.base, r1.size); +	memblock_add(r2.base, r2.size); +	memblock_trim_memory(alignment); + +	ASSERT_EQ(rgn1->base, r1.base); +	ASSERT_EQ(rgn1->size, r1.size); + +	ASSERT_EQ(rgn2->base, r2.base); +	ASSERT_EQ(rgn2->size, new_r2_size); + +	ASSERT_EQ(memblock.memory.cnt, 2); + +	test_pass_pop(); + +	return 0; +} + +static int memblock_trim_memory_checks(void) +{ +	prefix_reset(); +	prefix_push(FUNC_TRIM); +	test_print("Running %s tests...\n", FUNC_TRIM); + +	memblock_trim_memory_aligned_check(); +	memblock_trim_memory_too_small_check(); +	memblock_trim_memory_unaligned_base_check(); +	memblock_trim_memory_unaligned_end_check();  	prefix_pop(); @@ -1187,6 +1952,8 @@ int memblock_basic_checks(void)  	memblock_reserve_checks();  	memblock_remove_checks();  	memblock_free_checks(); +	memblock_bottom_up_checks(); +	memblock_trim_memory_checks();  	return 0;  } diff --git a/tools/testing/memblock/tests/common.c b/tools/testing/memblock/tests/common.c index e43b2676af81..3f795047bbe1 100644 --- a/tools/testing/memblock/tests/common.c +++ b/tools/testing/memblock/tests/common.c @@ -9,19 +9,22 @@  #define INIT_MEMBLOCK_RESERVED_REGIONS		INIT_MEMBLOCK_REGIONS  #define PREFIXES_MAX				15  #define DELIM					": " +#define BASIS					10000  static struct test_memory memory_block;  static const char __maybe_unused *prefixes[PREFIXES_MAX];  static int __maybe_unused nr_prefixes; -static const char *short_opts = "mv"; +static const char *short_opts = "hmv";  static const struct option long_opts[] = { +	{"help", 0, NULL, 'h'},  	{"movable-node", 0, NULL, 'm'},  	{"verbose", 0, NULL, 'v'},  	{NULL, 0, NULL, 0}  };  static const char * const help_opts[] = { +	"display this help message and exit",  	"disallow allocations from regions marked as hotplugged\n\t\t\t"  		"by simulating enabling the \"movable_node\" kernel\n\t\t\t"  		"parameter", @@ -58,16 +61,53 @@ void reset_memblock_attributes(void)  	memblock.current_limit	= MEMBLOCK_ALLOC_ANYWHERE;  } +static inline void fill_memblock(void) +{ +	memset(memory_block.base, 1, MEM_SIZE); +} +  void setup_memblock(void)  {  	reset_memblock_regions();  	memblock_add((phys_addr_t)memory_block.base, MEM_SIZE); +	fill_memblock(); +} + +/** + * setup_numa_memblock: + * Set up a memory layout with multiple NUMA nodes in a previously allocated + * dummy physical memory. + * @node_fracs: an array representing the fraction of MEM_SIZE contained in + *              each node in basis point units (one hundredth of 1% or 1/10000). + *              For example, if node 0 should contain 1/8 of MEM_SIZE, + *              node_fracs[0] = 1250. + * + * The nids will be set to 0 through NUMA_NODES - 1. + */ +void setup_numa_memblock(const unsigned int node_fracs[]) +{ +	phys_addr_t base; +	int flags; + +	reset_memblock_regions(); +	base = (phys_addr_t)memory_block.base; +	flags = (movable_node_is_enabled()) ? MEMBLOCK_NONE : MEMBLOCK_HOTPLUG; + +	for (int i = 0; i < NUMA_NODES; i++) { +		assert(node_fracs[i] <= BASIS); +		phys_addr_t size = MEM_SIZE * node_fracs[i] / BASIS; + +		memblock_add_node(base, size, i, flags); +		base += size; +	} +	fill_memblock();  }  void dummy_physical_memory_init(void)  {  	memory_block.base = malloc(MEM_SIZE);  	assert(memory_block.base); +	fill_memblock();  }  void dummy_physical_memory_cleanup(void) diff --git a/tools/testing/memblock/tests/common.h b/tools/testing/memblock/tests/common.h index 3e7f23d341d7..d6bbbe63bfc3 100644 --- a/tools/testing/memblock/tests/common.h +++ b/tools/testing/memblock/tests/common.h @@ -10,13 +10,22 @@  #include <linux/printk.h>  #include <../selftests/kselftest.h> -#define MEM_SIZE SZ_16K +#define MEM_SIZE		SZ_16K +#define NUMA_NODES		8 + +enum test_flags { +	/* No special request. */ +	TEST_F_NONE = 0x0, +	/* Perform raw allocations (no zeroing of memory). */ +	TEST_F_RAW = 0x1, +};  /**   * ASSERT_EQ():   * Check the condition   * @_expected == @_seen - * If false, print failed test message (if in VERBOSE mode) and then assert + * If false, print failed test message (if running with --verbose) and then + * assert.   */  #define ASSERT_EQ(_expected, _seen) do { \  	if ((_expected) != (_seen)) \ @@ -28,7 +37,8 @@   * ASSERT_NE():   * Check the condition   * @_expected != @_seen - * If false, print failed test message (if in VERBOSE mode) and then assert + * If false, print failed test message (if running with --verbose) and then + * assert.   */  #define ASSERT_NE(_expected, _seen) do { \  	if ((_expected) == (_seen)) \ @@ -40,7 +50,8 @@   * ASSERT_LT():   * Check the condition   * @_expected < @_seen - * If false, print failed test message (if in VERBOSE mode) and then assert + * If false, print failed test message (if running with --verbose) and then + * assert.   */  #define ASSERT_LT(_expected, _seen) do { \  	if ((_expected) >= (_seen)) \ @@ -48,6 +59,43 @@  	assert((_expected) < (_seen)); \  } while (0) +/** + * ASSERT_LE(): + * Check the condition + * @_expected <= @_seen + * If false, print failed test message (if running with --verbose) and then + * assert. + */ +#define ASSERT_LE(_expected, _seen) do { \ +	if ((_expected) > (_seen)) \ +		test_fail(); \ +	assert((_expected) <= (_seen)); \ +} while (0) + +/** + * ASSERT_MEM_EQ(): + * Check that the first @_size bytes of @_seen are all equal to @_expected. + * If false, print failed test message (if running with --verbose) and then + * assert. + */ +#define ASSERT_MEM_EQ(_seen, _expected, _size) do { \ +	for (int _i = 0; _i < (_size); _i++) { \ +		ASSERT_EQ(((char *)_seen)[_i], (_expected)); \ +	} \ +} while (0) + +/** + * ASSERT_MEM_NE(): + * Check that none of the first @_size bytes of @_seen are equal to @_expected. + * If false, print failed test message (if running with --verbose) and then + * assert. + */ +#define ASSERT_MEM_NE(_seen, _expected, _size) do { \ +	for (int _i = 0; _i < (_size); _i++) { \ +		ASSERT_NE(((char *)_seen)[_i], (_expected)); \ +	} \ +} while (0) +  #define PREFIX_PUSH() prefix_push(__func__)  /* @@ -65,9 +113,15 @@ struct region {  	phys_addr_t size;  }; +static inline phys_addr_t __maybe_unused region_end(struct memblock_region *rgn) +{ +	return rgn->base + rgn->size; +} +  void reset_memblock_regions(void);  void reset_memblock_attributes(void);  void setup_memblock(void); +void setup_numa_memblock(const unsigned int node_fracs[]);  void dummy_physical_memory_init(void);  void dummy_physical_memory_cleanup(void);  void parse_args(int argc, char **argv); @@ -85,4 +139,28 @@ static inline void test_pass_pop(void)  	prefix_pop();  } +static inline void run_top_down(int (*func)()) +{ +	memblock_set_bottom_up(false); +	prefix_push("top-down"); +	func(); +	prefix_pop(); +} + +static inline void run_bottom_up(int (*func)()) +{ +	memblock_set_bottom_up(true); +	prefix_push("bottom-up"); +	func(); +	prefix_pop(); +} + +static inline void assert_mem_content(void *mem, int size, int flags) +{ +	if (flags & TEST_F_RAW) +		ASSERT_MEM_NE(mem, 0, size); +	else +		ASSERT_MEM_EQ(mem, 0, size); +} +  #endif |