1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2019 Intel Corporation 4 * Copyright © 2022 Maíra Canal <mairacanal@riseup.net> 5 */ 6 7 #include <kunit/test.h> 8 9 #include <linux/prime_numbers.h> 10 #include <linux/sched/signal.h> 11 #include <linux/sizes.h> 12 13 #include <linux/gpu_buddy.h> 14 15 #include "gpu_random.h" 16 17 static unsigned int random_seed; 18 19 static inline u64 get_size(int order, u64 chunk_size) 20 { 21 return (1 << order) * chunk_size; 22 } 23 24 static void gpu_test_buddy_subtree_offset_alignment_stress(struct kunit *test) 25 { 26 struct gpu_buddy_block *block; 27 struct rb_node *node = NULL; 28 const u64 mm_size = SZ_2M; 29 const u64 alignments[] = { 30 SZ_1M, 31 SZ_512K, 32 SZ_256K, 33 SZ_128K, 34 SZ_64K, 35 SZ_32K, 36 SZ_16K, 37 SZ_8K, 38 }; 39 struct list_head allocated[ARRAY_SIZE(alignments)]; 40 unsigned int i, max_subtree_align = 0; 41 int ret, order; 42 struct gpu_buddy mm; 43 44 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 45 "buddy_init failed\n"); 46 47 for (i = 0; i < ARRAY_SIZE(allocated); i++) 48 INIT_LIST_HEAD(&allocated[i]); 49 50 /* 51 * Exercise subtree_max_alignment tracking by allocating blocks with descending 52 * alignment constraints and freeing them in reverse order. This verifies that 53 * free-tree augmentation correctly propagates the maximum offset alignment 54 * present in each subtree at every stage. 55 */ 56 57 for (i = 0; i < ARRAY_SIZE(alignments); i++) { 58 struct gpu_buddy_block *root = NULL; 59 unsigned int expected; 60 u64 align; 61 62 align = alignments[i]; 63 expected = ilog2(align) - 1; 64 65 for (;;) { 66 ret = gpu_buddy_alloc_blocks(&mm, 67 0, mm_size, 68 SZ_4K, align, 69 &allocated[i], 70 0); 71 if (ret) 72 break; 73 74 block = list_last_entry(&allocated[i], 75 struct gpu_buddy_block, 76 link); 77 KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), align)); 78 } 79 80 for (order = mm.max_order; order >= 0 && !root; order--) { 81 node = mm.free_tree[order].rb_node; 82 if (node) 83 root = container_of(node, 84 struct gpu_buddy_block, 85 rb); 86 } 87 88 KUNIT_ASSERT_NOT_NULL(test, root); 89 KUNIT_EXPECT_EQ(test, root->subtree_max_alignment, expected); 90 } 91 92 for (i = ARRAY_SIZE(alignments); i-- > 0; ) { 93 gpu_buddy_free_list(&mm, &allocated[i], 0); 94 95 for (order = 0; order <= mm.max_order; order++) { 96 node = mm.free_tree[order].rb_node; 97 if (!node) 98 continue; 99 100 block = container_of(node, struct gpu_buddy_block, rb); 101 max_subtree_align = max(max_subtree_align, 102 block->subtree_max_alignment); 103 } 104 105 KUNIT_EXPECT_GE(test, max_subtree_align, ilog2(alignments[i])); 106 } 107 108 gpu_buddy_fini(&mm); 109 } 110 111 static void gpu_test_buddy_offset_aligned_allocation(struct kunit *test) 112 { 113 struct gpu_buddy_block *block, *tmp; 114 int num_blocks, i, count = 0; 115 LIST_HEAD(allocated); 116 struct gpu_buddy mm; 117 u64 mm_size = SZ_4M; 118 LIST_HEAD(freed); 119 120 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 121 "buddy_init failed\n"); 122 123 num_blocks = mm_size / SZ_256K; 124 /* 125 * Allocate multiple sizes under a fixed offset alignment. 126 * Ensures alignment handling is independent of allocation size and 127 * exercises subtree max-alignment pruning for small requests. 128 */ 129 for (i = 0; i < num_blocks; i++) 130 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_256K, 131 &allocated, 0), 132 "buddy_alloc hit an error size=%u\n", SZ_8K); 133 134 list_for_each_entry(block, &allocated, link) { 135 /* Ensure the allocated block uses the expected 8 KB size */ 136 KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, block), SZ_8K); 137 /* Ensure the block starts at a 256 KB-aligned offset for proper alignment */ 138 KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), SZ_256K)); 139 } 140 gpu_buddy_free_list(&mm, &allocated, 0); 141 142 for (i = 0; i < num_blocks; i++) 143 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K, 144 &allocated, 0), 145 "buddy_alloc hit an error size=%u\n", SZ_16K); 146 147 list_for_each_entry(block, &allocated, link) { 148 /* Ensure the allocated block uses the expected 16 KB size */ 149 KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, block), SZ_16K); 150 /* Ensure the block starts at a 256 KB-aligned offset for proper alignment */ 151 KUNIT_EXPECT_TRUE(test, IS_ALIGNED(gpu_buddy_block_offset(block), SZ_256K)); 152 } 153 154 /* 155 * Free alternating aligned blocks to introduce fragmentation. 156 * Ensures offset-aligned allocations remain valid after frees and 157 * verifies subtree max-alignment metadata is correctly maintained. 158 */ 159 list_for_each_entry_safe(block, tmp, &allocated, link) { 160 if (count % 2 == 0) 161 list_move_tail(&block->link, &freed); 162 count++; 163 } 164 gpu_buddy_free_list(&mm, &freed, 0); 165 166 for (i = 0; i < num_blocks / 2; i++) 167 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K, 168 &allocated, 0), 169 "buddy_alloc hit an error size=%u\n", SZ_16K); 170 171 /* 172 * Allocate with offset alignment after all slots are used; must fail. 173 * Confirms that no aligned offsets remain. 174 */ 175 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_16K, SZ_256K, 176 &allocated, 0), 177 "buddy_alloc hit an error size=%u\n", SZ_16K); 178 gpu_buddy_free_list(&mm, &allocated, 0); 179 gpu_buddy_fini(&mm); 180 } 181 182 static void gpu_test_buddy_fragmentation_performance(struct kunit *test) 183 { 184 struct gpu_buddy_block *block, *tmp; 185 int num_blocks, i, ret, count = 0; 186 LIST_HEAD(allocated_blocks); 187 unsigned long elapsed_ms; 188 LIST_HEAD(reverse_list); 189 LIST_HEAD(test_blocks); 190 LIST_HEAD(clear_list); 191 LIST_HEAD(dirty_list); 192 LIST_HEAD(free_list); 193 struct gpu_buddy mm; 194 u64 mm_size = SZ_4G; 195 ktime_t start, end; 196 197 /* 198 * Allocation under severe fragmentation 199 * 200 * Create severe fragmentation by allocating the entire 4 GiB address space 201 * as tiny 8 KiB blocks but forcing a 64 KiB alignment. The resulting pattern 202 * leaves many scattered holes. Split the allocations into two groups and 203 * return them with different flags to block coalescing, then repeatedly 204 * allocate and free 64 KiB blocks while timing the loop. This stresses how 205 * quickly the allocator can satisfy larger, aligned requests from a pool of 206 * highly fragmented space. 207 */ 208 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 209 "buddy_init failed\n"); 210 211 num_blocks = mm_size / SZ_64K; 212 213 start = ktime_get(); 214 /* Allocate with maximum fragmentation - 8K blocks with 64K alignment */ 215 for (i = 0; i < num_blocks; i++) 216 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_64K, 217 &allocated_blocks, 0), 218 "buddy_alloc hit an error size=%u\n", SZ_8K); 219 220 list_for_each_entry_safe(block, tmp, &allocated_blocks, link) { 221 if (count % 4 == 0 || count % 4 == 3) 222 list_move_tail(&block->link, &clear_list); 223 else 224 list_move_tail(&block->link, &dirty_list); 225 count++; 226 } 227 228 /* Free with different flags to ensure no coalescing */ 229 gpu_buddy_free_list(&mm, &clear_list, GPU_BUDDY_CLEARED); 230 gpu_buddy_free_list(&mm, &dirty_list, 0); 231 232 for (i = 0; i < num_blocks; i++) 233 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_64K, SZ_64K, 234 &test_blocks, 0), 235 "buddy_alloc hit an error size=%u\n", SZ_64K); 236 gpu_buddy_free_list(&mm, &test_blocks, 0); 237 238 end = ktime_get(); 239 elapsed_ms = ktime_to_ms(ktime_sub(end, start)); 240 241 kunit_info(test, "Fragmented allocation took %lu ms\n", elapsed_ms); 242 243 gpu_buddy_fini(&mm); 244 245 /* 246 * Reverse free order under fragmentation 247 * 248 * Construct a fragmented 4 GiB space by allocating every 8 KiB block with 249 * 64 KiB alignment, creating a dense scatter of small regions. Half of the 250 * blocks are selectively freed to form sparse gaps, while the remaining 251 * allocations are preserved, reordered in reverse, and released back with 252 * the cleared flag. This models a pathological reverse-ordered free pattern 253 * and measures how quickly the allocator can merge and reclaim space when 254 * deallocation occurs in the opposite order of allocation, exposing the 255 * cost difference between a linear freelist scan and an ordered tree lookup. 256 */ 257 ret = gpu_buddy_init(&mm, mm_size, SZ_4K); 258 KUNIT_ASSERT_EQ(test, ret, 0); 259 260 start = ktime_get(); 261 /* Allocate maximum fragmentation */ 262 for (i = 0; i < num_blocks; i++) 263 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, SZ_8K, SZ_64K, 264 &allocated_blocks, 0), 265 "buddy_alloc hit an error size=%u\n", SZ_8K); 266 267 list_for_each_entry_safe(block, tmp, &allocated_blocks, link) { 268 if (count % 2 == 0) 269 list_move_tail(&block->link, &free_list); 270 count++; 271 } 272 gpu_buddy_free_list(&mm, &free_list, GPU_BUDDY_CLEARED); 273 274 list_for_each_entry_safe_reverse(block, tmp, &allocated_blocks, link) 275 list_move(&block->link, &reverse_list); 276 gpu_buddy_free_list(&mm, &reverse_list, GPU_BUDDY_CLEARED); 277 278 end = ktime_get(); 279 elapsed_ms = ktime_to_ms(ktime_sub(end, start)); 280 281 kunit_info(test, "Reverse-ordered free took %lu ms\n", elapsed_ms); 282 283 gpu_buddy_fini(&mm); 284 } 285 286 static void gpu_test_buddy_dirty_tracker_performance(struct kunit *test) 287 { 288 struct gpu_buddy_block *block, *tmp; 289 unsigned long elapsed_ms; 290 LIST_HEAD(clear_blocks); 291 LIST_HEAD(dirty_blocks); 292 LIST_HEAD(allocated); 293 struct gpu_buddy mm; 294 LIST_HEAD(results); 295 ktime_t start, end; 296 int i, count; 297 298 /* 299 * Contiguous alloc latency after alternating clear/dirty fragmentation 300 * 301 * Fill a 4 GiB pool with 4 KiB allocations, partition them into 302 * alternating cleared and dirty sets, then free both. In the old 303 * dual-tree design every adjacent buddy pair has one cleared half and 304 * one dirty half, so the pair sits on opposite sides of the clear/dirty 305 * merge barrier and cannot be coalesced at free() time. The pool 306 * stays fully fragmented and the subsequent contiguous 2 GiB allocation 307 * (smaller than the 4 GiB span so it routes through the contiguous 308 * allocator rather than the exact-range fast path) has to invoke 309 * __force_merge() to rebuild a 2 GiB block before it can succeed. With 310 * the dirty-tracker design buddy pairs coalesce unconditionally during 311 * free(), so the pool is already at max_order before the timed alloc 312 * begins and __force_merge() is not needed. 313 */ 314 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, SZ_4G, SZ_4K), 315 "buddy_init failed\n"); 316 317 for (i = 0; i < SZ_4G / SZ_4K; i++) 318 KUNIT_ASSERT_FALSE_MSG(test, 319 gpu_buddy_alloc_blocks(&mm, 0, SZ_4G, SZ_4K, SZ_4K, 320 &allocated, 0), 321 "buddy_alloc hit an error size=%u\n", SZ_4K); 322 323 count = 0; 324 list_for_each_entry_safe(block, tmp, &allocated, link) { 325 if (count++ % 2 == 0) 326 list_move_tail(&block->link, &clear_blocks); 327 else 328 list_move_tail(&block->link, &dirty_blocks); 329 } 330 331 gpu_buddy_free_list(&mm, &clear_blocks, GPU_BUDDY_CLEARED); 332 gpu_buddy_free_list(&mm, &dirty_blocks, 0); 333 334 start = ktime_get(); 335 KUNIT_ASSERT_FALSE_MSG(test, 336 gpu_buddy_alloc_blocks(&mm, 0, SZ_4G, SZ_2G, SZ_2G, 337 &results, 338 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 339 "contiguous alloc failed\n"); 340 end = ktime_get(); 341 elapsed_ms = ktime_to_ms(ktime_sub(end, start)); 342 343 kunit_info(test, "Contiguous alloc after fragmentation: %lu ms\n", 344 elapsed_ms); 345 346 gpu_buddy_free_list(&mm, &results, 0); 347 gpu_buddy_fini(&mm); 348 349 /* 350 * Repeated alloc throughput from a maximally fragmented pool 351 * 352 * Fill a 4 GiB pool with 4 KiB allocations, free even-indexed blocks 353 * as cleared and odd-indexed blocks as dirty. The alternating pattern 354 * ensures every adjacent buddy pair has one cleared half and one dirty 355 * half, so each pair lands on opposite sides of the old merge barrier. 356 * Each of the 16 384 x 256 KiB allocations in the timed loop asks for a 357 * single contiguous block (size == min_block_size, CONTIGUOUS flag), so 358 * it cannot be satisfied by 64 stray 4 KiB blocks: under the old design 359 * every alloc has to pay the __force_merge() cost to rebuild a 256 KiB 360 * block. With the dirty-tracker design the pool collapses to one 361 * max_order block during free(), so each alloc is a simple O(log N) 362 * split. 363 */ 364 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, SZ_4G, SZ_4K), 365 "buddy_init failed\n"); 366 367 for (i = 0; i < SZ_4G / SZ_4K; i++) 368 KUNIT_ASSERT_FALSE_MSG(test, 369 gpu_buddy_alloc_blocks(&mm, 0, SZ_4G, SZ_4K, SZ_4K, 370 &allocated, 0), 371 "buddy_alloc hit an error size=%u\n", SZ_4K); 372 373 count = 0; 374 list_for_each_entry_safe(block, tmp, &allocated, link) { 375 if (count++ % 2 == 0) 376 list_move_tail(&block->link, &clear_blocks); 377 else 378 list_move_tail(&block->link, &dirty_blocks); 379 } 380 381 gpu_buddy_free_list(&mm, &clear_blocks, GPU_BUDDY_CLEARED); 382 gpu_buddy_free_list(&mm, &dirty_blocks, 0); 383 384 start = ktime_get(); 385 for (i = 0; i < SZ_4G / SZ_256K; i++) 386 KUNIT_ASSERT_FALSE_MSG(test, 387 gpu_buddy_alloc_blocks(&mm, 0, SZ_4G, SZ_256K, SZ_256K, 388 &results, 389 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 390 "buddy_alloc hit an error size=%u\n", SZ_256K); 391 end = ktime_get(); 392 elapsed_ms = ktime_to_ms(ktime_sub(end, start)); 393 394 kunit_info(test, "Repeated 256 KiB allocs from fragmented pool: %lu ms\n", 395 elapsed_ms); 396 397 gpu_buddy_free_list(&mm, &results, 0); 398 gpu_buddy_fini(&mm); 399 } 400 401 static void gpu_test_buddy_alloc_range_bias(struct kunit *test) 402 { 403 u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem; 404 GPU_RND_STATE(prng, random_seed); 405 unsigned int i, count, *order; 406 struct gpu_buddy_block *block; 407 unsigned long flags; 408 struct gpu_buddy mm; 409 LIST_HEAD(allocated); 410 411 bias_size = SZ_1M; 412 ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size); 413 ps = max(SZ_4K, ps); 414 mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */ 415 416 kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps); 417 418 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), 419 "buddy_init failed\n"); 420 421 count = mm_size / bias_size; 422 order = gpu_random_order(count, &prng); 423 KUNIT_EXPECT_TRUE(test, order); 424 425 /* 426 * Idea is to split the address space into uniform bias ranges, and then 427 * in some random order allocate within each bias, using various 428 * patterns within. This should detect if allocations leak out from a 429 * given bias, for example. 430 */ 431 432 for (i = 0; i < count; i++) { 433 LIST_HEAD(tmp); 434 u32 size; 435 436 bias_start = order[i] * bias_size; 437 bias_end = bias_start + bias_size; 438 bias_rem = bias_size; 439 440 /* internal round_up too big */ 441 KUNIT_ASSERT_TRUE_MSG(test, 442 gpu_buddy_alloc_blocks(&mm, bias_start, 443 bias_end, bias_size + ps, bias_size, 444 &allocated, 445 GPU_BUDDY_RANGE_ALLOCATION), 446 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 447 bias_start, bias_end, bias_size, bias_size); 448 449 /* size too big */ 450 KUNIT_ASSERT_TRUE_MSG(test, 451 gpu_buddy_alloc_blocks(&mm, bias_start, 452 bias_end, bias_size + ps, ps, 453 &allocated, 454 GPU_BUDDY_RANGE_ALLOCATION), 455 "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", 456 bias_start, bias_end, bias_size + ps, ps); 457 458 /* bias range too small for size */ 459 KUNIT_ASSERT_TRUE_MSG(test, 460 gpu_buddy_alloc_blocks(&mm, bias_start + ps, 461 bias_end, bias_size, ps, 462 &allocated, 463 GPU_BUDDY_RANGE_ALLOCATION), 464 "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", 465 bias_start + ps, bias_end, bias_size, ps); 466 467 /* bias misaligned */ 468 KUNIT_ASSERT_TRUE_MSG(test, 469 gpu_buddy_alloc_blocks(&mm, bias_start + ps, 470 bias_end - ps, 471 bias_size >> 1, bias_size >> 1, 472 &allocated, 473 GPU_BUDDY_RANGE_ALLOCATION), 474 "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n", 475 bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1); 476 477 /* single big page */ 478 KUNIT_ASSERT_FALSE_MSG(test, 479 gpu_buddy_alloc_blocks(&mm, bias_start, 480 bias_end, bias_size, bias_size, 481 &tmp, 482 GPU_BUDDY_RANGE_ALLOCATION), 483 "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n", 484 bias_start, bias_end, bias_size, bias_size); 485 gpu_buddy_free_list(&mm, &tmp, 0); 486 487 /* single page with internal round_up */ 488 KUNIT_ASSERT_FALSE_MSG(test, 489 gpu_buddy_alloc_blocks(&mm, bias_start, 490 bias_end, ps, bias_size, 491 &tmp, 492 GPU_BUDDY_RANGE_ALLOCATION), 493 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 494 bias_start, bias_end, ps, bias_size); 495 gpu_buddy_free_list(&mm, &tmp, 0); 496 497 /* random size within */ 498 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); 499 if (size) 500 KUNIT_ASSERT_FALSE_MSG(test, 501 gpu_buddy_alloc_blocks(&mm, bias_start, 502 bias_end, size, ps, 503 &tmp, 504 GPU_BUDDY_RANGE_ALLOCATION), 505 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 506 bias_start, bias_end, size, ps); 507 508 bias_rem -= size; 509 /* too big for current avail */ 510 KUNIT_ASSERT_TRUE_MSG(test, 511 gpu_buddy_alloc_blocks(&mm, bias_start, 512 bias_end, bias_rem + ps, ps, 513 &allocated, 514 GPU_BUDDY_RANGE_ALLOCATION), 515 "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", 516 bias_start, bias_end, bias_rem + ps, ps); 517 518 if (bias_rem) { 519 /* random fill of the remainder */ 520 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); 521 size = max(size, ps); 522 523 KUNIT_ASSERT_FALSE_MSG(test, 524 gpu_buddy_alloc_blocks(&mm, bias_start, 525 bias_end, size, ps, 526 &allocated, 527 GPU_BUDDY_RANGE_ALLOCATION), 528 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 529 bias_start, bias_end, size, ps); 530 /* 531 * Intentionally allow some space to be left 532 * unallocated, and ideally not always on the bias 533 * boundaries. 534 */ 535 gpu_buddy_free_list(&mm, &tmp, 0); 536 } else { 537 list_splice_tail(&tmp, &allocated); 538 } 539 } 540 541 kfree(order); 542 gpu_buddy_free_list(&mm, &allocated, 0); 543 gpu_buddy_fini(&mm); 544 545 /* 546 * Something more free-form. Idea is to pick a random starting bias 547 * range within the address space and then start filling it up. Also 548 * randomly grow the bias range in both directions as we go along. This 549 * should give us bias start/end which is not always uniform like above, 550 * and in some cases will require the allocator to jump over already 551 * allocated nodes in the middle of the address space. 552 */ 553 554 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), 555 "buddy_init failed\n"); 556 557 bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); 558 bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); 559 bias_end = max(bias_end, bias_start + ps); 560 bias_rem = bias_end - bias_start; 561 562 do { 563 u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); 564 565 KUNIT_ASSERT_FALSE_MSG(test, 566 gpu_buddy_alloc_blocks(&mm, bias_start, 567 bias_end, size, ps, 568 &allocated, 569 GPU_BUDDY_RANGE_ALLOCATION), 570 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 571 bias_start, bias_end, size, ps); 572 bias_rem -= size; 573 574 /* 575 * Try to randomly grow the bias range in both directions, or 576 * only one, or perhaps don't grow at all. 577 */ 578 do { 579 u32 old_bias_start = bias_start; 580 u32 old_bias_end = bias_end; 581 582 if (bias_start) 583 bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps); 584 if (bias_end != mm_size) 585 bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps); 586 587 bias_rem += old_bias_start - bias_start; 588 bias_rem += bias_end - old_bias_end; 589 } while (!bias_rem && (bias_start || bias_end != mm_size)); 590 } while (bias_rem); 591 592 KUNIT_ASSERT_EQ(test, bias_start, 0); 593 KUNIT_ASSERT_EQ(test, bias_end, mm_size); 594 KUNIT_ASSERT_TRUE_MSG(test, 595 gpu_buddy_alloc_blocks(&mm, bias_start, bias_end, 596 ps, ps, 597 &allocated, 598 GPU_BUDDY_RANGE_ALLOCATION), 599 "buddy_alloc passed with bias(%x-%x), size=%u\n", 600 bias_start, bias_end, ps); 601 602 gpu_buddy_free_list(&mm, &allocated, 0); 603 gpu_buddy_fini(&mm); 604 605 /* 606 * Allocate cleared blocks in the bias range when the GPU buddy's clear avail is 607 * zero. This will validate the bias range allocation in scenarios like system boot 608 * when no cleared blocks are available and exercise the fallback path too. The resulting 609 * blocks should always be dirty. 610 */ 611 612 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), 613 "buddy_init failed\n"); 614 615 bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); 616 bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); 617 bias_end = max(bias_end, bias_start + ps); 618 bias_rem = bias_end - bias_start; 619 620 flags = GPU_BUDDY_CLEAR_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION; 621 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); 622 623 KUNIT_ASSERT_FALSE_MSG(test, 624 gpu_buddy_alloc_blocks(&mm, bias_start, 625 bias_end, size, ps, 626 &allocated, 627 flags), 628 "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", 629 bias_start, bias_end, size, ps); 630 631 list_for_each_entry(block, &allocated, link) 632 KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); 633 634 gpu_buddy_free_list(&mm, &allocated, 0); 635 gpu_buddy_fini(&mm); 636 } 637 638 static void gpu_test_buddy_alloc_range(struct kunit *test) 639 { 640 GPU_RND_STATE(prng, random_seed); 641 struct gpu_buddy_block *block; 642 struct gpu_buddy mm; 643 u32 mm_size, total; 644 LIST_HEAD(blocks); 645 LIST_HEAD(tmp); 646 u32 ps = SZ_4K; 647 int ret; 648 649 mm_size = SZ_16M; 650 651 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), 652 "buddy_init failed\n"); 653 654 /* 655 * Basic exact-range allocation. 656 * Allocate the entire mm as one exact range (start + size == end). 657 * This is the simplest case exercising __gpu_buddy_alloc_range. 658 */ 659 ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &blocks, 0); 660 KUNIT_ASSERT_EQ_MSG(test, ret, 0, 661 "exact-range alloc of full mm failed\n"); 662 663 total = 0; 664 list_for_each_entry(block, &blocks, link) { 665 u64 offset = gpu_buddy_block_offset(block); 666 u64 bsize = gpu_buddy_block_size(&mm, block); 667 668 KUNIT_EXPECT_TRUE_MSG(test, offset + bsize <= (u64)mm_size, 669 "block [%llx, %llx) outside mm\n", offset, offset + bsize); 670 total += (u32)bsize; 671 } 672 KUNIT_EXPECT_EQ(test, total, mm_size); 673 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 674 675 /* Full mm should be exhausted */ 676 ret = gpu_buddy_alloc_blocks(&mm, 0, ps, ps, ps, &tmp, 0); 677 KUNIT_EXPECT_NE_MSG(test, ret, 0, "alloc should fail when mm is full\n"); 678 679 gpu_buddy_free_list(&mm, &blocks, 0); 680 KUNIT_EXPECT_EQ(test, mm.avail, (u64)mm_size); 681 gpu_buddy_fini(&mm); 682 683 /* 684 * Exact-range allocation of sub-ranges. 685 * Split the mm into four equal quarters and allocate each as an exact 686 * range. Validates splitting and non-overlapping exact allocations. 687 */ 688 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 689 690 { 691 u32 quarter = mm_size / 4; 692 int i; 693 694 for (i = 0; i < 4; i++) { 695 u32 start = i * quarter; 696 u32 end = start + quarter; 697 698 ret = gpu_buddy_alloc_blocks(&mm, start, end, quarter, ps, &blocks, 0); 699 KUNIT_ASSERT_EQ_MSG(test, ret, 0, 700 "exact-range alloc quarter %d [%x, %x) failed\n", 701 i, start, end); 702 } 703 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 704 gpu_buddy_free_list(&mm, &blocks, 0); 705 } 706 707 gpu_buddy_fini(&mm); 708 709 /* 710 * Minimum chunk-size exact range at various offsets. 711 * Allocate single-page exact ranges at the start, middle and end. 712 */ 713 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 714 715 ret = gpu_buddy_alloc_blocks(&mm, 0, ps, ps, ps, &blocks, 0); 716 KUNIT_ASSERT_EQ(test, ret, 0); 717 718 ret = gpu_buddy_alloc_blocks(&mm, mm_size / 2, mm_size / 2 + ps, ps, ps, &blocks, 0); 719 KUNIT_ASSERT_EQ(test, ret, 0); 720 721 ret = gpu_buddy_alloc_blocks(&mm, mm_size - ps, mm_size, ps, ps, &blocks, 0); 722 KUNIT_ASSERT_EQ(test, ret, 0); 723 724 total = 0; 725 list_for_each_entry(block, &blocks, link) 726 total += (u32)gpu_buddy_block_size(&mm, block); 727 KUNIT_EXPECT_EQ(test, total, 3 * ps); 728 729 gpu_buddy_free_list(&mm, &blocks, 0); 730 gpu_buddy_fini(&mm); 731 732 /* 733 * Non power-of-two mm size (multiple roots). 734 * Exact-range allocations that span root boundaries must still work. 735 */ 736 mm_size = SZ_4M + SZ_2M + SZ_1M; /* 7 MiB, three roots */ 737 738 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 739 KUNIT_EXPECT_GT(test, mm.n_roots, 1U); 740 741 /* Allocate first 4M root exactly */ 742 ret = gpu_buddy_alloc_blocks(&mm, 0, SZ_4M, SZ_4M, ps, &blocks, 0); 743 KUNIT_ASSERT_EQ(test, ret, 0); 744 745 /* Allocate second root (4M-6M) exactly */ 746 ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_2M, SZ_2M, ps, &blocks, 0); 747 KUNIT_ASSERT_EQ(test, ret, 0); 748 749 /* Allocate third root (6M-7M) exactly */ 750 ret = gpu_buddy_alloc_blocks(&mm, SZ_4M + SZ_2M, mm_size, SZ_1M, ps, &blocks, 0); 751 KUNIT_ASSERT_EQ(test, ret, 0); 752 753 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 754 gpu_buddy_free_list(&mm, &blocks, 0); 755 756 /* Cross-root exact-range: the entire non-pot mm */ 757 ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &blocks, 0); 758 KUNIT_ASSERT_EQ(test, ret, 0); 759 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 760 761 gpu_buddy_free_list(&mm, &blocks, 0); 762 gpu_buddy_fini(&mm); 763 764 /* 765 * Randomized exact-range allocations. 766 * Divide the mm into N random-sized, contiguous, page-aligned slices 767 * and allocate each as an exact range in random order. 768 */ 769 mm_size = SZ_16M; 770 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 771 772 { 773 #define N_RAND_RANGES 16 774 u32 ranges[N_RAND_RANGES + 1]; /* boundaries */ 775 u32 order_arr[N_RAND_RANGES]; 776 u32 remaining = mm_size; 777 int i; 778 779 ranges[0] = 0; 780 for (i = 0; i < N_RAND_RANGES - 1; i++) { 781 u32 max_chunk = remaining - (N_RAND_RANGES - 1 - i) * ps; 782 u32 sz = max(round_up(prandom_u32_state(&prng) % max_chunk, ps), ps); 783 784 ranges[i + 1] = ranges[i] + sz; 785 remaining -= sz; 786 } 787 ranges[N_RAND_RANGES] = mm_size; 788 789 /* Create a random order */ 790 for (i = 0; i < N_RAND_RANGES; i++) 791 order_arr[i] = i; 792 for (i = N_RAND_RANGES - 1; i > 0; i--) { 793 u32 j = prandom_u32_state(&prng) % (i + 1); 794 u32 tmp_val = order_arr[i]; 795 796 order_arr[i] = order_arr[j]; 797 order_arr[j] = tmp_val; 798 } 799 800 for (i = 0; i < N_RAND_RANGES; i++) { 801 u32 idx = order_arr[i]; 802 u32 start = ranges[idx]; 803 u32 end = ranges[idx + 1]; 804 u32 sz = end - start; 805 806 ret = gpu_buddy_alloc_blocks(&mm, start, end, sz, ps, &blocks, 0); 807 KUNIT_ASSERT_EQ_MSG(test, ret, 0, 808 "random exact-range [%x, %x) sz=%x failed\n", 809 start, end, sz); 810 } 811 812 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 813 gpu_buddy_free_list(&mm, &blocks, 0); 814 #undef N_RAND_RANGES 815 } 816 817 gpu_buddy_fini(&mm); 818 819 /* 820 * Negative case - partially allocated range. 821 * Allocate the first half, then try to exact-range allocate the full 822 * mm. This must fail because the first half is already occupied. 823 */ 824 mm_size = SZ_16M; 825 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 826 827 ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size / 2, mm_size / 2, ps, &blocks, 0); 828 KUNIT_ASSERT_EQ(test, ret, 0); 829 830 ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size, mm_size, ps, &tmp, 0); 831 KUNIT_EXPECT_NE_MSG(test, ret, 0, 832 "exact-range alloc should fail when range is partially used\n"); 833 834 /* Also try the already-occupied sub-range directly */ 835 ret = gpu_buddy_alloc_blocks(&mm, 0, mm_size / 2, mm_size / 2, ps, &tmp, 0); 836 KUNIT_EXPECT_NE_MSG(test, ret, 0, 837 "double alloc of same exact range should fail\n"); 838 839 /* The free second half should still be allocatable */ 840 ret = gpu_buddy_alloc_blocks(&mm, mm_size / 2, mm_size, mm_size / 2, ps, &blocks, 0); 841 KUNIT_ASSERT_EQ(test, ret, 0); 842 843 KUNIT_EXPECT_EQ(test, mm.avail, 0ULL); 844 gpu_buddy_free_list(&mm, &blocks, 0); 845 gpu_buddy_fini(&mm); 846 847 /* 848 * Negative case - checkerboard partial allocation. 849 * Allocate every other page-sized chunk in a small mm, then try to 850 * exact-range allocate a range covering two pages (one allocated, one 851 * free). This must fail. 852 */ 853 mm_size = SZ_64K; 854 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 855 856 { 857 u32 off; 858 859 for (off = 0; off < mm_size; off += 2 * ps) { 860 ret = gpu_buddy_alloc_blocks(&mm, off, off + ps, ps, ps, &blocks, 0); 861 KUNIT_ASSERT_EQ(test, ret, 0); 862 } 863 864 /* Try exact range over a pair [allocated, free] */ 865 ret = gpu_buddy_alloc_blocks(&mm, 0, 2 * ps, 2 * ps, ps, &tmp, 0); 866 KUNIT_EXPECT_NE_MSG(test, ret, 0, 867 "exact-range over partially allocated pair should fail\n"); 868 869 /* The free pages individually should still work */ 870 ret = gpu_buddy_alloc_blocks(&mm, ps, 2 * ps, ps, ps, &blocks, 0); 871 KUNIT_ASSERT_EQ(test, ret, 0); 872 873 gpu_buddy_free_list(&mm, &blocks, 0); 874 } 875 876 gpu_buddy_fini(&mm); 877 878 /* Negative case - misaligned start/end/size */ 879 mm_size = SZ_16M; 880 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 881 882 /* start not aligned to chunk_size */ 883 ret = gpu_buddy_alloc_blocks(&mm, ps / 2, ps / 2 + ps, ps, ps, &tmp, 0); 884 KUNIT_EXPECT_NE(test, ret, 0); 885 886 /* size not aligned */ 887 ret = gpu_buddy_alloc_blocks(&mm, 0, ps + 1, ps + 1, ps, &tmp, 0); 888 KUNIT_EXPECT_NE(test, ret, 0); 889 890 /* end exceeds mm size */ 891 ret = gpu_buddy_alloc_blocks(&mm, mm_size, mm_size + ps, ps, ps, &tmp, 0); 892 KUNIT_EXPECT_NE(test, ret, 0); 893 894 gpu_buddy_fini(&mm); 895 896 /* 897 * Free and re-allocate the same exact range. 898 * This exercises merge-on-free followed by exact-range re-split. 899 */ 900 mm_size = SZ_16M; 901 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 902 903 { 904 int i; 905 906 for (i = 0; i < 5; i++) { 907 ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_2M, 908 SZ_2M, ps, &blocks, 0); 909 KUNIT_ASSERT_EQ_MSG(test, ret, 0, 910 "re-alloc iteration %d failed\n", i); 911 912 total = 0; 913 list_for_each_entry(block, &blocks, link) { 914 u64 offset = gpu_buddy_block_offset(block); 915 u64 bsize = gpu_buddy_block_size(&mm, block); 916 917 KUNIT_EXPECT_GE(test, offset, (u64)SZ_4M); 918 KUNIT_EXPECT_LE(test, offset + bsize, (u64)(SZ_4M + SZ_2M)); 919 total += (u32)bsize; 920 } 921 KUNIT_EXPECT_EQ(test, total, SZ_2M); 922 923 gpu_buddy_free_list(&mm, &blocks, 0); 924 } 925 926 KUNIT_EXPECT_EQ(test, mm.avail, (u64)mm_size); 927 } 928 929 gpu_buddy_fini(&mm); 930 931 /* 932 * Various power-of-two exact ranges within a large mm. 933 * Allocate non-overlapping power-of-two exact ranges at their natural 934 * alignment, validating that the allocator handles different orders. 935 */ 936 mm_size = SZ_16M; 937 KUNIT_ASSERT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 938 939 /* Allocate 4K at offset 0 */ 940 ret = gpu_buddy_alloc_blocks(&mm, 0, SZ_4K, SZ_4K, ps, &blocks, 0); 941 KUNIT_ASSERT_EQ(test, ret, 0); 942 943 /* Allocate 64K at offset 64K */ 944 ret = gpu_buddy_alloc_blocks(&mm, SZ_64K, SZ_64K + SZ_64K, SZ_64K, ps, &blocks, 0); 945 KUNIT_ASSERT_EQ(test, ret, 0); 946 947 /* Allocate 1M at offset 1M */ 948 ret = gpu_buddy_alloc_blocks(&mm, SZ_1M, SZ_1M + SZ_1M, SZ_1M, ps, &blocks, 0); 949 KUNIT_ASSERT_EQ(test, ret, 0); 950 951 /* Allocate 4M at offset 4M */ 952 ret = gpu_buddy_alloc_blocks(&mm, SZ_4M, SZ_4M + SZ_4M, SZ_4M, ps, &blocks, 0); 953 KUNIT_ASSERT_EQ(test, ret, 0); 954 955 total = 0; 956 list_for_each_entry(block, &blocks, link) 957 total += (u32)gpu_buddy_block_size(&mm, block); 958 KUNIT_EXPECT_EQ(test, total, SZ_4K + SZ_64K + SZ_1M + SZ_4M); 959 960 gpu_buddy_free_list(&mm, &blocks, 0); 961 gpu_buddy_fini(&mm); 962 } 963 964 static void gpu_test_buddy_alloc_clear(struct kunit *test) 965 { 966 unsigned long n_pages, total, i = 0; 967 const unsigned long ps = SZ_4K; 968 struct gpu_buddy_block *block; 969 const int max_order = 12; 970 LIST_HEAD(allocated); 971 struct gpu_buddy mm; 972 unsigned int order; 973 u32 mm_size, size; 974 LIST_HEAD(dirty); 975 LIST_HEAD(clean); 976 977 mm_size = SZ_4K << max_order; 978 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 979 980 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 981 982 /* 983 * Idea is to allocate and free some random portion of the address space, 984 * returning those pages as non-dirty and randomly alternate between 985 * requesting dirty and non-dirty pages (not going over the limit 986 * we freed as non-dirty), putting that into two separate lists. 987 * Loop over both lists at the end checking that the dirty list 988 * is indeed all dirty pages and vice versa. Free it all again, 989 * keeping the dirty/clear status. 990 */ 991 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 992 5 * ps, ps, &allocated, 993 GPU_BUDDY_TOPDOWN_ALLOCATION), 994 "buddy_alloc hit an error size=%lu\n", 5 * ps); 995 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); 996 997 n_pages = 10; 998 do { 999 unsigned long flags; 1000 struct list_head *list; 1001 int slot = i % 2; 1002 1003 if (slot == 0) { 1004 list = &dirty; 1005 flags = 0; 1006 } else { 1007 list = &clean; 1008 flags = GPU_BUDDY_CLEAR_ALLOCATION; 1009 } 1010 1011 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1012 ps, ps, list, 1013 flags), 1014 "buddy_alloc hit an error size=%lu\n", ps); 1015 } while (++i < n_pages); 1016 1017 list_for_each_entry(block, &clean, link) 1018 KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), true); 1019 1020 list_for_each_entry(block, &dirty, link) 1021 KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); 1022 1023 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); 1024 1025 /* 1026 * Trying to go over the clear limit for some allocation. 1027 * The allocation should never fail with reasonable page-size. 1028 */ 1029 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1030 10 * ps, ps, &clean, 1031 GPU_BUDDY_CLEAR_ALLOCATION), 1032 "buddy_alloc hit an error size=%lu\n", 10 * ps); 1033 1034 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); 1035 gpu_buddy_free_list(&mm, &dirty, 0); 1036 gpu_buddy_fini(&mm); 1037 1038 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 1039 1040 /* 1041 * Create a new mm. Intentionally fragment the address space by creating 1042 * two alternating lists. Free both lists, one as dirty the other as clean. 1043 * Try to allocate double the previous size with matching min_page_size. 1044 * The allocation should never fail because buddy pairs coalesce 1045 * unconditionally at free() time, rebuilding the larger block. Also check 1046 * that the page is always dirty (a merged block spanning a dirty half is 1047 * dirty). Free the page as dirty, then repeat the whole thing, increment 1048 * the order until we hit the max_order. 1049 */ 1050 1051 i = 0; 1052 n_pages = mm_size / ps; 1053 do { 1054 struct list_head *list; 1055 int slot = i % 2; 1056 1057 if (slot == 0) 1058 list = &dirty; 1059 else 1060 list = &clean; 1061 1062 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1063 ps, ps, list, 0), 1064 "buddy_alloc hit an error size=%lu\n", ps); 1065 } while (++i < n_pages); 1066 1067 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); 1068 gpu_buddy_free_list(&mm, &dirty, 0); 1069 1070 order = 1; 1071 do { 1072 size = SZ_4K << order; 1073 1074 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1075 size, size, &allocated, 1076 GPU_BUDDY_CLEAR_ALLOCATION), 1077 "buddy_alloc hit an error size=%u\n", size); 1078 total = 0; 1079 list_for_each_entry(block, &allocated, link) { 1080 if (size != mm_size) 1081 KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); 1082 total += gpu_buddy_block_size(&mm, block); 1083 } 1084 KUNIT_EXPECT_EQ(test, total, size); 1085 1086 gpu_buddy_free_list(&mm, &allocated, 0); 1087 } while (++order <= max_order); 1088 1089 gpu_buddy_fini(&mm); 1090 1091 /* 1092 * Create a new mm with a non power-of-two size. Allocate a random size from each 1093 * root, free as cleared and then call fini. This will ensure the multi-root 1094 * force merge during fini. 1095 */ 1096 mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2)); 1097 1098 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 1099 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1100 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, 1101 4 * ps, ps, &allocated, 1102 GPU_BUDDY_RANGE_ALLOCATION), 1103 "buddy_alloc hit an error size=%lu\n", 4 * ps); 1104 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); 1105 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, 1106 2 * ps, ps, &allocated, 1107 GPU_BUDDY_CLEAR_ALLOCATION), 1108 "buddy_alloc hit an error size=%lu\n", 2 * ps); 1109 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); 1110 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size, 1111 ps, ps, &allocated, 1112 GPU_BUDDY_RANGE_ALLOCATION), 1113 "buddy_alloc hit an error size=%lu\n", ps); 1114 gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); 1115 gpu_buddy_fini(&mm); 1116 1117 /* 1118 * Using a non-power-of-two mm size, allocate all 4KiB blocks and split 1119 * them across two alternating lists, then free one list as cleared and 1120 * the other as dirty. This interleaves cleared and dirty blocks so that 1121 * neighbouring buddies cannot be merged, fragmenting the address space. 1122 * After gpu_buddy_reset_clear(false) every block should be marked dirty 1123 * and the split blocks should be merged back to their original size, so 1124 * clear_avail must drop to 0. 1125 */ 1126 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 1127 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1128 1129 n_pages = mm_size / ps; 1130 for (i = 0; i < n_pages; i++) { 1131 struct list_head *list = (i % 2) ? &clean : &dirty; 1132 1133 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1134 ps, ps, list, 0), 1135 "buddy_alloc hit an error size=%lu\n", ps); 1136 } 1137 1138 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); 1139 gpu_buddy_free_list(&mm, &dirty, 0); 1140 gpu_buddy_reset_clear(&mm, false); 1141 KUNIT_EXPECT_EQ(test, gpu_buddy_clear_avail(&mm), 0); 1142 gpu_buddy_fini(&mm); 1143 1144 /* 1145 * Repeat the same fragmented setup, but this time call 1146 * gpu_buddy_reset_clear(true). Every block should be marked cleared and 1147 * the split blocks should be merged back to their original size, so the 1148 * whole address space (clear_avail) must equal mm_size. 1149 */ 1150 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 1151 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1152 1153 for (i = 0; i < n_pages; i++) { 1154 struct list_head *list = (i % 2) ? &clean : &dirty; 1155 1156 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1157 ps, ps, list, 0), 1158 "buddy_alloc hit an error size=%lu\n", ps); 1159 } 1160 1161 gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); 1162 gpu_buddy_free_list(&mm, &dirty, 0); 1163 gpu_buddy_reset_clear(&mm, true); 1164 KUNIT_EXPECT_EQ(test, gpu_buddy_clear_avail(&mm), mm_size); 1165 gpu_buddy_fini(&mm); 1166 } 1167 1168 static void gpu_test_buddy_alloc_contiguous(struct kunit *test) 1169 { 1170 const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K; 1171 unsigned long i, n_pages, total; 1172 struct gpu_buddy_block *block; 1173 struct gpu_buddy mm; 1174 LIST_HEAD(left); 1175 LIST_HEAD(middle); 1176 LIST_HEAD(right); 1177 LIST_HEAD(allocated); 1178 1179 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); 1180 1181 /* 1182 * Idea is to fragment the address space by alternating block 1183 * allocations between three different lists; one for left, middle and 1184 * right. We can then free a list to simulate fragmentation. In 1185 * particular we want to exercise the GPU_BUDDY_CONTIGUOUS_ALLOCATION, 1186 * including the try_harder path. 1187 */ 1188 1189 i = 0; 1190 n_pages = mm_size / ps; 1191 do { 1192 struct list_head *list; 1193 int slot = i % 3; 1194 1195 if (slot == 0) 1196 list = &left; 1197 else if (slot == 1) 1198 list = &middle; 1199 else 1200 list = &right; 1201 KUNIT_ASSERT_FALSE_MSG(test, 1202 gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1203 ps, ps, list, 0), 1204 "buddy_alloc hit an error size=%lu\n", 1205 ps); 1206 } while (++i < n_pages); 1207 1208 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1209 3 * ps, ps, &allocated, 1210 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1211 "buddy_alloc didn't error size=%lu\n", 3 * ps); 1212 1213 gpu_buddy_free_list(&mm, &middle, 0); 1214 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1215 3 * ps, ps, &allocated, 1216 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1217 "buddy_alloc didn't error size=%lu\n", 3 * ps); 1218 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1219 2 * ps, ps, &allocated, 1220 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1221 "buddy_alloc didn't error size=%lu\n", 2 * ps); 1222 1223 gpu_buddy_free_list(&mm, &right, 0); 1224 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1225 3 * ps, ps, &allocated, 1226 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1227 "buddy_alloc didn't error size=%lu\n", 3 * ps); 1228 /* 1229 * At this point we should have enough contiguous space for 2 blocks, 1230 * however they are never buddies (since we freed middle and right) so 1231 * will require the try_harder logic to find them. 1232 */ 1233 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1234 2 * ps, ps, &allocated, 1235 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1236 "buddy_alloc hit an error size=%lu\n", 2 * ps); 1237 1238 gpu_buddy_free_list(&mm, &left, 0); 1239 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, 1240 3 * ps, ps, &allocated, 1241 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1242 "buddy_alloc hit an error size=%lu\n", 3 * ps); 1243 1244 total = 0; 1245 list_for_each_entry(block, &allocated, link) 1246 total += gpu_buddy_block_size(&mm, block); 1247 1248 KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3); 1249 1250 gpu_buddy_free_list(&mm, &allocated, 0); 1251 gpu_buddy_fini(&mm); 1252 } 1253 1254 static void gpu_test_buddy_alloc_pathological(struct kunit *test) 1255 { 1256 u64 mm_size, size, start = 0; 1257 struct gpu_buddy_block *block; 1258 const int max_order = 3; 1259 unsigned long flags = 0; 1260 int order, top; 1261 struct gpu_buddy mm; 1262 LIST_HEAD(blocks); 1263 LIST_HEAD(holes); 1264 LIST_HEAD(tmp); 1265 1266 /* 1267 * Create a pot-sized mm, then allocate one of each possible 1268 * order within. This should leave the mm with exactly one 1269 * page left. Free the largest block, then whittle down again. 1270 * Eventually we will have a fully 50% fragmented mm. 1271 */ 1272 1273 mm_size = SZ_4K << max_order; 1274 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 1275 "buddy_init failed\n"); 1276 1277 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1278 1279 for (top = max_order; top; top--) { 1280 /* Make room by freeing the largest allocated block */ 1281 block = list_first_entry_or_null(&blocks, typeof(*block), link); 1282 if (block) { 1283 list_del(&block->link); 1284 gpu_buddy_free_block(&mm, block); 1285 } 1286 1287 for (order = top; order--;) { 1288 size = get_size(order, mm.chunk_size); 1289 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, 1290 mm_size, size, size, 1291 &tmp, flags), 1292 "buddy_alloc hit -ENOMEM with order=%d, top=%d\n", 1293 order, top); 1294 1295 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1296 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1297 1298 list_move_tail(&block->link, &blocks); 1299 } 1300 1301 /* There should be one final page for this sub-allocation */ 1302 size = get_size(0, mm.chunk_size); 1303 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1304 size, size, &tmp, flags), 1305 "buddy_alloc hit -ENOMEM for hole\n"); 1306 1307 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1308 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1309 1310 list_move_tail(&block->link, &holes); 1311 1312 size = get_size(top, mm.chunk_size); 1313 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1314 size, size, &tmp, flags), 1315 "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", 1316 top, max_order); 1317 } 1318 1319 gpu_buddy_free_list(&mm, &holes, 0); 1320 1321 /* Nothing larger than blocks of chunk_size now available */ 1322 for (order = 1; order <= max_order; order++) { 1323 size = get_size(order, mm.chunk_size); 1324 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1325 size, size, &tmp, flags), 1326 "buddy_alloc unexpectedly succeeded at order %d, it should be full!", 1327 order); 1328 } 1329 1330 list_splice_tail(&holes, &blocks); 1331 gpu_buddy_free_list(&mm, &blocks, 0); 1332 gpu_buddy_fini(&mm); 1333 } 1334 1335 static void gpu_test_buddy_alloc_pessimistic(struct kunit *test) 1336 { 1337 u64 mm_size, size, start = 0; 1338 struct gpu_buddy_block *block, *bn; 1339 const unsigned int max_order = 16; 1340 unsigned long flags = 0; 1341 struct gpu_buddy mm; 1342 unsigned int order; 1343 LIST_HEAD(blocks); 1344 LIST_HEAD(tmp); 1345 1346 /* 1347 * Create a pot-sized mm, then allocate one of each possible 1348 * order within. This should leave the mm with exactly one 1349 * page left. 1350 */ 1351 1352 mm_size = SZ_4K << max_order; 1353 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 1354 "buddy_init failed\n"); 1355 1356 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1357 1358 for (order = 0; order < max_order; order++) { 1359 size = get_size(order, mm.chunk_size); 1360 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1361 size, size, &tmp, flags), 1362 "buddy_alloc hit -ENOMEM with order=%d\n", 1363 order); 1364 1365 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1366 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1367 1368 list_move_tail(&block->link, &blocks); 1369 } 1370 1371 /* And now the last remaining block available */ 1372 size = get_size(0, mm.chunk_size); 1373 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1374 size, size, &tmp, flags), 1375 "buddy_alloc hit -ENOMEM on final alloc\n"); 1376 1377 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1378 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1379 1380 list_move_tail(&block->link, &blocks); 1381 1382 /* Should be completely full! */ 1383 for (order = max_order; order--;) { 1384 size = get_size(order, mm.chunk_size); 1385 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1386 size, size, &tmp, flags), 1387 "buddy_alloc unexpectedly succeeded, it should be full!"); 1388 } 1389 1390 block = list_last_entry(&blocks, typeof(*block), link); 1391 list_del(&block->link); 1392 gpu_buddy_free_block(&mm, block); 1393 1394 /* As we free in increasing size, we make available larger blocks */ 1395 order = 1; 1396 list_for_each_entry_safe(block, bn, &blocks, link) { 1397 list_del(&block->link); 1398 gpu_buddy_free_block(&mm, block); 1399 1400 size = get_size(order, mm.chunk_size); 1401 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1402 size, size, &tmp, flags), 1403 "buddy_alloc hit -ENOMEM with order=%d\n", 1404 order); 1405 1406 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1407 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1408 1409 list_del(&block->link); 1410 gpu_buddy_free_block(&mm, block); 1411 order++; 1412 } 1413 1414 /* To confirm, now the whole mm should be available */ 1415 size = get_size(max_order, mm.chunk_size); 1416 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1417 size, size, &tmp, flags), 1418 "buddy_alloc (realloc) hit -ENOMEM with order=%d\n", 1419 max_order); 1420 1421 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1422 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1423 1424 list_del(&block->link); 1425 gpu_buddy_free_block(&mm, block); 1426 gpu_buddy_free_list(&mm, &blocks, 0); 1427 gpu_buddy_fini(&mm); 1428 } 1429 1430 static void gpu_test_buddy_alloc_optimistic(struct kunit *test) 1431 { 1432 u64 mm_size, size, start = 0; 1433 struct gpu_buddy_block *block; 1434 unsigned long flags = 0; 1435 const int max_order = 16; 1436 struct gpu_buddy mm; 1437 LIST_HEAD(blocks); 1438 LIST_HEAD(tmp); 1439 int order; 1440 1441 /* 1442 * Create a mm with one block of each order available, and 1443 * try to allocate them all. 1444 */ 1445 1446 mm_size = SZ_4K * ((1 << (max_order + 1)) - 1); 1447 1448 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 1449 "buddy_init failed\n"); 1450 1451 KUNIT_EXPECT_EQ(test, mm.max_order, max_order); 1452 1453 for (order = 0; order <= max_order; order++) { 1454 size = get_size(order, mm.chunk_size); 1455 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1456 size, size, &tmp, flags), 1457 "buddy_alloc hit -ENOMEM with order=%d\n", 1458 order); 1459 1460 block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); 1461 KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); 1462 1463 list_move_tail(&block->link, &blocks); 1464 } 1465 1466 /* Should be completely full! */ 1467 size = get_size(0, mm.chunk_size); 1468 KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, 1469 size, size, &tmp, flags), 1470 "buddy_alloc unexpectedly succeeded, it should be full!"); 1471 1472 gpu_buddy_free_list(&mm, &blocks, 0); 1473 gpu_buddy_fini(&mm); 1474 } 1475 1476 static void gpu_test_buddy_alloc_limit(struct kunit *test) 1477 { 1478 u64 size = U64_MAX, start = 0; 1479 struct gpu_buddy_block *block; 1480 unsigned long flags = 0; 1481 LIST_HEAD(allocated); 1482 struct gpu_buddy mm; 1483 1484 KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, size, SZ_4K)); 1485 1486 KUNIT_EXPECT_EQ_MSG(test, mm.max_order, GPU_BUDDY_MAX_ORDER, 1487 "mm.max_order(%d) != %d\n", mm.max_order, 1488 GPU_BUDDY_MAX_ORDER); 1489 1490 size = mm.chunk_size << mm.max_order; 1491 KUNIT_EXPECT_FALSE(test, gpu_buddy_alloc_blocks(&mm, start, size, size, 1492 mm.chunk_size, &allocated, flags)); 1493 1494 block = list_first_entry_or_null(&allocated, struct gpu_buddy_block, link); 1495 KUNIT_EXPECT_TRUE(test, block); 1496 1497 KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_order(block), mm.max_order, 1498 "block order(%d) != %d\n", 1499 gpu_buddy_block_order(block), mm.max_order); 1500 1501 KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_size(&mm, block), 1502 BIT_ULL(mm.max_order) * mm.chunk_size, 1503 "block size(%llu) != %llu\n", 1504 gpu_buddy_block_size(&mm, block), 1505 BIT_ULL(mm.max_order) * mm.chunk_size); 1506 1507 gpu_buddy_free_list(&mm, &allocated, 0); 1508 gpu_buddy_fini(&mm); 1509 } 1510 1511 static void gpu_test_buddy_alloc_exceeds_max_order(struct kunit *test) 1512 { 1513 u64 mm_size = SZ_8G + SZ_2G, size = SZ_8G + SZ_1G, min_block_size = SZ_8G; 1514 struct gpu_buddy mm; 1515 LIST_HEAD(blocks); 1516 int err; 1517 1518 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), 1519 "buddy_init failed\n"); 1520 1521 /* CONTIGUOUS allocation should succeed via try_harder fallback */ 1522 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, 1523 SZ_4K, &blocks, 1524 GPU_BUDDY_CONTIGUOUS_ALLOCATION), 1525 "buddy_alloc hit an error size=%llu\n", size); 1526 gpu_buddy_free_list(&mm, &blocks, 0); 1527 1528 /* Non-CONTIGUOUS with large min_block_size should return -EINVAL */ 1529 err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, min_block_size, &blocks, 0); 1530 KUNIT_EXPECT_EQ(test, err, -EINVAL); 1531 1532 /* Non-CONTIGUOUS + RANGE with large min_block_size should return -EINVAL */ 1533 err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, min_block_size, &blocks, 1534 GPU_BUDDY_RANGE_ALLOCATION); 1535 KUNIT_EXPECT_EQ(test, err, -EINVAL); 1536 1537 /* CONTIGUOUS + RANGE should return -EINVAL (no try_harder for RANGE) */ 1538 err = gpu_buddy_alloc_blocks(&mm, 0, mm_size, size, SZ_4K, &blocks, 1539 GPU_BUDDY_CONTIGUOUS_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION); 1540 KUNIT_EXPECT_EQ(test, err, -EINVAL); 1541 1542 gpu_buddy_fini(&mm); 1543 } 1544 1545 static void gpu_test_buddy_addr_to_block(struct kunit *test) 1546 { 1547 struct gpu_buddy_block *allocated_block, *found_block; 1548 LIST_HEAD(allocated_list); 1549 const u64 test_size = SZ_4M + SZ_2M; 1550 const u64 alloc_start = SZ_4M; 1551 const u64 alloc_size = SZ_4K; 1552 const u64 chunk_size = SZ_4K; 1553 struct gpu_buddy mm; 1554 1555 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, test_size, chunk_size), 1556 "buddy_init failed\n"); 1557 1558 KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, alloc_start, 1559 alloc_start + alloc_size, 1560 alloc_size, chunk_size, 1561 &allocated_list, 0), 1562 "buddy_alloc failed\n"); 1563 1564 allocated_block = list_first_entry(&allocated_list, struct gpu_buddy_block, link); 1565 KUNIT_EXPECT_EQ(test, gpu_buddy_block_offset(allocated_block), alloc_start); 1566 KUNIT_EXPECT_EQ(test, gpu_buddy_block_size(&mm, allocated_block), alloc_size); 1567 1568 found_block = gpu_buddy_allocated_addr_to_block(&mm, alloc_start); 1569 KUNIT_EXPECT_PTR_EQ(test, found_block, allocated_block); 1570 1571 /* Unaligned address inside the allocated block (should resolve to the same block) */ 1572 found_block = gpu_buddy_allocated_addr_to_block(&mm, alloc_start + 16); 1573 KUNIT_EXPECT_PTR_EQ(test, found_block, allocated_block); 1574 1575 /* An unallocated address inside the manager should return NULL. */ 1576 found_block = gpu_buddy_allocated_addr_to_block(&mm, 1577 alloc_start - chunk_size); 1578 KUNIT_EXPECT_NULL(test, found_block); 1579 1580 /* An address outside the manager should return -ENXIO. */ 1581 found_block = gpu_buddy_allocated_addr_to_block(&mm, test_size); 1582 KUNIT_EXPECT_EQ(test, PTR_ERR(found_block), -ENXIO); 1583 1584 /* 3. Standard inline cleanup flow */ 1585 gpu_buddy_free_list(&mm, &allocated_list, 0); 1586 gpu_buddy_fini(&mm); 1587 } 1588 1589 static int gpu_buddy_suite_init(struct kunit_suite *suite) 1590 { 1591 while (!random_seed) 1592 random_seed = get_random_u32(); 1593 1594 kunit_info(suite, "Testing GPU buddy manager, with random_seed=0x%x\n", 1595 random_seed); 1596 1597 return 0; 1598 } 1599 1600 static struct kunit_case gpu_buddy_tests[] = { 1601 KUNIT_CASE(gpu_test_buddy_alloc_limit), 1602 KUNIT_CASE(gpu_test_buddy_alloc_optimistic), 1603 KUNIT_CASE(gpu_test_buddy_alloc_pessimistic), 1604 KUNIT_CASE(gpu_test_buddy_alloc_pathological), 1605 KUNIT_CASE(gpu_test_buddy_alloc_contiguous), 1606 KUNIT_CASE(gpu_test_buddy_alloc_clear), 1607 KUNIT_CASE(gpu_test_buddy_alloc_range), 1608 KUNIT_CASE(gpu_test_buddy_alloc_range_bias), 1609 KUNIT_CASE_SLOW(gpu_test_buddy_fragmentation_performance), 1610 KUNIT_CASE_SLOW(gpu_test_buddy_dirty_tracker_performance), 1611 KUNIT_CASE(gpu_test_buddy_alloc_exceeds_max_order), 1612 KUNIT_CASE(gpu_test_buddy_offset_aligned_allocation), 1613 KUNIT_CASE(gpu_test_buddy_subtree_offset_alignment_stress), 1614 KUNIT_CASE(gpu_test_buddy_addr_to_block), 1615 {} 1616 }; 1617 1618 static struct kunit_suite gpu_buddy_test_suite = { 1619 .name = "gpu_buddy", 1620 .suite_init = gpu_buddy_suite_init, 1621 .test_cases = gpu_buddy_tests, 1622 }; 1623 1624 kunit_test_suite(gpu_buddy_test_suite); 1625 1626 MODULE_AUTHOR("Intel Corporation"); 1627 MODULE_DESCRIPTION("Kunit test for gpu_buddy functions"); 1628 MODULE_LICENSE("GPL"); 1629