Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.18-rc6 992 lines 21 kB view raw
1// SPDX-License-Identifier: MIT 2/* 3 * Copyright © 2019 Intel Corporation 4 */ 5 6#define pr_fmt(fmt) "drm_buddy: " fmt 7 8#include <linux/module.h> 9#include <linux/prime_numbers.h> 10#include <linux/sched/signal.h> 11 12#include <drm/drm_buddy.h> 13 14#include "../lib/drm_random.h" 15 16#define TESTS "drm_buddy_selftests.h" 17#include "drm_selftest.h" 18 19#define IGT_TIMEOUT(name__) \ 20 unsigned long name__ = jiffies + MAX_SCHEDULE_TIMEOUT 21 22static unsigned int random_seed; 23 24static inline u64 get_size(int order, u64 chunk_size) 25{ 26 return (1 << order) * chunk_size; 27} 28 29__printf(2, 3) 30static bool __igt_timeout(unsigned long timeout, const char *fmt, ...) 31{ 32 va_list va; 33 34 if (!signal_pending(current)) { 35 cond_resched(); 36 if (time_before(jiffies, timeout)) 37 return false; 38 } 39 40 if (fmt) { 41 va_start(va, fmt); 42 vprintk(fmt, va); 43 va_end(va); 44 } 45 46 return true; 47} 48 49static inline const char *yesno(bool v) 50{ 51 return v ? "yes" : "no"; 52} 53 54static void __igt_dump_block(struct drm_buddy *mm, 55 struct drm_buddy_block *block, 56 bool buddy) 57{ 58 pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n", 59 block->header, 60 drm_buddy_block_state(block), 61 drm_buddy_block_order(block), 62 drm_buddy_block_offset(block), 63 drm_buddy_block_size(mm, block), 64 yesno(!block->parent), 65 yesno(buddy)); 66} 67 68static void igt_dump_block(struct drm_buddy *mm, 69 struct drm_buddy_block *block) 70{ 71 struct drm_buddy_block *buddy; 72 73 __igt_dump_block(mm, block, false); 74 75 buddy = drm_get_buddy(block); 76 if (buddy) 77 __igt_dump_block(mm, buddy, true); 78} 79 80static int igt_check_block(struct drm_buddy *mm, 81 struct drm_buddy_block *block) 82{ 83 struct drm_buddy_block *buddy; 84 unsigned int block_state; 85 u64 block_size; 86 u64 offset; 87 int err = 0; 88 89 block_state = drm_buddy_block_state(block); 90 91 if (block_state != DRM_BUDDY_ALLOCATED && 92 block_state != DRM_BUDDY_FREE && 93 block_state != DRM_BUDDY_SPLIT) { 94 pr_err("block state mismatch\n"); 95 err = -EINVAL; 96 } 97 98 block_size = drm_buddy_block_size(mm, block); 99 offset = drm_buddy_block_offset(block); 100 101 if (block_size < mm->chunk_size) { 102 pr_err("block size smaller than min size\n"); 103 err = -EINVAL; 104 } 105 106 if (!is_power_of_2(block_size)) { 107 pr_err("block size not power of two\n"); 108 err = -EINVAL; 109 } 110 111 if (!IS_ALIGNED(block_size, mm->chunk_size)) { 112 pr_err("block size not aligned to min size\n"); 113 err = -EINVAL; 114 } 115 116 if (!IS_ALIGNED(offset, mm->chunk_size)) { 117 pr_err("block offset not aligned to min size\n"); 118 err = -EINVAL; 119 } 120 121 if (!IS_ALIGNED(offset, block_size)) { 122 pr_err("block offset not aligned to block size\n"); 123 err = -EINVAL; 124 } 125 126 buddy = drm_get_buddy(block); 127 128 if (!buddy && block->parent) { 129 pr_err("buddy has gone fishing\n"); 130 err = -EINVAL; 131 } 132 133 if (buddy) { 134 if (drm_buddy_block_offset(buddy) != (offset ^ block_size)) { 135 pr_err("buddy has wrong offset\n"); 136 err = -EINVAL; 137 } 138 139 if (drm_buddy_block_size(mm, buddy) != block_size) { 140 pr_err("buddy size mismatch\n"); 141 err = -EINVAL; 142 } 143 144 if (drm_buddy_block_state(buddy) == block_state && 145 block_state == DRM_BUDDY_FREE) { 146 pr_err("block and its buddy are free\n"); 147 err = -EINVAL; 148 } 149 } 150 151 return err; 152} 153 154static int igt_check_blocks(struct drm_buddy *mm, 155 struct list_head *blocks, 156 u64 expected_size, 157 bool is_contiguous) 158{ 159 struct drm_buddy_block *block; 160 struct drm_buddy_block *prev; 161 u64 total; 162 int err = 0; 163 164 block = NULL; 165 prev = NULL; 166 total = 0; 167 168 list_for_each_entry(block, blocks, link) { 169 err = igt_check_block(mm, block); 170 171 if (!drm_buddy_block_is_allocated(block)) { 172 pr_err("block not allocated\n"), 173 err = -EINVAL; 174 } 175 176 if (is_contiguous && prev) { 177 u64 prev_block_size; 178 u64 prev_offset; 179 u64 offset; 180 181 prev_offset = drm_buddy_block_offset(prev); 182 prev_block_size = drm_buddy_block_size(mm, prev); 183 offset = drm_buddy_block_offset(block); 184 185 if (offset != (prev_offset + prev_block_size)) { 186 pr_err("block offset mismatch\n"); 187 err = -EINVAL; 188 } 189 } 190 191 if (err) 192 break; 193 194 total += drm_buddy_block_size(mm, block); 195 prev = block; 196 } 197 198 if (!err) { 199 if (total != expected_size) { 200 pr_err("size mismatch, expected=%llx, found=%llx\n", 201 expected_size, total); 202 err = -EINVAL; 203 } 204 return err; 205 } 206 207 if (prev) { 208 pr_err("prev block, dump:\n"); 209 igt_dump_block(mm, prev); 210 } 211 212 pr_err("bad block, dump:\n"); 213 igt_dump_block(mm, block); 214 215 return err; 216} 217 218static int igt_check_mm(struct drm_buddy *mm) 219{ 220 struct drm_buddy_block *root; 221 struct drm_buddy_block *prev; 222 unsigned int i; 223 u64 total; 224 int err = 0; 225 226 if (!mm->n_roots) { 227 pr_err("n_roots is zero\n"); 228 return -EINVAL; 229 } 230 231 if (mm->n_roots != hweight64(mm->size)) { 232 pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n", 233 mm->n_roots, hweight64(mm->size)); 234 return -EINVAL; 235 } 236 237 root = NULL; 238 prev = NULL; 239 total = 0; 240 241 for (i = 0; i < mm->n_roots; ++i) { 242 struct drm_buddy_block *block; 243 unsigned int order; 244 245 root = mm->roots[i]; 246 if (!root) { 247 pr_err("root(%u) is NULL\n", i); 248 err = -EINVAL; 249 break; 250 } 251 252 err = igt_check_block(mm, root); 253 254 if (!drm_buddy_block_is_free(root)) { 255 pr_err("root not free\n"); 256 err = -EINVAL; 257 } 258 259 order = drm_buddy_block_order(root); 260 261 if (!i) { 262 if (order != mm->max_order) { 263 pr_err("max order root missing\n"); 264 err = -EINVAL; 265 } 266 } 267 268 if (prev) { 269 u64 prev_block_size; 270 u64 prev_offset; 271 u64 offset; 272 273 prev_offset = drm_buddy_block_offset(prev); 274 prev_block_size = drm_buddy_block_size(mm, prev); 275 offset = drm_buddy_block_offset(root); 276 277 if (offset != (prev_offset + prev_block_size)) { 278 pr_err("root offset mismatch\n"); 279 err = -EINVAL; 280 } 281 } 282 283 block = list_first_entry_or_null(&mm->free_list[order], 284 struct drm_buddy_block, 285 link); 286 if (block != root) { 287 pr_err("root mismatch at order=%u\n", order); 288 err = -EINVAL; 289 } 290 291 if (err) 292 break; 293 294 prev = root; 295 total += drm_buddy_block_size(mm, root); 296 } 297 298 if (!err) { 299 if (total != mm->size) { 300 pr_err("expected mm size=%llx, found=%llx\n", mm->size, 301 total); 302 err = -EINVAL; 303 } 304 return err; 305 } 306 307 if (prev) { 308 pr_err("prev root(%u), dump:\n", i - 1); 309 igt_dump_block(mm, prev); 310 } 311 312 if (root) { 313 pr_err("bad root(%u), dump:\n", i); 314 igt_dump_block(mm, root); 315 } 316 317 return err; 318} 319 320static void igt_mm_config(u64 *size, u64 *chunk_size) 321{ 322 DRM_RND_STATE(prng, random_seed); 323 u32 s, ms; 324 325 /* Nothing fancy, just try to get an interesting bit pattern */ 326 327 prandom_seed_state(&prng, random_seed); 328 329 /* Let size be a random number of pages up to 8 GB (2M pages) */ 330 s = 1 + drm_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); 331 /* Let the chunk size be a random power of 2 less than size */ 332 ms = BIT(drm_prandom_u32_max_state(ilog2(s), &prng)); 333 /* Round size down to the chunk size */ 334 s &= -ms; 335 336 /* Convert from pages to bytes */ 337 *chunk_size = (u64)ms << 12; 338 *size = (u64)s << 12; 339} 340 341static int igt_buddy_alloc_pathological(void *arg) 342{ 343 u64 mm_size, size, min_page_size, start = 0; 344 struct drm_buddy_block *block; 345 const int max_order = 3; 346 unsigned long flags = 0; 347 int order, top, err; 348 struct drm_buddy mm; 349 LIST_HEAD(blocks); 350 LIST_HEAD(holes); 351 LIST_HEAD(tmp); 352 353 /* 354 * Create a pot-sized mm, then allocate one of each possible 355 * order within. This should leave the mm with exactly one 356 * page left. Free the largest block, then whittle down again. 357 * Eventually we will have a fully 50% fragmented mm. 358 */ 359 360 mm_size = PAGE_SIZE << max_order; 361 err = drm_buddy_init(&mm, mm_size, PAGE_SIZE); 362 if (err) { 363 pr_err("buddy_init failed(%d)\n", err); 364 return err; 365 } 366 BUG_ON(mm.max_order != max_order); 367 368 for (top = max_order; top; top--) { 369 /* Make room by freeing the largest allocated block */ 370 block = list_first_entry_or_null(&blocks, typeof(*block), link); 371 if (block) { 372 list_del(&block->link); 373 drm_buddy_free_block(&mm, block); 374 } 375 376 for (order = top; order--; ) { 377 size = min_page_size = get_size(order, PAGE_SIZE); 378 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, 379 min_page_size, &tmp, flags); 380 if (err) { 381 pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n", 382 order, top); 383 goto err; 384 } 385 386 block = list_first_entry_or_null(&tmp, 387 struct drm_buddy_block, 388 link); 389 if (!block) { 390 pr_err("alloc_blocks has no blocks\n"); 391 err = -EINVAL; 392 goto err; 393 } 394 395 list_move_tail(&block->link, &blocks); 396 } 397 398 /* There should be one final page for this sub-allocation */ 399 size = min_page_size = get_size(0, PAGE_SIZE); 400 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 401 if (err) { 402 pr_info("buddy_alloc hit -ENOMEM for hole\n"); 403 goto err; 404 } 405 406 block = list_first_entry_or_null(&tmp, 407 struct drm_buddy_block, 408 link); 409 if (!block) { 410 pr_err("alloc_blocks has no blocks\n"); 411 err = -EINVAL; 412 goto err; 413 } 414 415 list_move_tail(&block->link, &holes); 416 417 size = min_page_size = get_size(top, PAGE_SIZE); 418 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 419 if (!err) { 420 pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", 421 top, max_order); 422 block = list_first_entry_or_null(&tmp, 423 struct drm_buddy_block, 424 link); 425 if (!block) { 426 pr_err("alloc_blocks has no blocks\n"); 427 err = -EINVAL; 428 goto err; 429 } 430 431 list_move_tail(&block->link, &blocks); 432 err = -EINVAL; 433 goto err; 434 } 435 } 436 437 drm_buddy_free_list(&mm, &holes); 438 439 /* Nothing larger than blocks of chunk_size now available */ 440 for (order = 1; order <= max_order; order++) { 441 size = min_page_size = get_size(order, PAGE_SIZE); 442 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 443 if (!err) { 444 pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", 445 order); 446 block = list_first_entry_or_null(&tmp, 447 struct drm_buddy_block, 448 link); 449 if (!block) { 450 pr_err("alloc_blocks has no blocks\n"); 451 err = -EINVAL; 452 goto err; 453 } 454 455 list_move_tail(&block->link, &blocks); 456 err = -EINVAL; 457 goto err; 458 } 459 } 460 461 if (err) 462 err = 0; 463 464err: 465 list_splice_tail(&holes, &blocks); 466 drm_buddy_free_list(&mm, &blocks); 467 drm_buddy_fini(&mm); 468 return err; 469} 470 471static int igt_buddy_alloc_smoke(void *arg) 472{ 473 u64 mm_size, min_page_size, chunk_size, start = 0; 474 unsigned long flags = 0; 475 struct drm_buddy mm; 476 int *order; 477 int err, i; 478 479 DRM_RND_STATE(prng, random_seed); 480 IGT_TIMEOUT(end_time); 481 482 igt_mm_config(&mm_size, &chunk_size); 483 484 err = drm_buddy_init(&mm, mm_size, chunk_size); 485 if (err) { 486 pr_err("buddy_init failed(%d)\n", err); 487 return err; 488 } 489 490 order = drm_random_order(mm.max_order + 1, &prng); 491 if (!order) 492 goto out_fini; 493 494 for (i = 0; i <= mm.max_order; ++i) { 495 struct drm_buddy_block *block; 496 int max_order = order[i]; 497 bool timeout = false; 498 LIST_HEAD(blocks); 499 u64 total, size; 500 LIST_HEAD(tmp); 501 int order; 502 503 err = igt_check_mm(&mm); 504 if (err) { 505 pr_err("pre-mm check failed, abort\n"); 506 break; 507 } 508 509 order = max_order; 510 total = 0; 511 512 do { 513retry: 514 size = min_page_size = get_size(order, chunk_size); 515 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, 516 min_page_size, &tmp, flags); 517 if (err) { 518 if (err == -ENOMEM) { 519 pr_info("buddy_alloc hit -ENOMEM with order=%d\n", 520 order); 521 } else { 522 if (order--) { 523 err = 0; 524 goto retry; 525 } 526 527 pr_err("buddy_alloc with order=%d failed(%d)\n", 528 order, err); 529 } 530 531 break; 532 } 533 534 block = list_first_entry_or_null(&tmp, 535 struct drm_buddy_block, 536 link); 537 if (!block) { 538 pr_err("alloc_blocks has no blocks\n"); 539 err = -EINVAL; 540 break; 541 } 542 543 list_move_tail(&block->link, &blocks); 544 545 if (drm_buddy_block_order(block) != order) { 546 pr_err("buddy_alloc order mismatch\n"); 547 err = -EINVAL; 548 break; 549 } 550 551 total += drm_buddy_block_size(&mm, block); 552 553 if (__igt_timeout(end_time, NULL)) { 554 timeout = true; 555 break; 556 } 557 } while (total < mm.size); 558 559 if (!err) 560 err = igt_check_blocks(&mm, &blocks, total, false); 561 562 drm_buddy_free_list(&mm, &blocks); 563 564 if (!err) { 565 err = igt_check_mm(&mm); 566 if (err) 567 pr_err("post-mm check failed\n"); 568 } 569 570 if (err || timeout) 571 break; 572 573 cond_resched(); 574 } 575 576 if (err == -ENOMEM) 577 err = 0; 578 579 kfree(order); 580out_fini: 581 drm_buddy_fini(&mm); 582 583 return err; 584} 585 586static int igt_buddy_alloc_pessimistic(void *arg) 587{ 588 u64 mm_size, size, min_page_size, start = 0; 589 struct drm_buddy_block *block, *bn; 590 const unsigned int max_order = 16; 591 unsigned long flags = 0; 592 struct drm_buddy mm; 593 unsigned int order; 594 LIST_HEAD(blocks); 595 LIST_HEAD(tmp); 596 int err; 597 598 /* 599 * Create a pot-sized mm, then allocate one of each possible 600 * order within. This should leave the mm with exactly one 601 * page left. 602 */ 603 604 mm_size = PAGE_SIZE << max_order; 605 err = drm_buddy_init(&mm, mm_size, PAGE_SIZE); 606 if (err) { 607 pr_err("buddy_init failed(%d)\n", err); 608 return err; 609 } 610 BUG_ON(mm.max_order != max_order); 611 612 for (order = 0; order < max_order; order++) { 613 size = min_page_size = get_size(order, PAGE_SIZE); 614 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 615 if (err) { 616 pr_info("buddy_alloc hit -ENOMEM with order=%d\n", 617 order); 618 goto err; 619 } 620 621 block = list_first_entry_or_null(&tmp, 622 struct drm_buddy_block, 623 link); 624 if (!block) { 625 pr_err("alloc_blocks has no blocks\n"); 626 err = -EINVAL; 627 goto err; 628 } 629 630 list_move_tail(&block->link, &blocks); 631 } 632 633 /* And now the last remaining block available */ 634 size = min_page_size = get_size(0, PAGE_SIZE); 635 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 636 if (err) { 637 pr_info("buddy_alloc hit -ENOMEM on final alloc\n"); 638 goto err; 639 } 640 641 block = list_first_entry_or_null(&tmp, 642 struct drm_buddy_block, 643 link); 644 if (!block) { 645 pr_err("alloc_blocks has no blocks\n"); 646 err = -EINVAL; 647 goto err; 648 } 649 650 list_move_tail(&block->link, &blocks); 651 652 /* Should be completely full! */ 653 for (order = max_order; order--; ) { 654 size = min_page_size = get_size(order, PAGE_SIZE); 655 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 656 if (!err) { 657 pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", 658 order); 659 block = list_first_entry_or_null(&tmp, 660 struct drm_buddy_block, 661 link); 662 if (!block) { 663 pr_err("alloc_blocks has no blocks\n"); 664 err = -EINVAL; 665 goto err; 666 } 667 668 list_move_tail(&block->link, &blocks); 669 err = -EINVAL; 670 goto err; 671 } 672 } 673 674 block = list_last_entry(&blocks, typeof(*block), link); 675 list_del(&block->link); 676 drm_buddy_free_block(&mm, block); 677 678 /* As we free in increasing size, we make available larger blocks */ 679 order = 1; 680 list_for_each_entry_safe(block, bn, &blocks, link) { 681 list_del(&block->link); 682 drm_buddy_free_block(&mm, block); 683 684 size = min_page_size = get_size(order, PAGE_SIZE); 685 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 686 if (err) { 687 pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", 688 order); 689 goto err; 690 } 691 692 block = list_first_entry_or_null(&tmp, 693 struct drm_buddy_block, 694 link); 695 if (!block) { 696 pr_err("alloc_blocks has no blocks\n"); 697 err = -EINVAL; 698 goto err; 699 } 700 701 list_del(&block->link); 702 drm_buddy_free_block(&mm, block); 703 order++; 704 } 705 706 /* To confirm, now the whole mm should be available */ 707 size = min_page_size = get_size(max_order, PAGE_SIZE); 708 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 709 if (err) { 710 pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", 711 max_order); 712 goto err; 713 } 714 715 block = list_first_entry_or_null(&tmp, 716 struct drm_buddy_block, 717 link); 718 if (!block) { 719 pr_err("alloc_blocks has no blocks\n"); 720 err = -EINVAL; 721 goto err; 722 } 723 724 list_del(&block->link); 725 drm_buddy_free_block(&mm, block); 726 727err: 728 drm_buddy_free_list(&mm, &blocks); 729 drm_buddy_fini(&mm); 730 return err; 731} 732 733static int igt_buddy_alloc_optimistic(void *arg) 734{ 735 u64 mm_size, size, min_page_size, start = 0; 736 struct drm_buddy_block *block; 737 unsigned long flags = 0; 738 const int max_order = 16; 739 struct drm_buddy mm; 740 LIST_HEAD(blocks); 741 LIST_HEAD(tmp); 742 int order, err; 743 744 /* 745 * Create a mm with one block of each order available, and 746 * try to allocate them all. 747 */ 748 749 mm_size = PAGE_SIZE * ((1 << (max_order + 1)) - 1); 750 err = drm_buddy_init(&mm, 751 mm_size, 752 PAGE_SIZE); 753 if (err) { 754 pr_err("buddy_init failed(%d)\n", err); 755 return err; 756 } 757 758 BUG_ON(mm.max_order != max_order); 759 760 for (order = 0; order <= max_order; order++) { 761 size = min_page_size = get_size(order, PAGE_SIZE); 762 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 763 if (err) { 764 pr_info("buddy_alloc hit -ENOMEM with order=%d\n", 765 order); 766 goto err; 767 } 768 769 block = list_first_entry_or_null(&tmp, 770 struct drm_buddy_block, 771 link); 772 if (!block) { 773 pr_err("alloc_blocks has no blocks\n"); 774 err = -EINVAL; 775 goto err; 776 } 777 778 list_move_tail(&block->link, &blocks); 779 } 780 781 /* Should be completely full! */ 782 size = min_page_size = get_size(0, PAGE_SIZE); 783 err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); 784 if (!err) { 785 pr_info("buddy_alloc unexpectedly succeeded, it should be full!"); 786 block = list_first_entry_or_null(&tmp, 787 struct drm_buddy_block, 788 link); 789 if (!block) { 790 pr_err("alloc_blocks has no blocks\n"); 791 err = -EINVAL; 792 goto err; 793 } 794 795 list_move_tail(&block->link, &blocks); 796 err = -EINVAL; 797 goto err; 798 } else { 799 err = 0; 800 } 801 802err: 803 drm_buddy_free_list(&mm, &blocks); 804 drm_buddy_fini(&mm); 805 return err; 806} 807 808static int igt_buddy_alloc_range(void *arg) 809{ 810 unsigned long flags = DRM_BUDDY_RANGE_ALLOCATION; 811 u64 offset, size, rem, chunk_size, end; 812 unsigned long page_num; 813 struct drm_buddy mm; 814 LIST_HEAD(blocks); 815 int err; 816 817 igt_mm_config(&size, &chunk_size); 818 819 err = drm_buddy_init(&mm, size, chunk_size); 820 if (err) { 821 pr_err("buddy_init failed(%d)\n", err); 822 return err; 823 } 824 825 err = igt_check_mm(&mm); 826 if (err) { 827 pr_err("pre-mm check failed, abort, abort, abort!\n"); 828 goto err_fini; 829 } 830 831 rem = mm.size; 832 offset = 0; 833 834 for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { 835 struct drm_buddy_block *block; 836 LIST_HEAD(tmp); 837 838 size = min(page_num * mm.chunk_size, rem); 839 end = offset + size; 840 841 err = drm_buddy_alloc_blocks(&mm, offset, end, size, mm.chunk_size, &tmp, flags); 842 if (err) { 843 if (err == -ENOMEM) { 844 pr_info("alloc_range hit -ENOMEM with size=%llx\n", 845 size); 846 } else { 847 pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n", 848 offset, size, err); 849 } 850 851 break; 852 } 853 854 block = list_first_entry_or_null(&tmp, 855 struct drm_buddy_block, 856 link); 857 if (!block) { 858 pr_err("alloc_range has no blocks\n"); 859 err = -EINVAL; 860 break; 861 } 862 863 if (drm_buddy_block_offset(block) != offset) { 864 pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n", 865 drm_buddy_block_offset(block), offset); 866 err = -EINVAL; 867 } 868 869 if (!err) 870 err = igt_check_blocks(&mm, &tmp, size, true); 871 872 list_splice_tail(&tmp, &blocks); 873 874 if (err) 875 break; 876 877 offset += size; 878 879 rem -= size; 880 if (!rem) 881 break; 882 883 cond_resched(); 884 } 885 886 if (err == -ENOMEM) 887 err = 0; 888 889 drm_buddy_free_list(&mm, &blocks); 890 891 if (!err) { 892 err = igt_check_mm(&mm); 893 if (err) 894 pr_err("post-mm check failed\n"); 895 } 896 897err_fini: 898 drm_buddy_fini(&mm); 899 900 return err; 901} 902 903static int igt_buddy_alloc_limit(void *arg) 904{ 905 u64 end, size = U64_MAX, start = 0; 906 struct drm_buddy_block *block; 907 unsigned long flags = 0; 908 LIST_HEAD(allocated); 909 struct drm_buddy mm; 910 int err; 911 912 size = end = round_down(size, 4096); 913 err = drm_buddy_init(&mm, size, PAGE_SIZE); 914 if (err) 915 return err; 916 917 if (mm.max_order != DRM_BUDDY_MAX_ORDER) { 918 pr_err("mm.max_order(%d) != %d\n", 919 mm.max_order, DRM_BUDDY_MAX_ORDER); 920 err = -EINVAL; 921 goto out_fini; 922 } 923 924 err = drm_buddy_alloc_blocks(&mm, start, end, size, 925 PAGE_SIZE, &allocated, flags); 926 927 if (unlikely(err)) 928 goto out_free; 929 930 block = list_first_entry_or_null(&allocated, 931 struct drm_buddy_block, 932 link); 933 934 if (!block) { 935 err = -EINVAL; 936 goto out_fini; 937 } 938 939 if (drm_buddy_block_order(block) != mm.max_order) { 940 pr_err("block order(%d) != %d\n", 941 drm_buddy_block_order(block), mm.max_order); 942 err = -EINVAL; 943 goto out_free; 944 } 945 946 if (drm_buddy_block_size(&mm, block) != 947 BIT_ULL(mm.max_order) * PAGE_SIZE) { 948 pr_err("block size(%llu) != %llu\n", 949 drm_buddy_block_size(&mm, block), 950 BIT_ULL(mm.max_order) * PAGE_SIZE); 951 err = -EINVAL; 952 goto out_free; 953 } 954 955out_free: 956 drm_buddy_free_list(&mm, &allocated); 957out_fini: 958 drm_buddy_fini(&mm); 959 return err; 960} 961 962static int igt_sanitycheck(void *ignored) 963{ 964 pr_info("%s - ok!\n", __func__); 965 return 0; 966} 967 968#include "drm_selftest.c" 969 970static int __init test_drm_buddy_init(void) 971{ 972 int err; 973 974 while (!random_seed) 975 random_seed = get_random_int(); 976 977 pr_info("Testing DRM buddy manager (struct drm_buddy), with random_seed=0x%x\n", 978 random_seed); 979 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); 980 981 return err > 0 ? 0 : err; 982} 983 984static void __exit test_drm_buddy_exit(void) 985{ 986} 987 988module_init(test_drm_buddy_init); 989module_exit(test_drm_buddy_exit); 990 991MODULE_AUTHOR("Intel Corporation"); 992MODULE_LICENSE("GPL");