xref: /linux/drivers/gpu/tests/gpu_buddy_test.c (revision 5ea5b6ff0d63aef1dc3fb25445acea183f61a934)
14a9671a0SJoel Fernandes // SPDX-License-Identifier: MIT
24a9671a0SJoel Fernandes /*
34a9671a0SJoel Fernandes  * Copyright © 2019 Intel Corporation
44a9671a0SJoel Fernandes  * Copyright © 2022 Maíra Canal <mairacanal@riseup.net>
54a9671a0SJoel Fernandes  */
64a9671a0SJoel Fernandes 
74a9671a0SJoel Fernandes #include <kunit/test.h>
84a9671a0SJoel Fernandes 
94a9671a0SJoel Fernandes #include <linux/prime_numbers.h>
104a9671a0SJoel Fernandes #include <linux/sched/signal.h>
114a9671a0SJoel Fernandes #include <linux/sizes.h>
124a9671a0SJoel Fernandes 
134a9671a0SJoel Fernandes #include <linux/gpu_buddy.h>
144a9671a0SJoel Fernandes 
154a9671a0SJoel Fernandes #include "gpu_random.h"
164a9671a0SJoel Fernandes 
174a9671a0SJoel Fernandes static unsigned int random_seed;
184a9671a0SJoel Fernandes 
194a9671a0SJoel Fernandes static inline u64 get_size(int order, u64 chunk_size)
204a9671a0SJoel Fernandes {
214a9671a0SJoel Fernandes 	return (1 << order) * chunk_size;
224a9671a0SJoel Fernandes }
234a9671a0SJoel Fernandes 
24ba110db8SJoel Fernandes static void gpu_test_buddy_fragmentation_performance(struct kunit *test)
254a9671a0SJoel Fernandes {
26ba110db8SJoel Fernandes 	struct gpu_buddy_block *block, *tmp;
274a9671a0SJoel Fernandes 	int num_blocks, i, ret, count = 0;
284a9671a0SJoel Fernandes 	LIST_HEAD(allocated_blocks);
294a9671a0SJoel Fernandes 	unsigned long elapsed_ms;
304a9671a0SJoel Fernandes 	LIST_HEAD(reverse_list);
314a9671a0SJoel Fernandes 	LIST_HEAD(test_blocks);
324a9671a0SJoel Fernandes 	LIST_HEAD(clear_list);
334a9671a0SJoel Fernandes 	LIST_HEAD(dirty_list);
344a9671a0SJoel Fernandes 	LIST_HEAD(free_list);
35ba110db8SJoel Fernandes 	struct gpu_buddy mm;
364a9671a0SJoel Fernandes 	u64 mm_size = SZ_4G;
374a9671a0SJoel Fernandes 	ktime_t start, end;
384a9671a0SJoel Fernandes 
394a9671a0SJoel Fernandes 	/*
404a9671a0SJoel Fernandes 	 * Allocation under severe fragmentation
414a9671a0SJoel Fernandes 	 *
424a9671a0SJoel Fernandes 	 * Create severe fragmentation by allocating the entire 4 GiB address space
434a9671a0SJoel Fernandes 	 * as tiny 8 KiB blocks but forcing a 64 KiB alignment. The resulting pattern
444a9671a0SJoel Fernandes 	 * leaves many scattered holes. Split the allocations into two groups and
454a9671a0SJoel Fernandes 	 * return them with different flags to block coalescing, then repeatedly
464a9671a0SJoel Fernandes 	 * allocate and free 64 KiB blocks while timing the loop. This stresses how
474a9671a0SJoel Fernandes 	 * quickly the allocator can satisfy larger, aligned requests from a pool of
484a9671a0SJoel Fernandes 	 * highly fragmented space.
494a9671a0SJoel Fernandes 	 */
50ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
514a9671a0SJoel Fernandes 			       "buddy_init failed\n");
524a9671a0SJoel Fernandes 
534a9671a0SJoel Fernandes 	num_blocks = mm_size / SZ_64K;
544a9671a0SJoel Fernandes 
554a9671a0SJoel Fernandes 	start = ktime_get();
564a9671a0SJoel Fernandes 	/* Allocate with maximum fragmentation - 8K blocks with 64K alignment */
574a9671a0SJoel Fernandes 	for (i = 0; i < num_blocks; i++)
58ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_64K,
594a9671a0SJoel Fernandes 								    &allocated_blocks, 0),
604a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%u\n", SZ_8K);
614a9671a0SJoel Fernandes 
624a9671a0SJoel Fernandes 	list_for_each_entry_safe(block, tmp, &allocated_blocks, link) {
634a9671a0SJoel Fernandes 		if (count % 4 == 0 || count % 4 == 3)
644a9671a0SJoel Fernandes 			list_move_tail(&block->link, &clear_list);
654a9671a0SJoel Fernandes 		else
664a9671a0SJoel Fernandes 			list_move_tail(&block->link, &dirty_list);
674a9671a0SJoel Fernandes 		count++;
684a9671a0SJoel Fernandes 	}
694a9671a0SJoel Fernandes 
704a9671a0SJoel Fernandes 	/* Free with different flags to ensure no coalescing */
71ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &clear_list, GPU_BUDDY_CLEARED);
72ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &dirty_list, 0);
734a9671a0SJoel Fernandes 
744a9671a0SJoel Fernandes 	for (i = 0; i < num_blocks; i++)
75ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_64K, SZ_64K,
764a9671a0SJoel Fernandes 								    &test_blocks, 0),
774a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%u\n", SZ_64K);
78ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &test_blocks, 0);
794a9671a0SJoel Fernandes 
804a9671a0SJoel Fernandes 	end = ktime_get();
814a9671a0SJoel Fernandes 	elapsed_ms = ktime_to_ms(ktime_sub(end, start));
824a9671a0SJoel Fernandes 
834a9671a0SJoel Fernandes 	kunit_info(test, "Fragmented allocation took %lu ms\n", elapsed_ms);
844a9671a0SJoel Fernandes 
85ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
864a9671a0SJoel Fernandes 
874a9671a0SJoel Fernandes 	/*
884a9671a0SJoel Fernandes 	 * Reverse free order under fragmentation
894a9671a0SJoel Fernandes 	 *
904a9671a0SJoel Fernandes 	 * Construct a fragmented 4 GiB space by allocating every 8 KiB block with
914a9671a0SJoel Fernandes 	 * 64 KiB alignment, creating a dense scatter of small regions. Half of the
924a9671a0SJoel Fernandes 	 * blocks are selectively freed to form sparse gaps, while the remaining
934a9671a0SJoel Fernandes 	 * allocations are preserved, reordered in reverse, and released back with
944a9671a0SJoel Fernandes 	 * the cleared flag. This models a pathological reverse-ordered free pattern
954a9671a0SJoel Fernandes 	 * and measures how quickly the allocator can merge and reclaim space when
964a9671a0SJoel Fernandes 	 * deallocation occurs in the opposite order of allocation, exposing the
974a9671a0SJoel Fernandes 	 * cost difference between a linear freelist scan and an ordered tree lookup.
984a9671a0SJoel Fernandes 	 */
99ba110db8SJoel Fernandes 	ret = gpu_buddy_init(&mm, mm_size, SZ_4K);
1004a9671a0SJoel Fernandes 	KUNIT_ASSERT_EQ(test, ret, 0);
1014a9671a0SJoel Fernandes 
1024a9671a0SJoel Fernandes 	start = ktime_get();
1034a9671a0SJoel Fernandes 	/* Allocate maximum fragmentation */
1044a9671a0SJoel Fernandes 	for (i = 0; i < num_blocks; i++)
105ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_64K,
1064a9671a0SJoel Fernandes 								    &allocated_blocks, 0),
1074a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%u\n", SZ_8K);
1084a9671a0SJoel Fernandes 
1094a9671a0SJoel Fernandes 	list_for_each_entry_safe(block, tmp, &allocated_blocks, link) {
1104a9671a0SJoel Fernandes 		if (count % 2 == 0)
1114a9671a0SJoel Fernandes 			list_move_tail(&block->link, &free_list);
1124a9671a0SJoel Fernandes 		count++;
1134a9671a0SJoel Fernandes 	}
114ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &free_list, GPU_BUDDY_CLEARED);
1154a9671a0SJoel Fernandes 
1164a9671a0SJoel Fernandes 	list_for_each_entry_safe_reverse(block, tmp, &allocated_blocks, link)
1174a9671a0SJoel Fernandes 		list_move(&block->link, &reverse_list);
118ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &reverse_list, GPU_BUDDY_CLEARED);
1194a9671a0SJoel Fernandes 
1204a9671a0SJoel Fernandes 	end = ktime_get();
1214a9671a0SJoel Fernandes 	elapsed_ms = ktime_to_ms(ktime_sub(end, start));
1224a9671a0SJoel Fernandes 
1234a9671a0SJoel Fernandes 	kunit_info(test, "Reverse-ordered free took %lu ms\n", elapsed_ms);
1244a9671a0SJoel Fernandes 
125ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
1264a9671a0SJoel Fernandes }
1274a9671a0SJoel Fernandes 
128ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_range_bias(struct kunit *test)
1294a9671a0SJoel Fernandes {
1304a9671a0SJoel Fernandes 	u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem;
131ba110db8SJoel Fernandes 	GPU_RND_STATE(prng, random_seed);
1324a9671a0SJoel Fernandes 	unsigned int i, count, *order;
133ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
1344a9671a0SJoel Fernandes 	unsigned long flags;
135ba110db8SJoel Fernandes 	struct gpu_buddy mm;
1364a9671a0SJoel Fernandes 	LIST_HEAD(allocated);
1374a9671a0SJoel Fernandes 
1384a9671a0SJoel Fernandes 	bias_size = SZ_1M;
1394a9671a0SJoel Fernandes 	ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size);
1404a9671a0SJoel Fernandes 	ps = max(SZ_4K, ps);
1414a9671a0SJoel Fernandes 	mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */
1424a9671a0SJoel Fernandes 
1434a9671a0SJoel Fernandes 	kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps);
1444a9671a0SJoel Fernandes 
145ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
1464a9671a0SJoel Fernandes 			       "buddy_init failed\n");
1474a9671a0SJoel Fernandes 
1484a9671a0SJoel Fernandes 	count = mm_size / bias_size;
149ba110db8SJoel Fernandes 	order = gpu_random_order(count, &prng);
1504a9671a0SJoel Fernandes 	KUNIT_EXPECT_TRUE(test, order);
1514a9671a0SJoel Fernandes 
1524a9671a0SJoel Fernandes 	/*
1534a9671a0SJoel Fernandes 	 * Idea is to split the address space into uniform bias ranges, and then
1544a9671a0SJoel Fernandes 	 * in some random order allocate within each bias, using various
1554a9671a0SJoel Fernandes 	 * patterns within. This should detect if allocations leak out from a
1564a9671a0SJoel Fernandes 	 * given bias, for example.
1574a9671a0SJoel Fernandes 	 */
1584a9671a0SJoel Fernandes 
1594a9671a0SJoel Fernandes 	for (i = 0; i < count; i++) {
1604a9671a0SJoel Fernandes 		LIST_HEAD(tmp);
1614a9671a0SJoel Fernandes 		u32 size;
1624a9671a0SJoel Fernandes 
1634a9671a0SJoel Fernandes 		bias_start = order[i] * bias_size;
1644a9671a0SJoel Fernandes 		bias_end = bias_start + bias_size;
1654a9671a0SJoel Fernandes 		bias_rem = bias_size;
1664a9671a0SJoel Fernandes 
1674a9671a0SJoel Fernandes 		/* internal round_up too big */
1684a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test,
169ba110db8SJoel Fernandes 				      gpu_buddy_alloc_blocks(&mm, bias_start,
1704a9671a0SJoel Fernandes 							     bias_end, bias_size + ps, bias_size,
1714a9671a0SJoel Fernandes 							     &allocated,
172ba110db8SJoel Fernandes 							     GPU_BUDDY_RANGE_ALLOCATION),
1734a9671a0SJoel Fernandes 				      "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
1744a9671a0SJoel Fernandes 				      bias_start, bias_end, bias_size, bias_size);
1754a9671a0SJoel Fernandes 
1764a9671a0SJoel Fernandes 		/* size too big */
1774a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test,
178ba110db8SJoel Fernandes 				      gpu_buddy_alloc_blocks(&mm, bias_start,
1794a9671a0SJoel Fernandes 							     bias_end, bias_size + ps, ps,
1804a9671a0SJoel Fernandes 							     &allocated,
181ba110db8SJoel Fernandes 							     GPU_BUDDY_RANGE_ALLOCATION),
1824a9671a0SJoel Fernandes 				      "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
1834a9671a0SJoel Fernandes 				      bias_start, bias_end, bias_size + ps, ps);
1844a9671a0SJoel Fernandes 
1854a9671a0SJoel Fernandes 		/* bias range too small for size */
1864a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test,
187ba110db8SJoel Fernandes 				      gpu_buddy_alloc_blocks(&mm, bias_start + ps,
1884a9671a0SJoel Fernandes 							     bias_end, bias_size, ps,
1894a9671a0SJoel Fernandes 							     &allocated,
190ba110db8SJoel Fernandes 							     GPU_BUDDY_RANGE_ALLOCATION),
1914a9671a0SJoel Fernandes 				      "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
1924a9671a0SJoel Fernandes 				      bias_start + ps, bias_end, bias_size, ps);
1934a9671a0SJoel Fernandes 
1944a9671a0SJoel Fernandes 		/* bias misaligned */
1954a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test,
196ba110db8SJoel Fernandes 				      gpu_buddy_alloc_blocks(&mm, bias_start + ps,
1974a9671a0SJoel Fernandes 							     bias_end - ps,
1984a9671a0SJoel Fernandes 							     bias_size >> 1, bias_size >> 1,
1994a9671a0SJoel Fernandes 							     &allocated,
200ba110db8SJoel Fernandes 							     GPU_BUDDY_RANGE_ALLOCATION),
2014a9671a0SJoel Fernandes 				      "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n",
2024a9671a0SJoel Fernandes 				      bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1);
2034a9671a0SJoel Fernandes 
2044a9671a0SJoel Fernandes 		/* single big page */
2054a9671a0SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test,
206ba110db8SJoel Fernandes 				       gpu_buddy_alloc_blocks(&mm, bias_start,
2074a9671a0SJoel Fernandes 							      bias_end, bias_size, bias_size,
2084a9671a0SJoel Fernandes 							      &tmp,
209ba110db8SJoel Fernandes 							      GPU_BUDDY_RANGE_ALLOCATION),
2104a9671a0SJoel Fernandes 				       "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n",
2114a9671a0SJoel Fernandes 				       bias_start, bias_end, bias_size, bias_size);
212ba110db8SJoel Fernandes 		gpu_buddy_free_list(&mm, &tmp, 0);
2134a9671a0SJoel Fernandes 
2144a9671a0SJoel Fernandes 		/* single page with internal round_up */
2154a9671a0SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test,
216ba110db8SJoel Fernandes 				       gpu_buddy_alloc_blocks(&mm, bias_start,
2174a9671a0SJoel Fernandes 							      bias_end, ps, bias_size,
2184a9671a0SJoel Fernandes 							      &tmp,
219ba110db8SJoel Fernandes 							      GPU_BUDDY_RANGE_ALLOCATION),
2204a9671a0SJoel Fernandes 				       "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
2214a9671a0SJoel Fernandes 				       bias_start, bias_end, ps, bias_size);
222ba110db8SJoel Fernandes 		gpu_buddy_free_list(&mm, &tmp, 0);
2234a9671a0SJoel Fernandes 
2244a9671a0SJoel Fernandes 		/* random size within */
2254a9671a0SJoel Fernandes 		size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
2264a9671a0SJoel Fernandes 		if (size)
2274a9671a0SJoel Fernandes 			KUNIT_ASSERT_FALSE_MSG(test,
228ba110db8SJoel Fernandes 					       gpu_buddy_alloc_blocks(&mm, bias_start,
2294a9671a0SJoel Fernandes 								      bias_end, size, ps,
2304a9671a0SJoel Fernandes 								      &tmp,
231ba110db8SJoel Fernandes 								      GPU_BUDDY_RANGE_ALLOCATION),
2324a9671a0SJoel Fernandes 					       "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
2334a9671a0SJoel Fernandes 					       bias_start, bias_end, size, ps);
2344a9671a0SJoel Fernandes 
2354a9671a0SJoel Fernandes 		bias_rem -= size;
2364a9671a0SJoel Fernandes 		/* too big for current avail */
2374a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test,
238ba110db8SJoel Fernandes 				      gpu_buddy_alloc_blocks(&mm, bias_start,
2394a9671a0SJoel Fernandes 							     bias_end, bias_rem + ps, ps,
2404a9671a0SJoel Fernandes 							     &allocated,
241ba110db8SJoel Fernandes 							     GPU_BUDDY_RANGE_ALLOCATION),
2424a9671a0SJoel Fernandes 				      "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
2434a9671a0SJoel Fernandes 				      bias_start, bias_end, bias_rem + ps, ps);
2444a9671a0SJoel Fernandes 
2454a9671a0SJoel Fernandes 		if (bias_rem) {
2464a9671a0SJoel Fernandes 			/* random fill of the remainder */
2474a9671a0SJoel Fernandes 			size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
2484a9671a0SJoel Fernandes 			size = max(size, ps);
2494a9671a0SJoel Fernandes 
2504a9671a0SJoel Fernandes 			KUNIT_ASSERT_FALSE_MSG(test,
251ba110db8SJoel Fernandes 					       gpu_buddy_alloc_blocks(&mm, bias_start,
2524a9671a0SJoel Fernandes 								      bias_end, size, ps,
2534a9671a0SJoel Fernandes 								      &allocated,
254ba110db8SJoel Fernandes 								      GPU_BUDDY_RANGE_ALLOCATION),
2554a9671a0SJoel Fernandes 					       "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
2564a9671a0SJoel Fernandes 					       bias_start, bias_end, size, ps);
2574a9671a0SJoel Fernandes 			/*
2584a9671a0SJoel Fernandes 			 * Intentionally allow some space to be left
2594a9671a0SJoel Fernandes 			 * unallocated, and ideally not always on the bias
2604a9671a0SJoel Fernandes 			 * boundaries.
2614a9671a0SJoel Fernandes 			 */
262ba110db8SJoel Fernandes 			gpu_buddy_free_list(&mm, &tmp, 0);
2634a9671a0SJoel Fernandes 		} else {
2644a9671a0SJoel Fernandes 			list_splice_tail(&tmp, &allocated);
2654a9671a0SJoel Fernandes 		}
2664a9671a0SJoel Fernandes 	}
2674a9671a0SJoel Fernandes 
2684a9671a0SJoel Fernandes 	kfree(order);
269ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, 0);
270ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
2714a9671a0SJoel Fernandes 
2724a9671a0SJoel Fernandes 	/*
2734a9671a0SJoel Fernandes 	 * Something more free-form. Idea is to pick a random starting bias
2744a9671a0SJoel Fernandes 	 * range within the address space and then start filling it up. Also
2754a9671a0SJoel Fernandes 	 * randomly grow the bias range in both directions as we go along. This
2764a9671a0SJoel Fernandes 	 * should give us bias start/end which is not always uniform like above,
2774a9671a0SJoel Fernandes 	 * and in some cases will require the allocator to jump over already
2784a9671a0SJoel Fernandes 	 * allocated nodes in the middle of the address space.
2794a9671a0SJoel Fernandes 	 */
2804a9671a0SJoel Fernandes 
281ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
2824a9671a0SJoel Fernandes 			       "buddy_init failed\n");
2834a9671a0SJoel Fernandes 
2844a9671a0SJoel Fernandes 	bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
2854a9671a0SJoel Fernandes 	bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
2864a9671a0SJoel Fernandes 	bias_end = max(bias_end, bias_start + ps);
2874a9671a0SJoel Fernandes 	bias_rem = bias_end - bias_start;
2884a9671a0SJoel Fernandes 
2894a9671a0SJoel Fernandes 	do {
2904a9671a0SJoel Fernandes 		u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
2914a9671a0SJoel Fernandes 
2924a9671a0SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test,
293ba110db8SJoel Fernandes 				       gpu_buddy_alloc_blocks(&mm, bias_start,
2944a9671a0SJoel Fernandes 							      bias_end, size, ps,
2954a9671a0SJoel Fernandes 							      &allocated,
296ba110db8SJoel Fernandes 							      GPU_BUDDY_RANGE_ALLOCATION),
2974a9671a0SJoel Fernandes 				       "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
2984a9671a0SJoel Fernandes 				       bias_start, bias_end, size, ps);
2994a9671a0SJoel Fernandes 		bias_rem -= size;
3004a9671a0SJoel Fernandes 
3014a9671a0SJoel Fernandes 		/*
3024a9671a0SJoel Fernandes 		 * Try to randomly grow the bias range in both directions, or
3034a9671a0SJoel Fernandes 		 * only one, or perhaps don't grow at all.
3044a9671a0SJoel Fernandes 		 */
3054a9671a0SJoel Fernandes 		do {
3064a9671a0SJoel Fernandes 			u32 old_bias_start = bias_start;
3074a9671a0SJoel Fernandes 			u32 old_bias_end = bias_end;
3084a9671a0SJoel Fernandes 
3094a9671a0SJoel Fernandes 			if (bias_start)
3104a9671a0SJoel Fernandes 				bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps);
3114a9671a0SJoel Fernandes 			if (bias_end != mm_size)
3124a9671a0SJoel Fernandes 				bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps);
3134a9671a0SJoel Fernandes 
3144a9671a0SJoel Fernandes 			bias_rem += old_bias_start - bias_start;
3154a9671a0SJoel Fernandes 			bias_rem += bias_end - old_bias_end;
3164a9671a0SJoel Fernandes 		} while (!bias_rem && (bias_start || bias_end != mm_size));
3174a9671a0SJoel Fernandes 	} while (bias_rem);
3184a9671a0SJoel Fernandes 
3194a9671a0SJoel Fernandes 	KUNIT_ASSERT_EQ(test, bias_start, 0);
3204a9671a0SJoel Fernandes 	KUNIT_ASSERT_EQ(test, bias_end, mm_size);
3214a9671a0SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test,
322ba110db8SJoel Fernandes 			      gpu_buddy_alloc_blocks(&mm, bias_start, bias_end,
3234a9671a0SJoel Fernandes 						     ps, ps,
3244a9671a0SJoel Fernandes 						     &allocated,
325ba110db8SJoel Fernandes 						     GPU_BUDDY_RANGE_ALLOCATION),
3264a9671a0SJoel Fernandes 			      "buddy_alloc passed with bias(%x-%x), size=%u\n",
3274a9671a0SJoel Fernandes 			      bias_start, bias_end, ps);
3284a9671a0SJoel Fernandes 
329ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, 0);
330ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
3314a9671a0SJoel Fernandes 
3324a9671a0SJoel Fernandes 	/*
333ba110db8SJoel Fernandes 	 * Allocate cleared blocks in the bias range when the GPU buddy's clear avail is
3344a9671a0SJoel Fernandes 	 * zero. This will validate the bias range allocation in scenarios like system boot
3354a9671a0SJoel Fernandes 	 * when no cleared blocks are available and exercise the fallback path too. The resulting
3364a9671a0SJoel Fernandes 	 * blocks should always be dirty.
3374a9671a0SJoel Fernandes 	 */
3384a9671a0SJoel Fernandes 
339ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
3404a9671a0SJoel Fernandes 			       "buddy_init failed\n");
3414a9671a0SJoel Fernandes 
3424a9671a0SJoel Fernandes 	bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
3434a9671a0SJoel Fernandes 	bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
3444a9671a0SJoel Fernandes 	bias_end = max(bias_end, bias_start + ps);
3454a9671a0SJoel Fernandes 	bias_rem = bias_end - bias_start;
3464a9671a0SJoel Fernandes 
347ba110db8SJoel Fernandes 	flags = GPU_BUDDY_CLEAR_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION;
3484a9671a0SJoel Fernandes 	size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
3494a9671a0SJoel Fernandes 
3504a9671a0SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test,
351ba110db8SJoel Fernandes 			       gpu_buddy_alloc_blocks(&mm, bias_start,
3524a9671a0SJoel Fernandes 						      bias_end, size, ps,
3534a9671a0SJoel Fernandes 						      &allocated,
3544a9671a0SJoel Fernandes 						      flags),
3554a9671a0SJoel Fernandes 			       "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
3564a9671a0SJoel Fernandes 			       bias_start, bias_end, size, ps);
3574a9671a0SJoel Fernandes 
3584a9671a0SJoel Fernandes 	list_for_each_entry(block, &allocated, link)
359ba110db8SJoel Fernandes 		KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
3604a9671a0SJoel Fernandes 
361ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, 0);
362ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
3634a9671a0SJoel Fernandes }
3644a9671a0SJoel Fernandes 
365ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_clear(struct kunit *test)
3664a9671a0SJoel Fernandes {
3674a9671a0SJoel Fernandes 	unsigned long n_pages, total, i = 0;
3684a9671a0SJoel Fernandes 	const unsigned long ps = SZ_4K;
369ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
3704a9671a0SJoel Fernandes 	const int max_order = 12;
3714a9671a0SJoel Fernandes 	LIST_HEAD(allocated);
372ba110db8SJoel Fernandes 	struct gpu_buddy mm;
3734a9671a0SJoel Fernandes 	unsigned int order;
3744a9671a0SJoel Fernandes 	u32 mm_size, size;
3754a9671a0SJoel Fernandes 	LIST_HEAD(dirty);
3764a9671a0SJoel Fernandes 	LIST_HEAD(clean);
3774a9671a0SJoel Fernandes 
3784a9671a0SJoel Fernandes 	mm_size = SZ_4K << max_order;
379ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
3804a9671a0SJoel Fernandes 
3814a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
3824a9671a0SJoel Fernandes 
3834a9671a0SJoel Fernandes 	/*
3844a9671a0SJoel Fernandes 	 * Idea is to allocate and free some random portion of the address space,
3854a9671a0SJoel Fernandes 	 * returning those pages as non-dirty and randomly alternate between
3864a9671a0SJoel Fernandes 	 * requesting dirty and non-dirty pages (not going over the limit
3874a9671a0SJoel Fernandes 	 * we freed as non-dirty), putting that into two separate lists.
3884a9671a0SJoel Fernandes 	 * Loop over both lists at the end checking that the dirty list
3894a9671a0SJoel Fernandes 	 * is indeed all dirty pages and vice versa. Free it all again,
3904a9671a0SJoel Fernandes 	 * keeping the dirty/clear status.
3914a9671a0SJoel Fernandes 	 */
392ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
3934a9671a0SJoel Fernandes 							    5 * ps, ps, &allocated,
394ba110db8SJoel Fernandes 							    GPU_BUDDY_TOPDOWN_ALLOCATION),
3954a9671a0SJoel Fernandes 				"buddy_alloc hit an error size=%lu\n", 5 * ps);
396ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
3974a9671a0SJoel Fernandes 
3984a9671a0SJoel Fernandes 	n_pages = 10;
3994a9671a0SJoel Fernandes 	do {
4004a9671a0SJoel Fernandes 		unsigned long flags;
4014a9671a0SJoel Fernandes 		struct list_head *list;
4024a9671a0SJoel Fernandes 		int slot = i % 2;
4034a9671a0SJoel Fernandes 
4044a9671a0SJoel Fernandes 		if (slot == 0) {
4054a9671a0SJoel Fernandes 			list = &dirty;
4064a9671a0SJoel Fernandes 			flags = 0;
4074a9671a0SJoel Fernandes 		} else {
4084a9671a0SJoel Fernandes 			list = &clean;
409ba110db8SJoel Fernandes 			flags = GPU_BUDDY_CLEAR_ALLOCATION;
4104a9671a0SJoel Fernandes 		}
4114a9671a0SJoel Fernandes 
412ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
4134a9671a0SJoel Fernandes 								    ps, ps, list,
4144a9671a0SJoel Fernandes 								    flags),
4154a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%lu\n", ps);
4164a9671a0SJoel Fernandes 	} while (++i < n_pages);
4174a9671a0SJoel Fernandes 
4184a9671a0SJoel Fernandes 	list_for_each_entry(block, &clean, link)
419ba110db8SJoel Fernandes 		KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), true);
4204a9671a0SJoel Fernandes 
4214a9671a0SJoel Fernandes 	list_for_each_entry(block, &dirty, link)
422ba110db8SJoel Fernandes 		KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
4234a9671a0SJoel Fernandes 
424ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
4254a9671a0SJoel Fernandes 
4264a9671a0SJoel Fernandes 	/*
4274a9671a0SJoel Fernandes 	 * Trying to go over the clear limit for some allocation.
4284a9671a0SJoel Fernandes 	 * The allocation should never fail with reasonable page-size.
4294a9671a0SJoel Fernandes 	 */
430ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
4314a9671a0SJoel Fernandes 							    10 * ps, ps, &clean,
432ba110db8SJoel Fernandes 							    GPU_BUDDY_CLEAR_ALLOCATION),
4334a9671a0SJoel Fernandes 				"buddy_alloc hit an error size=%lu\n", 10 * ps);
4344a9671a0SJoel Fernandes 
435ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
436ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &dirty, 0);
437ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
4384a9671a0SJoel Fernandes 
439ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
4404a9671a0SJoel Fernandes 
4414a9671a0SJoel Fernandes 	/*
4424a9671a0SJoel Fernandes 	 * Create a new mm. Intentionally fragment the address space by creating
4434a9671a0SJoel Fernandes 	 * two alternating lists. Free both lists, one as dirty the other as clean.
4444a9671a0SJoel Fernandes 	 * Try to allocate double the previous size with matching min_page_size. The
4454a9671a0SJoel Fernandes 	 * allocation should never fail as it calls the force_merge. Also check that
4464a9671a0SJoel Fernandes 	 * the page is always dirty after force_merge. Free the page as dirty, then
4474a9671a0SJoel Fernandes 	 * repeat the whole thing, increment the order until we hit the max_order.
4484a9671a0SJoel Fernandes 	 */
4494a9671a0SJoel Fernandes 
4504a9671a0SJoel Fernandes 	i = 0;
4514a9671a0SJoel Fernandes 	n_pages = mm_size / ps;
4524a9671a0SJoel Fernandes 	do {
4534a9671a0SJoel Fernandes 		struct list_head *list;
4544a9671a0SJoel Fernandes 		int slot = i % 2;
4554a9671a0SJoel Fernandes 
4564a9671a0SJoel Fernandes 		if (slot == 0)
4574a9671a0SJoel Fernandes 			list = &dirty;
4584a9671a0SJoel Fernandes 		else
4594a9671a0SJoel Fernandes 			list = &clean;
4604a9671a0SJoel Fernandes 
461ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
4624a9671a0SJoel Fernandes 								    ps, ps, list, 0),
4634a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%lu\n", ps);
4644a9671a0SJoel Fernandes 	} while (++i < n_pages);
4654a9671a0SJoel Fernandes 
466ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
467ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &dirty, 0);
4684a9671a0SJoel Fernandes 
4694a9671a0SJoel Fernandes 	order = 1;
4704a9671a0SJoel Fernandes 	do {
4714a9671a0SJoel Fernandes 		size = SZ_4K << order;
4724a9671a0SJoel Fernandes 
473ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
4744a9671a0SJoel Fernandes 								    size, size, &allocated,
475ba110db8SJoel Fernandes 								    GPU_BUDDY_CLEAR_ALLOCATION),
4764a9671a0SJoel Fernandes 					"buddy_alloc hit an error size=%u\n", size);
4774a9671a0SJoel Fernandes 		total = 0;
4784a9671a0SJoel Fernandes 		list_for_each_entry(block, &allocated, link) {
4794a9671a0SJoel Fernandes 			if (size != mm_size)
480ba110db8SJoel Fernandes 				KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
481ba110db8SJoel Fernandes 			total += gpu_buddy_block_size(&mm, block);
4824a9671a0SJoel Fernandes 		}
4834a9671a0SJoel Fernandes 		KUNIT_EXPECT_EQ(test, total, size);
4844a9671a0SJoel Fernandes 
485ba110db8SJoel Fernandes 		gpu_buddy_free_list(&mm, &allocated, 0);
4864a9671a0SJoel Fernandes 	} while (++order <= max_order);
4874a9671a0SJoel Fernandes 
488ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
4894a9671a0SJoel Fernandes 
4904a9671a0SJoel Fernandes 	/*
4914a9671a0SJoel Fernandes 	 * Create a new mm with a non power-of-two size. Allocate a random size from each
4924a9671a0SJoel Fernandes 	 * root, free as cleared and then call fini. This will ensure the multi-root
4934a9671a0SJoel Fernandes 	 * force merge during fini.
4944a9671a0SJoel Fernandes 	 */
4954a9671a0SJoel Fernandes 	mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2));
4964a9671a0SJoel Fernandes 
497ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
4984a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
499ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
5004a9671a0SJoel Fernandes 							    4 * ps, ps, &allocated,
501ba110db8SJoel Fernandes 							    GPU_BUDDY_RANGE_ALLOCATION),
5024a9671a0SJoel Fernandes 				"buddy_alloc hit an error size=%lu\n", 4 * ps);
503ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
504ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
5054a9671a0SJoel Fernandes 							    2 * ps, ps, &allocated,
506ba110db8SJoel Fernandes 							    GPU_BUDDY_CLEAR_ALLOCATION),
5074a9671a0SJoel Fernandes 				"buddy_alloc hit an error size=%lu\n", 2 * ps);
508ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
509ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size,
5104a9671a0SJoel Fernandes 							    ps, ps, &allocated,
511ba110db8SJoel Fernandes 							    GPU_BUDDY_RANGE_ALLOCATION),
5124a9671a0SJoel Fernandes 				"buddy_alloc hit an error size=%lu\n", ps);
513ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
514ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
5154a9671a0SJoel Fernandes }
5164a9671a0SJoel Fernandes 
517ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_contiguous(struct kunit *test)
5184a9671a0SJoel Fernandes {
5194a9671a0SJoel Fernandes 	const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
5204a9671a0SJoel Fernandes 	unsigned long i, n_pages, total;
521ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
522ba110db8SJoel Fernandes 	struct gpu_buddy mm;
5234a9671a0SJoel Fernandes 	LIST_HEAD(left);
5244a9671a0SJoel Fernandes 	LIST_HEAD(middle);
5254a9671a0SJoel Fernandes 	LIST_HEAD(right);
5264a9671a0SJoel Fernandes 	LIST_HEAD(allocated);
5274a9671a0SJoel Fernandes 
528ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
5294a9671a0SJoel Fernandes 
5304a9671a0SJoel Fernandes 	/*
5314a9671a0SJoel Fernandes 	 * Idea is to fragment the address space by alternating block
5324a9671a0SJoel Fernandes 	 * allocations between three different lists; one for left, middle and
5334a9671a0SJoel Fernandes 	 * right. We can then free a list to simulate fragmentation. In
534ba110db8SJoel Fernandes 	 * particular we want to exercise the GPU_BUDDY_CONTIGUOUS_ALLOCATION,
5354a9671a0SJoel Fernandes 	 * including the try_harder path.
5364a9671a0SJoel Fernandes 	 */
5374a9671a0SJoel Fernandes 
5384a9671a0SJoel Fernandes 	i = 0;
5394a9671a0SJoel Fernandes 	n_pages = mm_size / ps;
5404a9671a0SJoel Fernandes 	do {
5414a9671a0SJoel Fernandes 		struct list_head *list;
5424a9671a0SJoel Fernandes 		int slot = i % 3;
5434a9671a0SJoel Fernandes 
5444a9671a0SJoel Fernandes 		if (slot == 0)
5454a9671a0SJoel Fernandes 			list = &left;
5464a9671a0SJoel Fernandes 		else if (slot == 1)
5474a9671a0SJoel Fernandes 			list = &middle;
5484a9671a0SJoel Fernandes 		else
5494a9671a0SJoel Fernandes 			list = &right;
5504a9671a0SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test,
551ba110db8SJoel Fernandes 				       gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5524a9671a0SJoel Fernandes 							      ps, ps, list, 0),
5534a9671a0SJoel Fernandes 				       "buddy_alloc hit an error size=%lu\n",
5544a9671a0SJoel Fernandes 				       ps);
5554a9671a0SJoel Fernandes 	} while (++i < n_pages);
5564a9671a0SJoel Fernandes 
557ba110db8SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5584a9671a0SJoel Fernandes 							   3 * ps, ps, &allocated,
559ba110db8SJoel Fernandes 							   GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5604a9671a0SJoel Fernandes 			       "buddy_alloc didn't error size=%lu\n", 3 * ps);
5614a9671a0SJoel Fernandes 
562ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &middle, 0);
563ba110db8SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5644a9671a0SJoel Fernandes 							   3 * ps, ps, &allocated,
565ba110db8SJoel Fernandes 							   GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5664a9671a0SJoel Fernandes 			       "buddy_alloc didn't error size=%lu\n", 3 * ps);
567ba110db8SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5684a9671a0SJoel Fernandes 							   2 * ps, ps, &allocated,
569ba110db8SJoel Fernandes 							   GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5704a9671a0SJoel Fernandes 			       "buddy_alloc didn't error size=%lu\n", 2 * ps);
5714a9671a0SJoel Fernandes 
572ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &right, 0);
573ba110db8SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5744a9671a0SJoel Fernandes 							   3 * ps, ps, &allocated,
575ba110db8SJoel Fernandes 							   GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5764a9671a0SJoel Fernandes 			       "buddy_alloc didn't error size=%lu\n", 3 * ps);
5774a9671a0SJoel Fernandes 	/*
5784a9671a0SJoel Fernandes 	 * At this point we should have enough contiguous space for 2 blocks,
5794a9671a0SJoel Fernandes 	 * however they are never buddies (since we freed middle and right) so
5804a9671a0SJoel Fernandes 	 * will require the try_harder logic to find them.
5814a9671a0SJoel Fernandes 	 */
582ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5834a9671a0SJoel Fernandes 							    2 * ps, ps, &allocated,
584ba110db8SJoel Fernandes 							    GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5854a9671a0SJoel Fernandes 			       "buddy_alloc hit an error size=%lu\n", 2 * ps);
5864a9671a0SJoel Fernandes 
587ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &left, 0);
588ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
5894a9671a0SJoel Fernandes 							    3 * ps, ps, &allocated,
590ba110db8SJoel Fernandes 							    GPU_BUDDY_CONTIGUOUS_ALLOCATION),
5914a9671a0SJoel Fernandes 			       "buddy_alloc hit an error size=%lu\n", 3 * ps);
5924a9671a0SJoel Fernandes 
5934a9671a0SJoel Fernandes 	total = 0;
5944a9671a0SJoel Fernandes 	list_for_each_entry(block, &allocated, link)
595ba110db8SJoel Fernandes 		total += gpu_buddy_block_size(&mm, block);
5964a9671a0SJoel Fernandes 
5974a9671a0SJoel Fernandes 	KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
5984a9671a0SJoel Fernandes 
599ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, 0);
600ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
6014a9671a0SJoel Fernandes }
6024a9671a0SJoel Fernandes 
603ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_pathological(struct kunit *test)
6044a9671a0SJoel Fernandes {
6054a9671a0SJoel Fernandes 	u64 mm_size, size, start = 0;
606ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
6074a9671a0SJoel Fernandes 	const int max_order = 3;
6084a9671a0SJoel Fernandes 	unsigned long flags = 0;
6094a9671a0SJoel Fernandes 	int order, top;
610ba110db8SJoel Fernandes 	struct gpu_buddy mm;
6114a9671a0SJoel Fernandes 	LIST_HEAD(blocks);
6124a9671a0SJoel Fernandes 	LIST_HEAD(holes);
6134a9671a0SJoel Fernandes 	LIST_HEAD(tmp);
6144a9671a0SJoel Fernandes 
6154a9671a0SJoel Fernandes 	/*
6164a9671a0SJoel Fernandes 	 * Create a pot-sized mm, then allocate one of each possible
6174a9671a0SJoel Fernandes 	 * order within. This should leave the mm with exactly one
6184a9671a0SJoel Fernandes 	 * page left. Free the largest block, then whittle down again.
6194a9671a0SJoel Fernandes 	 * Eventually we will have a fully 50% fragmented mm.
6204a9671a0SJoel Fernandes 	 */
6214a9671a0SJoel Fernandes 
6224a9671a0SJoel Fernandes 	mm_size = SZ_4K << max_order;
623ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
6244a9671a0SJoel Fernandes 			       "buddy_init failed\n");
6254a9671a0SJoel Fernandes 
6264a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
6274a9671a0SJoel Fernandes 
6284a9671a0SJoel Fernandes 	for (top = max_order; top; top--) {
6294a9671a0SJoel Fernandes 		/* Make room by freeing the largest allocated block */
6304a9671a0SJoel Fernandes 		block = list_first_entry_or_null(&blocks, typeof(*block), link);
6314a9671a0SJoel Fernandes 		if (block) {
6324a9671a0SJoel Fernandes 			list_del(&block->link);
633ba110db8SJoel Fernandes 			gpu_buddy_free_block(&mm, block);
6344a9671a0SJoel Fernandes 		}
6354a9671a0SJoel Fernandes 
6364a9671a0SJoel Fernandes 		for (order = top; order--;) {
6374a9671a0SJoel Fernandes 			size = get_size(order, mm.chunk_size);
638ba110db8SJoel Fernandes 			KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start,
6394a9671a0SJoel Fernandes 									    mm_size, size, size,
6404a9671a0SJoel Fernandes 										&tmp, flags),
6414a9671a0SJoel Fernandes 					"buddy_alloc hit -ENOMEM with order=%d, top=%d\n",
6424a9671a0SJoel Fernandes 					order, top);
6434a9671a0SJoel Fernandes 
644ba110db8SJoel Fernandes 			block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
6454a9671a0SJoel Fernandes 			KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
6464a9671a0SJoel Fernandes 
6474a9671a0SJoel Fernandes 			list_move_tail(&block->link, &blocks);
6484a9671a0SJoel Fernandes 		}
6494a9671a0SJoel Fernandes 
6504a9671a0SJoel Fernandes 		/* There should be one final page for this sub-allocation */
6514a9671a0SJoel Fernandes 		size = get_size(0, mm.chunk_size);
652ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
6534a9671a0SJoel Fernandes 								    size, size, &tmp, flags),
6544a9671a0SJoel Fernandes 							   "buddy_alloc hit -ENOMEM for hole\n");
6554a9671a0SJoel Fernandes 
656ba110db8SJoel Fernandes 		block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
6574a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
6584a9671a0SJoel Fernandes 
6594a9671a0SJoel Fernandes 		list_move_tail(&block->link, &holes);
6604a9671a0SJoel Fernandes 
6614a9671a0SJoel Fernandes 		size = get_size(top, mm.chunk_size);
662ba110db8SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
6634a9671a0SJoel Fernandes 								   size, size, &tmp, flags),
6644a9671a0SJoel Fernandes 							  "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!",
6654a9671a0SJoel Fernandes 							  top, max_order);
6664a9671a0SJoel Fernandes 	}
6674a9671a0SJoel Fernandes 
668ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &holes, 0);
6694a9671a0SJoel Fernandes 
6704a9671a0SJoel Fernandes 	/* Nothing larger than blocks of chunk_size now available */
6714a9671a0SJoel Fernandes 	for (order = 1; order <= max_order; order++) {
6724a9671a0SJoel Fernandes 		size = get_size(order, mm.chunk_size);
673ba110db8SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
6744a9671a0SJoel Fernandes 								   size, size, &tmp, flags),
6754a9671a0SJoel Fernandes 							  "buddy_alloc unexpectedly succeeded at order %d, it should be full!",
6764a9671a0SJoel Fernandes 							  order);
6774a9671a0SJoel Fernandes 	}
6784a9671a0SJoel Fernandes 
6794a9671a0SJoel Fernandes 	list_splice_tail(&holes, &blocks);
680ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &blocks, 0);
681ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
6824a9671a0SJoel Fernandes }
6834a9671a0SJoel Fernandes 
684ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_pessimistic(struct kunit *test)
6854a9671a0SJoel Fernandes {
6864a9671a0SJoel Fernandes 	u64 mm_size, size, start = 0;
687ba110db8SJoel Fernandes 	struct gpu_buddy_block *block, *bn;
6884a9671a0SJoel Fernandes 	const unsigned int max_order = 16;
6894a9671a0SJoel Fernandes 	unsigned long flags = 0;
690ba110db8SJoel Fernandes 	struct gpu_buddy mm;
6914a9671a0SJoel Fernandes 	unsigned int order;
6924a9671a0SJoel Fernandes 	LIST_HEAD(blocks);
6934a9671a0SJoel Fernandes 	LIST_HEAD(tmp);
6944a9671a0SJoel Fernandes 
6954a9671a0SJoel Fernandes 	/*
6964a9671a0SJoel Fernandes 	 * Create a pot-sized mm, then allocate one of each possible
6974a9671a0SJoel Fernandes 	 * order within. This should leave the mm with exactly one
6984a9671a0SJoel Fernandes 	 * page left.
6994a9671a0SJoel Fernandes 	 */
7004a9671a0SJoel Fernandes 
7014a9671a0SJoel Fernandes 	mm_size = SZ_4K << max_order;
702ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
7034a9671a0SJoel Fernandes 			       "buddy_init failed\n");
7044a9671a0SJoel Fernandes 
7054a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
7064a9671a0SJoel Fernandes 
7074a9671a0SJoel Fernandes 	for (order = 0; order < max_order; order++) {
7084a9671a0SJoel Fernandes 		size = get_size(order, mm.chunk_size);
709ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
7104a9671a0SJoel Fernandes 								    size, size, &tmp, flags),
7114a9671a0SJoel Fernandes 							   "buddy_alloc hit -ENOMEM with order=%d\n",
7124a9671a0SJoel Fernandes 							   order);
7134a9671a0SJoel Fernandes 
714ba110db8SJoel Fernandes 		block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
7154a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
7164a9671a0SJoel Fernandes 
7174a9671a0SJoel Fernandes 		list_move_tail(&block->link, &blocks);
7184a9671a0SJoel Fernandes 	}
7194a9671a0SJoel Fernandes 
7204a9671a0SJoel Fernandes 	/* And now the last remaining block available */
7214a9671a0SJoel Fernandes 	size = get_size(0, mm.chunk_size);
722ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
7234a9671a0SJoel Fernandes 							    size, size, &tmp, flags),
7244a9671a0SJoel Fernandes 						   "buddy_alloc hit -ENOMEM on final alloc\n");
7254a9671a0SJoel Fernandes 
726ba110db8SJoel Fernandes 	block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
7274a9671a0SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
7284a9671a0SJoel Fernandes 
7294a9671a0SJoel Fernandes 	list_move_tail(&block->link, &blocks);
7304a9671a0SJoel Fernandes 
7314a9671a0SJoel Fernandes 	/* Should be completely full! */
7324a9671a0SJoel Fernandes 	for (order = max_order; order--;) {
7334a9671a0SJoel Fernandes 		size = get_size(order, mm.chunk_size);
734ba110db8SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
7354a9671a0SJoel Fernandes 								   size, size, &tmp, flags),
7364a9671a0SJoel Fernandes 							  "buddy_alloc unexpectedly succeeded, it should be full!");
7374a9671a0SJoel Fernandes 	}
7384a9671a0SJoel Fernandes 
7394a9671a0SJoel Fernandes 	block = list_last_entry(&blocks, typeof(*block), link);
7404a9671a0SJoel Fernandes 	list_del(&block->link);
741ba110db8SJoel Fernandes 	gpu_buddy_free_block(&mm, block);
7424a9671a0SJoel Fernandes 
7434a9671a0SJoel Fernandes 	/* As we free in increasing size, we make available larger blocks */
7444a9671a0SJoel Fernandes 	order = 1;
7454a9671a0SJoel Fernandes 	list_for_each_entry_safe(block, bn, &blocks, link) {
7464a9671a0SJoel Fernandes 		list_del(&block->link);
747ba110db8SJoel Fernandes 		gpu_buddy_free_block(&mm, block);
7484a9671a0SJoel Fernandes 
7494a9671a0SJoel Fernandes 		size = get_size(order, mm.chunk_size);
750ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
7514a9671a0SJoel Fernandes 								    size, size, &tmp, flags),
7524a9671a0SJoel Fernandes 							   "buddy_alloc hit -ENOMEM with order=%d\n",
7534a9671a0SJoel Fernandes 							   order);
7544a9671a0SJoel Fernandes 
755ba110db8SJoel Fernandes 		block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
7564a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
7574a9671a0SJoel Fernandes 
7584a9671a0SJoel Fernandes 		list_del(&block->link);
759ba110db8SJoel Fernandes 		gpu_buddy_free_block(&mm, block);
7604a9671a0SJoel Fernandes 		order++;
7614a9671a0SJoel Fernandes 	}
7624a9671a0SJoel Fernandes 
7634a9671a0SJoel Fernandes 	/* To confirm, now the whole mm should be available */
7644a9671a0SJoel Fernandes 	size = get_size(max_order, mm.chunk_size);
765ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
7664a9671a0SJoel Fernandes 							    size, size, &tmp, flags),
7674a9671a0SJoel Fernandes 						   "buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
7684a9671a0SJoel Fernandes 						   max_order);
7694a9671a0SJoel Fernandes 
770ba110db8SJoel Fernandes 	block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
7714a9671a0SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
7724a9671a0SJoel Fernandes 
7734a9671a0SJoel Fernandes 	list_del(&block->link);
774ba110db8SJoel Fernandes 	gpu_buddy_free_block(&mm, block);
775ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &blocks, 0);
776ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
7774a9671a0SJoel Fernandes }
7784a9671a0SJoel Fernandes 
779ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_optimistic(struct kunit *test)
7804a9671a0SJoel Fernandes {
7814a9671a0SJoel Fernandes 	u64 mm_size, size, start = 0;
782ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
7834a9671a0SJoel Fernandes 	unsigned long flags = 0;
7844a9671a0SJoel Fernandes 	const int max_order = 16;
785ba110db8SJoel Fernandes 	struct gpu_buddy mm;
7864a9671a0SJoel Fernandes 	LIST_HEAD(blocks);
7874a9671a0SJoel Fernandes 	LIST_HEAD(tmp);
7884a9671a0SJoel Fernandes 	int order;
7894a9671a0SJoel Fernandes 
7904a9671a0SJoel Fernandes 	/*
7914a9671a0SJoel Fernandes 	 * Create a mm with one block of each order available, and
7924a9671a0SJoel Fernandes 	 * try to allocate them all.
7934a9671a0SJoel Fernandes 	 */
7944a9671a0SJoel Fernandes 
7954a9671a0SJoel Fernandes 	mm_size = SZ_4K * ((1 << (max_order + 1)) - 1);
7964a9671a0SJoel Fernandes 
797ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
7984a9671a0SJoel Fernandes 			       "buddy_init failed\n");
7994a9671a0SJoel Fernandes 
8004a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
8014a9671a0SJoel Fernandes 
8024a9671a0SJoel Fernandes 	for (order = 0; order <= max_order; order++) {
8034a9671a0SJoel Fernandes 		size = get_size(order, mm.chunk_size);
804ba110db8SJoel Fernandes 		KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
8054a9671a0SJoel Fernandes 								    size, size, &tmp, flags),
8064a9671a0SJoel Fernandes 							   "buddy_alloc hit -ENOMEM with order=%d\n",
8074a9671a0SJoel Fernandes 							   order);
8084a9671a0SJoel Fernandes 
809ba110db8SJoel Fernandes 		block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
8104a9671a0SJoel Fernandes 		KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
8114a9671a0SJoel Fernandes 
8124a9671a0SJoel Fernandes 		list_move_tail(&block->link, &blocks);
8134a9671a0SJoel Fernandes 	}
8144a9671a0SJoel Fernandes 
8154a9671a0SJoel Fernandes 	/* Should be completely full! */
8164a9671a0SJoel Fernandes 	size = get_size(0, mm.chunk_size);
817ba110db8SJoel Fernandes 	KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
8184a9671a0SJoel Fernandes 							   size, size, &tmp, flags),
8194a9671a0SJoel Fernandes 						  "buddy_alloc unexpectedly succeeded, it should be full!");
8204a9671a0SJoel Fernandes 
821ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &blocks, 0);
822ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
8234a9671a0SJoel Fernandes }
8244a9671a0SJoel Fernandes 
825ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_limit(struct kunit *test)
8264a9671a0SJoel Fernandes {
8274a9671a0SJoel Fernandes 	u64 size = U64_MAX, start = 0;
828ba110db8SJoel Fernandes 	struct gpu_buddy_block *block;
8294a9671a0SJoel Fernandes 	unsigned long flags = 0;
8304a9671a0SJoel Fernandes 	LIST_HEAD(allocated);
831ba110db8SJoel Fernandes 	struct gpu_buddy mm;
8324a9671a0SJoel Fernandes 
833ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, size, SZ_4K));
8344a9671a0SJoel Fernandes 
835ba110db8SJoel Fernandes 	KUNIT_EXPECT_EQ_MSG(test, mm.max_order, GPU_BUDDY_MAX_ORDER,
8364a9671a0SJoel Fernandes 			    "mm.max_order(%d) != %d\n", mm.max_order,
837ba110db8SJoel Fernandes 						GPU_BUDDY_MAX_ORDER);
8384a9671a0SJoel Fernandes 
8394a9671a0SJoel Fernandes 	size = mm.chunk_size << mm.max_order;
840ba110db8SJoel Fernandes 	KUNIT_EXPECT_FALSE(test, gpu_buddy_alloc_blocks(&mm, start, size, size,
8414a9671a0SJoel Fernandes 							mm.chunk_size, &allocated, flags));
8424a9671a0SJoel Fernandes 
843ba110db8SJoel Fernandes 	block = list_first_entry_or_null(&allocated, struct gpu_buddy_block, link);
8444a9671a0SJoel Fernandes 	KUNIT_EXPECT_TRUE(test, block);
8454a9671a0SJoel Fernandes 
846ba110db8SJoel Fernandes 	KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_order(block), mm.max_order,
8474a9671a0SJoel Fernandes 			    "block order(%d) != %d\n",
848ba110db8SJoel Fernandes 						gpu_buddy_block_order(block), mm.max_order);
8494a9671a0SJoel Fernandes 
850ba110db8SJoel Fernandes 	KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_size(&mm, block),
8514a9671a0SJoel Fernandes 			    BIT_ULL(mm.max_order) * mm.chunk_size,
8524a9671a0SJoel Fernandes 						"block size(%llu) != %llu\n",
853ba110db8SJoel Fernandes 						gpu_buddy_block_size(&mm, block),
8544a9671a0SJoel Fernandes 						BIT_ULL(mm.max_order) * mm.chunk_size);
8554a9671a0SJoel Fernandes 
856ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &allocated, 0);
857ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
8584a9671a0SJoel Fernandes }
8594a9671a0SJoel Fernandes 
860ba110db8SJoel Fernandes static void gpu_test_buddy_alloc_exceeds_max_order(struct kunit *test)
8614a9671a0SJoel Fernandes {
8624a9671a0SJoel Fernandes 	u64 mm_size = SZ_8G + SZ_2G, size = SZ_8G + SZ_1G, min_block_size = SZ_8G;
863ba110db8SJoel Fernandes 	struct gpu_buddy mm;
8644a9671a0SJoel Fernandes 	LIST_HEAD(blocks);
8654a9671a0SJoel Fernandes 	int err;
8664a9671a0SJoel Fernandes 
867ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
8684a9671a0SJoel Fernandes 			       "buddy_init failed\n");
8694a9671a0SJoel Fernandes 
8704a9671a0SJoel Fernandes 	/* CONTIGUOUS allocation should succeed via try_harder fallback */
871ba110db8SJoel Fernandes 	KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, size,
8724a9671a0SJoel Fernandes 							    SZ_4K, &blocks,
873ba110db8SJoel Fernandes 							    GPU_BUDDY_CONTIGUOUS_ALLOCATION),
8744a9671a0SJoel Fernandes 			       "buddy_alloc hit an error size=%llu\n", size);
875ba110db8SJoel Fernandes 	gpu_buddy_free_list(&mm, &blocks, 0);
8764a9671a0SJoel Fernandes 
8774a9671a0SJoel Fernandes 	/* Non-CONTIGUOUS with large min_block_size should return -EINVAL */
878ba110db8SJoel Fernandes 	err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, min_block_size, &blocks, 0);
8794a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, err, -EINVAL);
8804a9671a0SJoel Fernandes 
8814a9671a0SJoel Fernandes 	/* Non-CONTIGUOUS + RANGE with large min_block_size should return -EINVAL */
882ba110db8SJoel Fernandes 	err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, min_block_size, &blocks,
883ba110db8SJoel Fernandes 				     GPU_BUDDY_RANGE_ALLOCATION);
8844a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, err, -EINVAL);
8854a9671a0SJoel Fernandes 
8864a9671a0SJoel Fernandes 	/* CONTIGUOUS + RANGE should return -EINVAL (no try_harder for RANGE) */
887ba110db8SJoel Fernandes 	err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, SZ_4K, &blocks,
888ba110db8SJoel Fernandes 				     GPU_BUDDY_CONTIGUOUS_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION);
8894a9671a0SJoel Fernandes 	KUNIT_EXPECT_EQ(test, err, -EINVAL);
8904a9671a0SJoel Fernandes 
891ba110db8SJoel Fernandes 	gpu_buddy_fini(&mm);
8924a9671a0SJoel Fernandes }
8934a9671a0SJoel Fernandes 
894ba110db8SJoel Fernandes static int gpu_buddy_suite_init(struct kunit_suite *suite)
8954a9671a0SJoel Fernandes {
8964a9671a0SJoel Fernandes 	while (!random_seed)
8974a9671a0SJoel Fernandes 		random_seed = get_random_u32();
8984a9671a0SJoel Fernandes 
899ba110db8SJoel Fernandes 	kunit_info(suite, "Testing GPU buddy manager, with random_seed=0x%x\n",
9004a9671a0SJoel Fernandes 		   random_seed);
9014a9671a0SJoel Fernandes 
9024a9671a0SJoel Fernandes 	return 0;
9034a9671a0SJoel Fernandes }
9044a9671a0SJoel Fernandes 
905ba110db8SJoel Fernandes static struct kunit_case gpu_buddy_tests[] = {
906ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_limit),
907ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_optimistic),
908ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_pessimistic),
909ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_pathological),
910ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_contiguous),
911ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_clear),
912ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_range_bias),
913*5ea5b6ffSMaxime Ripard 	KUNIT_CASE_SLOW(gpu_test_buddy_fragmentation_performance),
914ba110db8SJoel Fernandes 	KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order),
9154a9671a0SJoel Fernandes 	{}
9164a9671a0SJoel Fernandes };
9174a9671a0SJoel Fernandes 
918ba110db8SJoel Fernandes static struct kunit_suite gpu_buddy_test_suite = {
919ba110db8SJoel Fernandes 	.name = "gpu_buddy",
920ba110db8SJoel Fernandes 	.suite_init = gpu_buddy_suite_init,
921ba110db8SJoel Fernandes 	.test_cases = gpu_buddy_tests,
9224a9671a0SJoel Fernandes };
9234a9671a0SJoel Fernandes 
924ba110db8SJoel Fernandes kunit_test_suite(gpu_buddy_test_suite);
9254a9671a0SJoel Fernandes 
9264a9671a0SJoel Fernandes MODULE_AUTHOR("Intel Corporation");
927ba110db8SJoel Fernandes MODULE_DESCRIPTION("Kunit test for gpu_buddy functions");
9284a9671a0SJoel Fernandes MODULE_LICENSE("GPL");
929