test-drm_mm.c (57078B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Test cases for the drm_mm range manager 4 */ 5 6#define pr_fmt(fmt) "drm_mm: " fmt 7 8#include <linux/module.h> 9#include <linux/prime_numbers.h> 10#include <linux/slab.h> 11#include <linux/random.h> 12#include <linux/vmalloc.h> 13#include <linux/ktime.h> 14 15#include <drm/drm_mm.h> 16 17#include "../lib/drm_random.h" 18 19#define TESTS "drm_mm_selftests.h" 20#include "drm_selftest.h" 21 22static unsigned int random_seed; 23static unsigned int max_iterations = 8192; 24static unsigned int max_prime = 128; 25 26enum { 27 BEST, 28 BOTTOMUP, 29 TOPDOWN, 30 EVICT, 31}; 32 33static const struct insert_mode { 34 const char *name; 35 enum drm_mm_insert_mode mode; 36} insert_modes[] = { 37 [BEST] = { "best", DRM_MM_INSERT_BEST }, 38 [BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW }, 39 [TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH }, 40 [EVICT] = { "evict", DRM_MM_INSERT_EVICT }, 41 {} 42}, evict_modes[] = { 43 { "bottom-up", DRM_MM_INSERT_LOW }, 44 { "top-down", DRM_MM_INSERT_HIGH }, 45 {} 46}; 47 48static int igt_sanitycheck(void *ignored) 49{ 50 pr_info("%s - ok!\n", __func__); 51 return 0; 52} 53 54static bool assert_no_holes(const struct drm_mm *mm) 55{ 56 struct drm_mm_node *hole; 57 u64 hole_start, __always_unused hole_end; 58 unsigned long count; 59 60 count = 0; 61 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) 62 count++; 63 if (count) { 64 pr_err("Expected to find no holes (after reserve), found %lu instead\n", count); 65 return false; 66 } 67 68 drm_mm_for_each_node(hole, mm) { 69 if (drm_mm_hole_follows(hole)) { 70 pr_err("Hole follows node, expected none!\n"); 71 return false; 72 } 73 } 74 75 return true; 76} 77 78static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end) 79{ 80 struct drm_mm_node *hole; 81 u64 hole_start, hole_end; 82 unsigned long count; 83 bool ok = true; 84 85 if (end <= start) 86 return true; 87 88 count = 0; 89 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 90 if (start != hole_start || end != hole_end) { 91 if (ok) 92 pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", 93 hole_start, hole_end, 94 start, end); 95 ok = false; 96 } 97 count++; 98 } 99 if (count != 1) { 100 pr_err("Expected to find one hole, found %lu instead\n", count); 101 ok = false; 102 } 103 104 return ok; 105} 106 107static bool assert_continuous(const struct drm_mm *mm, u64 size) 108{ 109 struct drm_mm_node *node, *check, *found; 110 unsigned long n; 111 u64 addr; 112 113 if (!assert_no_holes(mm)) 114 return false; 115 116 n = 0; 117 addr = 0; 118 drm_mm_for_each_node(node, mm) { 119 if (node->start != addr) { 120 pr_err("node[%ld] list out of order, expected %llx found %llx\n", 121 n, addr, node->start); 122 return false; 123 } 124 125 if (node->size != size) { 126 pr_err("node[%ld].size incorrect, expected %llx, found %llx\n", 127 n, size, node->size); 128 return false; 129 } 130 131 if (drm_mm_hole_follows(node)) { 132 pr_err("node[%ld] is followed by a hole!\n", n); 133 return false; 134 } 135 136 found = NULL; 137 drm_mm_for_each_node_in_range(check, mm, addr, addr + size) { 138 if (node != check) { 139 pr_err("lookup return wrong node, expected start %llx, found %llx\n", 140 node->start, check->start); 141 return false; 142 } 143 found = check; 144 } 145 if (!found) { 146 pr_err("lookup failed for node %llx + %llx\n", 147 addr, size); 148 return false; 149 } 150 151 addr += size; 152 n++; 153 } 154 155 return true; 156} 157 158static u64 misalignment(struct drm_mm_node *node, u64 alignment) 159{ 160 u64 rem; 161 162 if (!alignment) 163 return 0; 164 165 div64_u64_rem(node->start, alignment, &rem); 166 return rem; 167} 168 169static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm, 170 u64 size, u64 alignment, unsigned long color) 171{ 172 bool ok = true; 173 174 if (!drm_mm_node_allocated(node) || node->mm != mm) { 175 pr_err("node not allocated\n"); 176 ok = false; 177 } 178 179 if (node->size != size) { 180 pr_err("node has wrong size, found %llu, expected %llu\n", 181 node->size, size); 182 ok = false; 183 } 184 185 if (misalignment(node, alignment)) { 186 pr_err("node is misaligned, start %llx rem %llu, expected alignment %llu\n", 187 node->start, misalignment(node, alignment), alignment); 188 ok = false; 189 } 190 191 if (node->color != color) { 192 pr_err("node has wrong color, found %lu, expected %lu\n", 193 node->color, color); 194 ok = false; 195 } 196 197 return ok; 198} 199 200#define show_mm(mm) do { \ 201 struct drm_printer __p = drm_debug_printer(__func__); \ 202 drm_mm_print((mm), &__p); } while (0) 203 204static int igt_init(void *ignored) 205{ 206 const unsigned int size = 4096; 207 struct drm_mm mm; 208 struct drm_mm_node tmp; 209 int ret = -EINVAL; 210 211 /* Start with some simple checks on initialising the struct drm_mm */ 212 memset(&mm, 0, sizeof(mm)); 213 if (drm_mm_initialized(&mm)) { 214 pr_err("zeroed mm claims to be initialized\n"); 215 return ret; 216 } 217 218 memset(&mm, 0xff, sizeof(mm)); 219 drm_mm_init(&mm, 0, size); 220 if (!drm_mm_initialized(&mm)) { 221 pr_err("mm claims not to be initialized\n"); 222 goto out; 223 } 224 225 if (!drm_mm_clean(&mm)) { 226 pr_err("mm not empty on creation\n"); 227 goto out; 228 } 229 230 /* After creation, it should all be one massive hole */ 231 if (!assert_one_hole(&mm, 0, size)) { 232 ret = -EINVAL; 233 goto out; 234 } 235 236 memset(&tmp, 0, sizeof(tmp)); 237 tmp.start = 0; 238 tmp.size = size; 239 ret = drm_mm_reserve_node(&mm, &tmp); 240 if (ret) { 241 pr_err("failed to reserve whole drm_mm\n"); 242 goto out; 243 } 244 245 /* After filling the range entirely, there should be no holes */ 246 if (!assert_no_holes(&mm)) { 247 ret = -EINVAL; 248 goto out; 249 } 250 251 /* And then after emptying it again, the massive hole should be back */ 252 drm_mm_remove_node(&tmp); 253 if (!assert_one_hole(&mm, 0, size)) { 254 ret = -EINVAL; 255 goto out; 256 } 257 258out: 259 if (ret) 260 show_mm(&mm); 261 drm_mm_takedown(&mm); 262 return ret; 263} 264 265static int igt_debug(void *ignored) 266{ 267 struct drm_mm mm; 268 struct drm_mm_node nodes[2]; 269 int ret; 270 271 /* Create a small drm_mm with a couple of nodes and a few holes, and 272 * check that the debug iterator doesn't explode over a trivial drm_mm. 273 */ 274 275 drm_mm_init(&mm, 0, 4096); 276 277 memset(nodes, 0, sizeof(nodes)); 278 nodes[0].start = 512; 279 nodes[0].size = 1024; 280 ret = drm_mm_reserve_node(&mm, &nodes[0]); 281 if (ret) { 282 pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n", 283 nodes[0].start, nodes[0].size); 284 return ret; 285 } 286 287 nodes[1].size = 1024; 288 nodes[1].start = 4096 - 512 - nodes[1].size; 289 ret = drm_mm_reserve_node(&mm, &nodes[1]); 290 if (ret) { 291 pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n", 292 nodes[1].start, nodes[1].size); 293 return ret; 294 } 295 296 show_mm(&mm); 297 return 0; 298} 299 300static struct drm_mm_node *set_node(struct drm_mm_node *node, 301 u64 start, u64 size) 302{ 303 node->start = start; 304 node->size = size; 305 return node; 306} 307 308static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node) 309{ 310 int err; 311 312 err = drm_mm_reserve_node(mm, node); 313 if (likely(err == -ENOSPC)) 314 return true; 315 316 if (!err) { 317 pr_err("impossible reserve succeeded, node %llu + %llu\n", 318 node->start, node->size); 319 drm_mm_remove_node(node); 320 } else { 321 pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", 322 err, -ENOSPC, node->start, node->size); 323 } 324 return false; 325} 326 327static bool check_reserve_boundaries(struct drm_mm *mm, 328 unsigned int count, 329 u64 size) 330{ 331 const struct boundary { 332 u64 start, size; 333 const char *name; 334 } boundaries[] = { 335#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" } 336 B(0, 0), 337 B(-size, 0), 338 B(size, 0), 339 B(size * count, 0), 340 B(-size, size), 341 B(-size, -size), 342 B(-size, 2*size), 343 B(0, -size), 344 B(size, -size), 345 B(count*size, size), 346 B(count*size, -size), 347 B(count*size, count*size), 348 B(count*size, -count*size), 349 B(count*size, -(count+1)*size), 350 B((count+1)*size, size), 351 B((count+1)*size, -size), 352 B((count+1)*size, -2*size), 353#undef B 354 }; 355 struct drm_mm_node tmp = {}; 356 int n; 357 358 for (n = 0; n < ARRAY_SIZE(boundaries); n++) { 359 if (!expect_reserve_fail(mm, 360 set_node(&tmp, 361 boundaries[n].start, 362 boundaries[n].size))) { 363 pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n", 364 n, boundaries[n].name, count, size); 365 return false; 366 } 367 } 368 369 return true; 370} 371 372static int __igt_reserve(unsigned int count, u64 size) 373{ 374 DRM_RND_STATE(prng, random_seed); 375 struct drm_mm mm; 376 struct drm_mm_node tmp, *nodes, *node, *next; 377 unsigned int *order, n, m, o = 0; 378 int ret, err; 379 380 /* For exercising drm_mm_reserve_node(), we want to check that 381 * reservations outside of the drm_mm range are rejected, and to 382 * overlapping and otherwise already occupied ranges. Afterwards, 383 * the tree and nodes should be intact. 384 */ 385 386 DRM_MM_BUG_ON(!count); 387 DRM_MM_BUG_ON(!size); 388 389 ret = -ENOMEM; 390 order = drm_random_order(count, &prng); 391 if (!order) 392 goto err; 393 394 nodes = vzalloc(array_size(count, sizeof(*nodes))); 395 if (!nodes) 396 goto err_order; 397 398 ret = -EINVAL; 399 drm_mm_init(&mm, 0, count * size); 400 401 if (!check_reserve_boundaries(&mm, count, size)) 402 goto out; 403 404 for (n = 0; n < count; n++) { 405 nodes[n].start = order[n] * size; 406 nodes[n].size = size; 407 408 err = drm_mm_reserve_node(&mm, &nodes[n]); 409 if (err) { 410 pr_err("reserve failed, step %d, start %llu\n", 411 n, nodes[n].start); 412 ret = err; 413 goto out; 414 } 415 416 if (!drm_mm_node_allocated(&nodes[n])) { 417 pr_err("reserved node not allocated! step %d, start %llu\n", 418 n, nodes[n].start); 419 goto out; 420 } 421 422 if (!expect_reserve_fail(&mm, &nodes[n])) 423 goto out; 424 } 425 426 /* After random insertion the nodes should be in order */ 427 if (!assert_continuous(&mm, size)) 428 goto out; 429 430 /* Repeated use should then fail */ 431 drm_random_reorder(order, count, &prng); 432 for (n = 0; n < count; n++) { 433 if (!expect_reserve_fail(&mm, 434 set_node(&tmp, order[n] * size, 1))) 435 goto out; 436 437 /* Remove and reinsert should work */ 438 drm_mm_remove_node(&nodes[order[n]]); 439 err = drm_mm_reserve_node(&mm, &nodes[order[n]]); 440 if (err) { 441 pr_err("reserve failed, step %d, start %llu\n", 442 n, nodes[n].start); 443 ret = err; 444 goto out; 445 } 446 } 447 448 if (!assert_continuous(&mm, size)) 449 goto out; 450 451 /* Overlapping use should then fail */ 452 for (n = 0; n < count; n++) { 453 if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count))) 454 goto out; 455 } 456 for (n = 0; n < count; n++) { 457 if (!expect_reserve_fail(&mm, 458 set_node(&tmp, 459 size * n, 460 size * (count - n)))) 461 goto out; 462 } 463 464 /* Remove several, reinsert, check full */ 465 for_each_prime_number(n, min(max_prime, count)) { 466 for (m = 0; m < n; m++) { 467 node = &nodes[order[(o + m) % count]]; 468 drm_mm_remove_node(node); 469 } 470 471 for (m = 0; m < n; m++) { 472 node = &nodes[order[(o + m) % count]]; 473 err = drm_mm_reserve_node(&mm, node); 474 if (err) { 475 pr_err("reserve failed, step %d/%d, start %llu\n", 476 m, n, node->start); 477 ret = err; 478 goto out; 479 } 480 } 481 482 o += n; 483 484 if (!assert_continuous(&mm, size)) 485 goto out; 486 } 487 488 ret = 0; 489out: 490 drm_mm_for_each_node_safe(node, next, &mm) 491 drm_mm_remove_node(node); 492 drm_mm_takedown(&mm); 493 vfree(nodes); 494err_order: 495 kfree(order); 496err: 497 return ret; 498} 499 500static int igt_reserve(void *ignored) 501{ 502 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 503 int n, ret; 504 505 for_each_prime_number_from(n, 1, 54) { 506 u64 size = BIT_ULL(n); 507 508 ret = __igt_reserve(count, size - 1); 509 if (ret) 510 return ret; 511 512 ret = __igt_reserve(count, size); 513 if (ret) 514 return ret; 515 516 ret = __igt_reserve(count, size + 1); 517 if (ret) 518 return ret; 519 520 cond_resched(); 521 } 522 523 return 0; 524} 525 526static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node, 527 u64 size, u64 alignment, unsigned long color, 528 const struct insert_mode *mode) 529{ 530 int err; 531 532 err = drm_mm_insert_node_generic(mm, node, 533 size, alignment, color, 534 mode->mode); 535 if (err) { 536 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", 537 size, alignment, color, mode->name, err); 538 return false; 539 } 540 541 if (!assert_node(node, mm, size, alignment, color)) { 542 drm_mm_remove_node(node); 543 return false; 544 } 545 546 return true; 547} 548 549static bool expect_insert_fail(struct drm_mm *mm, u64 size) 550{ 551 struct drm_mm_node tmp = {}; 552 int err; 553 554 err = drm_mm_insert_node(mm, &tmp, size); 555 if (likely(err == -ENOSPC)) 556 return true; 557 558 if (!err) { 559 pr_err("impossible insert succeeded, node %llu + %llu\n", 560 tmp.start, tmp.size); 561 drm_mm_remove_node(&tmp); 562 } else { 563 pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n", 564 err, -ENOSPC, size); 565 } 566 return false; 567} 568 569static int __igt_insert(unsigned int count, u64 size, bool replace) 570{ 571 DRM_RND_STATE(prng, random_seed); 572 const struct insert_mode *mode; 573 struct drm_mm mm; 574 struct drm_mm_node *nodes, *node, *next; 575 unsigned int *order, n, m, o = 0; 576 int ret; 577 578 /* Fill a range with lots of nodes, check it doesn't fail too early */ 579 580 DRM_MM_BUG_ON(!count); 581 DRM_MM_BUG_ON(!size); 582 583 ret = -ENOMEM; 584 nodes = vmalloc(array_size(count, sizeof(*nodes))); 585 if (!nodes) 586 goto err; 587 588 order = drm_random_order(count, &prng); 589 if (!order) 590 goto err_nodes; 591 592 ret = -EINVAL; 593 drm_mm_init(&mm, 0, count * size); 594 595 for (mode = insert_modes; mode->name; mode++) { 596 for (n = 0; n < count; n++) { 597 struct drm_mm_node tmp; 598 599 node = replace ? &tmp : &nodes[n]; 600 memset(node, 0, sizeof(*node)); 601 if (!expect_insert(&mm, node, size, 0, n, mode)) { 602 pr_err("%s insert failed, size %llu step %d\n", 603 mode->name, size, n); 604 goto out; 605 } 606 607 if (replace) { 608 drm_mm_replace_node(&tmp, &nodes[n]); 609 if (drm_mm_node_allocated(&tmp)) { 610 pr_err("replaced old-node still allocated! step %d\n", 611 n); 612 goto out; 613 } 614 615 if (!assert_node(&nodes[n], &mm, size, 0, n)) { 616 pr_err("replaced node did not inherit parameters, size %llu step %d\n", 617 size, n); 618 goto out; 619 } 620 621 if (tmp.start != nodes[n].start) { 622 pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", 623 tmp.start, size, 624 nodes[n].start, nodes[n].size); 625 goto out; 626 } 627 } 628 } 629 630 /* After random insertion the nodes should be in order */ 631 if (!assert_continuous(&mm, size)) 632 goto out; 633 634 /* Repeated use should then fail */ 635 if (!expect_insert_fail(&mm, size)) 636 goto out; 637 638 /* Remove one and reinsert, as the only hole it should refill itself */ 639 for (n = 0; n < count; n++) { 640 u64 addr = nodes[n].start; 641 642 drm_mm_remove_node(&nodes[n]); 643 if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) { 644 pr_err("%s reinsert failed, size %llu step %d\n", 645 mode->name, size, n); 646 goto out; 647 } 648 649 if (nodes[n].start != addr) { 650 pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", 651 mode->name, n, addr, nodes[n].start); 652 goto out; 653 } 654 655 if (!assert_continuous(&mm, size)) 656 goto out; 657 } 658 659 /* Remove several, reinsert, check full */ 660 for_each_prime_number(n, min(max_prime, count)) { 661 for (m = 0; m < n; m++) { 662 node = &nodes[order[(o + m) % count]]; 663 drm_mm_remove_node(node); 664 } 665 666 for (m = 0; m < n; m++) { 667 node = &nodes[order[(o + m) % count]]; 668 if (!expect_insert(&mm, node, size, 0, n, mode)) { 669 pr_err("%s multiple reinsert failed, size %llu step %d\n", 670 mode->name, size, n); 671 goto out; 672 } 673 } 674 675 o += n; 676 677 if (!assert_continuous(&mm, size)) 678 goto out; 679 680 if (!expect_insert_fail(&mm, size)) 681 goto out; 682 } 683 684 drm_mm_for_each_node_safe(node, next, &mm) 685 drm_mm_remove_node(node); 686 DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 687 688 cond_resched(); 689 } 690 691 ret = 0; 692out: 693 drm_mm_for_each_node_safe(node, next, &mm) 694 drm_mm_remove_node(node); 695 drm_mm_takedown(&mm); 696 kfree(order); 697err_nodes: 698 vfree(nodes); 699err: 700 return ret; 701} 702 703static int igt_insert(void *ignored) 704{ 705 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 706 unsigned int n; 707 int ret; 708 709 for_each_prime_number_from(n, 1, 54) { 710 u64 size = BIT_ULL(n); 711 712 ret = __igt_insert(count, size - 1, false); 713 if (ret) 714 return ret; 715 716 ret = __igt_insert(count, size, false); 717 if (ret) 718 return ret; 719 720 ret = __igt_insert(count, size + 1, false); 721 if (ret) 722 return ret; 723 724 cond_resched(); 725 } 726 727 return 0; 728} 729 730static int igt_replace(void *ignored) 731{ 732 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 733 unsigned int n; 734 int ret; 735 736 /* Reuse igt_insert to exercise replacement by inserting a dummy node, 737 * then replacing it with the intended node. We want to check that 738 * the tree is intact and all the information we need is carried 739 * across to the target node. 740 */ 741 742 for_each_prime_number_from(n, 1, 54) { 743 u64 size = BIT_ULL(n); 744 745 ret = __igt_insert(count, size - 1, true); 746 if (ret) 747 return ret; 748 749 ret = __igt_insert(count, size, true); 750 if (ret) 751 return ret; 752 753 ret = __igt_insert(count, size + 1, true); 754 if (ret) 755 return ret; 756 757 cond_resched(); 758 } 759 760 return 0; 761} 762 763static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node, 764 u64 size, u64 alignment, unsigned long color, 765 u64 range_start, u64 range_end, 766 const struct insert_mode *mode) 767{ 768 int err; 769 770 err = drm_mm_insert_node_in_range(mm, node, 771 size, alignment, color, 772 range_start, range_end, 773 mode->mode); 774 if (err) { 775 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", 776 size, alignment, color, mode->name, 777 range_start, range_end, err); 778 return false; 779 } 780 781 if (!assert_node(node, mm, size, alignment, color)) { 782 drm_mm_remove_node(node); 783 return false; 784 } 785 786 return true; 787} 788 789static bool expect_insert_in_range_fail(struct drm_mm *mm, 790 u64 size, 791 u64 range_start, 792 u64 range_end) 793{ 794 struct drm_mm_node tmp = {}; 795 int err; 796 797 err = drm_mm_insert_node_in_range(mm, &tmp, 798 size, 0, 0, 799 range_start, range_end, 800 0); 801 if (likely(err == -ENOSPC)) 802 return true; 803 804 if (!err) { 805 pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", 806 tmp.start, tmp.size, range_start, range_end); 807 drm_mm_remove_node(&tmp); 808 } else { 809 pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", 810 err, -ENOSPC, size, range_start, range_end); 811 } 812 813 return false; 814} 815 816static bool assert_contiguous_in_range(struct drm_mm *mm, 817 u64 size, 818 u64 start, 819 u64 end) 820{ 821 struct drm_mm_node *node; 822 unsigned int n; 823 824 if (!expect_insert_in_range_fail(mm, size, start, end)) 825 return false; 826 827 n = div64_u64(start + size - 1, size); 828 drm_mm_for_each_node(node, mm) { 829 if (node->start < start || node->start + node->size > end) { 830 pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", 831 n, node->start, node->start + node->size, start, end); 832 return false; 833 } 834 835 if (node->start != n * size) { 836 pr_err("node %d out of order, expected start %llx, found %llx\n", 837 n, n * size, node->start); 838 return false; 839 } 840 841 if (node->size != size) { 842 pr_err("node %d has wrong size, expected size %llx, found %llx\n", 843 n, size, node->size); 844 return false; 845 } 846 847 if (drm_mm_hole_follows(node) && 848 drm_mm_hole_node_end(node) < end) { 849 pr_err("node %d is followed by a hole!\n", n); 850 return false; 851 } 852 853 n++; 854 } 855 856 if (start > 0) { 857 node = __drm_mm_interval_first(mm, 0, start - 1); 858 if (drm_mm_node_allocated(node)) { 859 pr_err("node before start: node=%llx+%llu, start=%llx\n", 860 node->start, node->size, start); 861 return false; 862 } 863 } 864 865 if (end < U64_MAX) { 866 node = __drm_mm_interval_first(mm, end, U64_MAX); 867 if (drm_mm_node_allocated(node)) { 868 pr_err("node after end: node=%llx+%llu, end=%llx\n", 869 node->start, node->size, end); 870 return false; 871 } 872 } 873 874 return true; 875} 876 877static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) 878{ 879 const struct insert_mode *mode; 880 struct drm_mm mm; 881 struct drm_mm_node *nodes, *node, *next; 882 unsigned int n, start_n, end_n; 883 int ret; 884 885 DRM_MM_BUG_ON(!count); 886 DRM_MM_BUG_ON(!size); 887 DRM_MM_BUG_ON(end <= start); 888 889 /* Very similar to __igt_insert(), but now instead of populating the 890 * full range of the drm_mm, we try to fill a small portion of it. 891 */ 892 893 ret = -ENOMEM; 894 nodes = vzalloc(array_size(count, sizeof(*nodes))); 895 if (!nodes) 896 goto err; 897 898 ret = -EINVAL; 899 drm_mm_init(&mm, 0, count * size); 900 901 start_n = div64_u64(start + size - 1, size); 902 end_n = div64_u64(end - size, size); 903 904 for (mode = insert_modes; mode->name; mode++) { 905 for (n = start_n; n <= end_n; n++) { 906 if (!expect_insert_in_range(&mm, &nodes[n], 907 size, size, n, 908 start, end, mode)) { 909 pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", 910 mode->name, size, n, 911 start_n, end_n, 912 start, end); 913 goto out; 914 } 915 } 916 917 if (!assert_contiguous_in_range(&mm, size, start, end)) { 918 pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n", 919 mode->name, start, end, size); 920 goto out; 921 } 922 923 /* Remove one and reinsert, it should refill itself */ 924 for (n = start_n; n <= end_n; n++) { 925 u64 addr = nodes[n].start; 926 927 drm_mm_remove_node(&nodes[n]); 928 if (!expect_insert_in_range(&mm, &nodes[n], 929 size, size, n, 930 start, end, mode)) { 931 pr_err("%s reinsert failed, step %d\n", mode->name, n); 932 goto out; 933 } 934 935 if (nodes[n].start != addr) { 936 pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", 937 mode->name, n, addr, nodes[n].start); 938 goto out; 939 } 940 } 941 942 if (!assert_contiguous_in_range(&mm, size, start, end)) { 943 pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", 944 mode->name, start, end, size); 945 goto out; 946 } 947 948 drm_mm_for_each_node_safe(node, next, &mm) 949 drm_mm_remove_node(node); 950 DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 951 952 cond_resched(); 953 } 954 955 ret = 0; 956out: 957 drm_mm_for_each_node_safe(node, next, &mm) 958 drm_mm_remove_node(node); 959 drm_mm_takedown(&mm); 960 vfree(nodes); 961err: 962 return ret; 963} 964 965static int insert_outside_range(void) 966{ 967 struct drm_mm mm; 968 const unsigned int start = 1024; 969 const unsigned int end = 2048; 970 const unsigned int size = end - start; 971 972 drm_mm_init(&mm, start, size); 973 974 if (!expect_insert_in_range_fail(&mm, 1, 0, start)) 975 return -EINVAL; 976 977 if (!expect_insert_in_range_fail(&mm, size, 978 start - size/2, start + (size+1)/2)) 979 return -EINVAL; 980 981 if (!expect_insert_in_range_fail(&mm, size, 982 end - (size+1)/2, end + size/2)) 983 return -EINVAL; 984 985 if (!expect_insert_in_range_fail(&mm, 1, end, end + size)) 986 return -EINVAL; 987 988 drm_mm_takedown(&mm); 989 return 0; 990} 991 992static int igt_insert_range(void *ignored) 993{ 994 const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); 995 unsigned int n; 996 int ret; 997 998 /* Check that requests outside the bounds of drm_mm are rejected. */ 999 ret = insert_outside_range(); 1000 if (ret) 1001 return ret; 1002 1003 for_each_prime_number_from(n, 1, 50) { 1004 const u64 size = BIT_ULL(n); 1005 const u64 max = count * size; 1006 1007 ret = __igt_insert_range(count, size, 0, max); 1008 if (ret) 1009 return ret; 1010 1011 ret = __igt_insert_range(count, size, 1, max); 1012 if (ret) 1013 return ret; 1014 1015 ret = __igt_insert_range(count, size, 0, max - 1); 1016 if (ret) 1017 return ret; 1018 1019 ret = __igt_insert_range(count, size, 0, max/2); 1020 if (ret) 1021 return ret; 1022 1023 ret = __igt_insert_range(count, size, max/2, max); 1024 if (ret) 1025 return ret; 1026 1027 ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); 1028 if (ret) 1029 return ret; 1030 1031 cond_resched(); 1032 } 1033 1034 return 0; 1035} 1036 1037static int prepare_igt_frag(struct drm_mm *mm, 1038 struct drm_mm_node *nodes, 1039 unsigned int num_insert, 1040 const struct insert_mode *mode) 1041{ 1042 unsigned int size = 4096; 1043 unsigned int i; 1044 1045 for (i = 0; i < num_insert; i++) { 1046 if (!expect_insert(mm, &nodes[i], size, 0, i, 1047 mode) != 0) { 1048 pr_err("%s insert failed\n", mode->name); 1049 return -EINVAL; 1050 } 1051 } 1052 1053 /* introduce fragmentation by freeing every other node */ 1054 for (i = 0; i < num_insert; i++) { 1055 if (i % 2 == 0) 1056 drm_mm_remove_node(&nodes[i]); 1057 } 1058 1059 return 0; 1060 1061} 1062 1063static u64 get_insert_time(struct drm_mm *mm, 1064 unsigned int num_insert, 1065 struct drm_mm_node *nodes, 1066 const struct insert_mode *mode) 1067{ 1068 unsigned int size = 8192; 1069 ktime_t start; 1070 unsigned int i; 1071 1072 start = ktime_get(); 1073 for (i = 0; i < num_insert; i++) { 1074 if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) { 1075 pr_err("%s insert failed\n", mode->name); 1076 return 0; 1077 } 1078 } 1079 1080 return ktime_to_ns(ktime_sub(ktime_get(), start)); 1081} 1082 1083static int igt_frag(void *ignored) 1084{ 1085 struct drm_mm mm; 1086 const struct insert_mode *mode; 1087 struct drm_mm_node *nodes, *node, *next; 1088 unsigned int insert_size = 10000; 1089 unsigned int scale_factor = 4; 1090 int ret = -EINVAL; 1091 1092 /* We need 4 * insert_size nodes to hold intermediate allocated 1093 * drm_mm nodes. 1094 * 1 times for prepare_igt_frag() 1095 * 1 times for get_insert_time() 1096 * 2 times for get_insert_time() 1097 */ 1098 nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); 1099 if (!nodes) 1100 return -ENOMEM; 1101 1102 /* For BOTTOMUP and TOPDOWN, we first fragment the 1103 * address space using prepare_igt_frag() and then try to verify 1104 * that that insertions scale quadratically from 10k to 20k insertions 1105 */ 1106 drm_mm_init(&mm, 1, U64_MAX - 2); 1107 for (mode = insert_modes; mode->name; mode++) { 1108 u64 insert_time1, insert_time2; 1109 1110 if (mode->mode != DRM_MM_INSERT_LOW && 1111 mode->mode != DRM_MM_INSERT_HIGH) 1112 continue; 1113 1114 ret = prepare_igt_frag(&mm, nodes, insert_size, mode); 1115 if (ret) 1116 goto err; 1117 1118 insert_time1 = get_insert_time(&mm, insert_size, 1119 nodes + insert_size, mode); 1120 if (insert_time1 == 0) 1121 goto err; 1122 1123 insert_time2 = get_insert_time(&mm, (insert_size * 2), 1124 nodes + insert_size * 2, mode); 1125 if (insert_time2 == 0) 1126 goto err; 1127 1128 pr_info("%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", 1129 mode->name, insert_size, insert_size * 2, 1130 insert_time1, insert_time2); 1131 1132 if (insert_time2 > (scale_factor * insert_time1)) { 1133 pr_err("%s fragmented insert took %llu nsecs more\n", 1134 mode->name, 1135 insert_time2 - (scale_factor * insert_time1)); 1136 goto err; 1137 } 1138 1139 drm_mm_for_each_node_safe(node, next, &mm) 1140 drm_mm_remove_node(node); 1141 } 1142 1143 ret = 0; 1144err: 1145 drm_mm_for_each_node_safe(node, next, &mm) 1146 drm_mm_remove_node(node); 1147 drm_mm_takedown(&mm); 1148 vfree(nodes); 1149 1150 return ret; 1151} 1152 1153static int igt_align(void *ignored) 1154{ 1155 const struct insert_mode *mode; 1156 const unsigned int max_count = min(8192u, max_prime); 1157 struct drm_mm mm; 1158 struct drm_mm_node *nodes, *node, *next; 1159 unsigned int prime; 1160 int ret = -EINVAL; 1161 1162 /* For each of the possible insertion modes, we pick a few 1163 * arbitrary alignments and check that the inserted node 1164 * meets our requirements. 1165 */ 1166 1167 nodes = vzalloc(array_size(max_count, sizeof(*nodes))); 1168 if (!nodes) 1169 goto err; 1170 1171 drm_mm_init(&mm, 1, U64_MAX - 2); 1172 1173 for (mode = insert_modes; mode->name; mode++) { 1174 unsigned int i = 0; 1175 1176 for_each_prime_number_from(prime, 1, max_count) { 1177 u64 size = next_prime_number(prime); 1178 1179 if (!expect_insert(&mm, &nodes[i], 1180 size, prime, i, 1181 mode)) { 1182 pr_err("%s insert failed with alignment=%d", 1183 mode->name, prime); 1184 goto out; 1185 } 1186 1187 i++; 1188 } 1189 1190 drm_mm_for_each_node_safe(node, next, &mm) 1191 drm_mm_remove_node(node); 1192 DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1193 1194 cond_resched(); 1195 } 1196 1197 ret = 0; 1198out: 1199 drm_mm_for_each_node_safe(node, next, &mm) 1200 drm_mm_remove_node(node); 1201 drm_mm_takedown(&mm); 1202 vfree(nodes); 1203err: 1204 return ret; 1205} 1206 1207static int igt_align_pot(int max) 1208{ 1209 struct drm_mm mm; 1210 struct drm_mm_node *node, *next; 1211 int bit; 1212 int ret = -EINVAL; 1213 1214 /* Check that we can align to the full u64 address space */ 1215 1216 drm_mm_init(&mm, 1, U64_MAX - 2); 1217 1218 for (bit = max - 1; bit; bit--) { 1219 u64 align, size; 1220 1221 node = kzalloc(sizeof(*node), GFP_KERNEL); 1222 if (!node) { 1223 ret = -ENOMEM; 1224 goto out; 1225 } 1226 1227 align = BIT_ULL(bit); 1228 size = BIT_ULL(bit-1) + 1; 1229 if (!expect_insert(&mm, node, 1230 size, align, bit, 1231 &insert_modes[0])) { 1232 pr_err("insert failed with alignment=%llx [%d]", 1233 align, bit); 1234 goto out; 1235 } 1236 1237 cond_resched(); 1238 } 1239 1240 ret = 0; 1241out: 1242 drm_mm_for_each_node_safe(node, next, &mm) { 1243 drm_mm_remove_node(node); 1244 kfree(node); 1245 } 1246 drm_mm_takedown(&mm); 1247 return ret; 1248} 1249 1250static int igt_align32(void *ignored) 1251{ 1252 return igt_align_pot(32); 1253} 1254 1255static int igt_align64(void *ignored) 1256{ 1257 return igt_align_pot(64); 1258} 1259 1260static void show_scan(const struct drm_mm_scan *scan) 1261{ 1262 pr_info("scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", 1263 scan->hit_start, scan->hit_end, 1264 scan->size, scan->alignment, scan->color); 1265} 1266 1267static void show_holes(const struct drm_mm *mm, int count) 1268{ 1269 u64 hole_start, hole_end; 1270 struct drm_mm_node *hole; 1271 1272 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 1273 struct drm_mm_node *next = list_next_entry(hole, node_list); 1274 const char *node1 = NULL, *node2 = NULL; 1275 1276 if (drm_mm_node_allocated(hole)) 1277 node1 = kasprintf(GFP_KERNEL, 1278 "[%llx + %lld, color=%ld], ", 1279 hole->start, hole->size, hole->color); 1280 1281 if (drm_mm_node_allocated(next)) 1282 node2 = kasprintf(GFP_KERNEL, 1283 ", [%llx + %lld, color=%ld]", 1284 next->start, next->size, next->color); 1285 1286 pr_info("%sHole [%llx - %llx, size %lld]%s\n", 1287 node1, 1288 hole_start, hole_end, hole_end - hole_start, 1289 node2); 1290 1291 kfree(node2); 1292 kfree(node1); 1293 1294 if (!--count) 1295 break; 1296 } 1297} 1298 1299struct evict_node { 1300 struct drm_mm_node node; 1301 struct list_head link; 1302}; 1303 1304static bool evict_nodes(struct drm_mm_scan *scan, 1305 struct evict_node *nodes, 1306 unsigned int *order, 1307 unsigned int count, 1308 bool use_color, 1309 struct list_head *evict_list) 1310{ 1311 struct evict_node *e, *en; 1312 unsigned int i; 1313 1314 for (i = 0; i < count; i++) { 1315 e = &nodes[order ? order[i] : i]; 1316 list_add(&e->link, evict_list); 1317 if (drm_mm_scan_add_block(scan, &e->node)) 1318 break; 1319 } 1320 list_for_each_entry_safe(e, en, evict_list, link) { 1321 if (!drm_mm_scan_remove_block(scan, &e->node)) 1322 list_del(&e->link); 1323 } 1324 if (list_empty(evict_list)) { 1325 pr_err("Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", 1326 scan->size, count, scan->alignment, scan->color); 1327 return false; 1328 } 1329 1330 list_for_each_entry(e, evict_list, link) 1331 drm_mm_remove_node(&e->node); 1332 1333 if (use_color) { 1334 struct drm_mm_node *node; 1335 1336 while ((node = drm_mm_scan_color_evict(scan))) { 1337 e = container_of(node, typeof(*e), node); 1338 drm_mm_remove_node(&e->node); 1339 list_add(&e->link, evict_list); 1340 } 1341 } else { 1342 if (drm_mm_scan_color_evict(scan)) { 1343 pr_err("drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); 1344 return false; 1345 } 1346 } 1347 1348 return true; 1349} 1350 1351static bool evict_nothing(struct drm_mm *mm, 1352 unsigned int total_size, 1353 struct evict_node *nodes) 1354{ 1355 struct drm_mm_scan scan; 1356 LIST_HEAD(evict_list); 1357 struct evict_node *e; 1358 struct drm_mm_node *node; 1359 unsigned int n; 1360 1361 drm_mm_scan_init(&scan, mm, 1, 0, 0, 0); 1362 for (n = 0; n < total_size; n++) { 1363 e = &nodes[n]; 1364 list_add(&e->link, &evict_list); 1365 drm_mm_scan_add_block(&scan, &e->node); 1366 } 1367 list_for_each_entry(e, &evict_list, link) 1368 drm_mm_scan_remove_block(&scan, &e->node); 1369 1370 for (n = 0; n < total_size; n++) { 1371 e = &nodes[n]; 1372 1373 if (!drm_mm_node_allocated(&e->node)) { 1374 pr_err("node[%d] no longer allocated!\n", n); 1375 return false; 1376 } 1377 1378 e->link.next = NULL; 1379 } 1380 1381 drm_mm_for_each_node(node, mm) { 1382 e = container_of(node, typeof(*e), node); 1383 e->link.next = &e->link; 1384 } 1385 1386 for (n = 0; n < total_size; n++) { 1387 e = &nodes[n]; 1388 1389 if (!e->link.next) { 1390 pr_err("node[%d] no longer connected!\n", n); 1391 return false; 1392 } 1393 } 1394 1395 return assert_continuous(mm, nodes[0].node.size); 1396} 1397 1398static bool evict_everything(struct drm_mm *mm, 1399 unsigned int total_size, 1400 struct evict_node *nodes) 1401{ 1402 struct drm_mm_scan scan; 1403 LIST_HEAD(evict_list); 1404 struct evict_node *e; 1405 unsigned int n; 1406 int err; 1407 1408 drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0); 1409 for (n = 0; n < total_size; n++) { 1410 e = &nodes[n]; 1411 list_add(&e->link, &evict_list); 1412 if (drm_mm_scan_add_block(&scan, &e->node)) 1413 break; 1414 } 1415 1416 err = 0; 1417 list_for_each_entry(e, &evict_list, link) { 1418 if (!drm_mm_scan_remove_block(&scan, &e->node)) { 1419 if (!err) { 1420 pr_err("Node %lld not marked for eviction!\n", 1421 e->node.start); 1422 err = -EINVAL; 1423 } 1424 } 1425 } 1426 if (err) 1427 return false; 1428 1429 list_for_each_entry(e, &evict_list, link) 1430 drm_mm_remove_node(&e->node); 1431 1432 if (!assert_one_hole(mm, 0, total_size)) 1433 return false; 1434 1435 list_for_each_entry(e, &evict_list, link) { 1436 err = drm_mm_reserve_node(mm, &e->node); 1437 if (err) { 1438 pr_err("Failed to reinsert node after eviction: start=%llx\n", 1439 e->node.start); 1440 return false; 1441 } 1442 } 1443 1444 return assert_continuous(mm, nodes[0].node.size); 1445} 1446 1447static int evict_something(struct drm_mm *mm, 1448 u64 range_start, u64 range_end, 1449 struct evict_node *nodes, 1450 unsigned int *order, 1451 unsigned int count, 1452 unsigned int size, 1453 unsigned int alignment, 1454 const struct insert_mode *mode) 1455{ 1456 struct drm_mm_scan scan; 1457 LIST_HEAD(evict_list); 1458 struct evict_node *e; 1459 struct drm_mm_node tmp; 1460 int err; 1461 1462 drm_mm_scan_init_with_range(&scan, mm, 1463 size, alignment, 0, 1464 range_start, range_end, 1465 mode->mode); 1466 if (!evict_nodes(&scan, 1467 nodes, order, count, false, 1468 &evict_list)) 1469 return -EINVAL; 1470 1471 memset(&tmp, 0, sizeof(tmp)); 1472 err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, 1473 DRM_MM_INSERT_EVICT); 1474 if (err) { 1475 pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", 1476 size, alignment); 1477 show_scan(&scan); 1478 show_holes(mm, 3); 1479 return err; 1480 } 1481 1482 if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 1483 pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 1484 tmp.start, tmp.size, range_start, range_end); 1485 err = -EINVAL; 1486 } 1487 1488 if (!assert_node(&tmp, mm, size, alignment, 0) || 1489 drm_mm_hole_follows(&tmp)) { 1490 pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", 1491 tmp.size, size, 1492 alignment, misalignment(&tmp, alignment), 1493 tmp.start, drm_mm_hole_follows(&tmp)); 1494 err = -EINVAL; 1495 } 1496 1497 drm_mm_remove_node(&tmp); 1498 if (err) 1499 return err; 1500 1501 list_for_each_entry(e, &evict_list, link) { 1502 err = drm_mm_reserve_node(mm, &e->node); 1503 if (err) { 1504 pr_err("Failed to reinsert node after eviction: start=%llx\n", 1505 e->node.start); 1506 return err; 1507 } 1508 } 1509 1510 if (!assert_continuous(mm, nodes[0].node.size)) { 1511 pr_err("range is no longer continuous\n"); 1512 return -EINVAL; 1513 } 1514 1515 return 0; 1516} 1517 1518static int igt_evict(void *ignored) 1519{ 1520 DRM_RND_STATE(prng, random_seed); 1521 const unsigned int size = 8192; 1522 const struct insert_mode *mode; 1523 struct drm_mm mm; 1524 struct evict_node *nodes; 1525 struct drm_mm_node *node, *next; 1526 unsigned int *order, n; 1527 int ret, err; 1528 1529 /* Here we populate a full drm_mm and then try and insert a new node 1530 * by evicting other nodes in a random order. The drm_mm_scan should 1531 * pick the first matching hole it finds from the random list. We 1532 * repeat that for different allocation strategies, alignments and 1533 * sizes to try and stress the hole finder. 1534 */ 1535 1536 ret = -ENOMEM; 1537 nodes = vzalloc(array_size(size, sizeof(*nodes))); 1538 if (!nodes) 1539 goto err; 1540 1541 order = drm_random_order(size, &prng); 1542 if (!order) 1543 goto err_nodes; 1544 1545 ret = -EINVAL; 1546 drm_mm_init(&mm, 0, size); 1547 for (n = 0; n < size; n++) { 1548 err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1549 if (err) { 1550 pr_err("insert failed, step %d\n", n); 1551 ret = err; 1552 goto out; 1553 } 1554 } 1555 1556 /* First check that using the scanner doesn't break the mm */ 1557 if (!evict_nothing(&mm, size, nodes)) { 1558 pr_err("evict_nothing() failed\n"); 1559 goto out; 1560 } 1561 if (!evict_everything(&mm, size, nodes)) { 1562 pr_err("evict_everything() failed\n"); 1563 goto out; 1564 } 1565 1566 for (mode = evict_modes; mode->name; mode++) { 1567 for (n = 1; n <= size; n <<= 1) { 1568 drm_random_reorder(order, size, &prng); 1569 err = evict_something(&mm, 0, U64_MAX, 1570 nodes, order, size, 1571 n, 1, 1572 mode); 1573 if (err) { 1574 pr_err("%s evict_something(size=%u) failed\n", 1575 mode->name, n); 1576 ret = err; 1577 goto out; 1578 } 1579 } 1580 1581 for (n = 1; n < size; n <<= 1) { 1582 drm_random_reorder(order, size, &prng); 1583 err = evict_something(&mm, 0, U64_MAX, 1584 nodes, order, size, 1585 size/2, n, 1586 mode); 1587 if (err) { 1588 pr_err("%s evict_something(size=%u, alignment=%u) failed\n", 1589 mode->name, size/2, n); 1590 ret = err; 1591 goto out; 1592 } 1593 } 1594 1595 for_each_prime_number_from(n, 1, min(size, max_prime)) { 1596 unsigned int nsize = (size - n + 1) / 2; 1597 1598 DRM_MM_BUG_ON(!nsize); 1599 1600 drm_random_reorder(order, size, &prng); 1601 err = evict_something(&mm, 0, U64_MAX, 1602 nodes, order, size, 1603 nsize, n, 1604 mode); 1605 if (err) { 1606 pr_err("%s evict_something(size=%u, alignment=%u) failed\n", 1607 mode->name, nsize, n); 1608 ret = err; 1609 goto out; 1610 } 1611 } 1612 1613 cond_resched(); 1614 } 1615 1616 ret = 0; 1617out: 1618 drm_mm_for_each_node_safe(node, next, &mm) 1619 drm_mm_remove_node(node); 1620 drm_mm_takedown(&mm); 1621 kfree(order); 1622err_nodes: 1623 vfree(nodes); 1624err: 1625 return ret; 1626} 1627 1628static int igt_evict_range(void *ignored) 1629{ 1630 DRM_RND_STATE(prng, random_seed); 1631 const unsigned int size = 8192; 1632 const unsigned int range_size = size / 2; 1633 const unsigned int range_start = size / 4; 1634 const unsigned int range_end = range_start + range_size; 1635 const struct insert_mode *mode; 1636 struct drm_mm mm; 1637 struct evict_node *nodes; 1638 struct drm_mm_node *node, *next; 1639 unsigned int *order, n; 1640 int ret, err; 1641 1642 /* Like igt_evict() but now we are limiting the search to a 1643 * small portion of the full drm_mm. 1644 */ 1645 1646 ret = -ENOMEM; 1647 nodes = vzalloc(array_size(size, sizeof(*nodes))); 1648 if (!nodes) 1649 goto err; 1650 1651 order = drm_random_order(size, &prng); 1652 if (!order) 1653 goto err_nodes; 1654 1655 ret = -EINVAL; 1656 drm_mm_init(&mm, 0, size); 1657 for (n = 0; n < size; n++) { 1658 err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1659 if (err) { 1660 pr_err("insert failed, step %d\n", n); 1661 ret = err; 1662 goto out; 1663 } 1664 } 1665 1666 for (mode = evict_modes; mode->name; mode++) { 1667 for (n = 1; n <= range_size; n <<= 1) { 1668 drm_random_reorder(order, size, &prng); 1669 err = evict_something(&mm, range_start, range_end, 1670 nodes, order, size, 1671 n, 1, 1672 mode); 1673 if (err) { 1674 pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n", 1675 mode->name, n, range_start, range_end); 1676 goto out; 1677 } 1678 } 1679 1680 for (n = 1; n <= range_size; n <<= 1) { 1681 drm_random_reorder(order, size, &prng); 1682 err = evict_something(&mm, range_start, range_end, 1683 nodes, order, size, 1684 range_size/2, n, 1685 mode); 1686 if (err) { 1687 pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 1688 mode->name, range_size/2, n, range_start, range_end); 1689 goto out; 1690 } 1691 } 1692 1693 for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 1694 unsigned int nsize = (range_size - n + 1) / 2; 1695 1696 DRM_MM_BUG_ON(!nsize); 1697 1698 drm_random_reorder(order, size, &prng); 1699 err = evict_something(&mm, range_start, range_end, 1700 nodes, order, size, 1701 nsize, n, 1702 mode); 1703 if (err) { 1704 pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 1705 mode->name, nsize, n, range_start, range_end); 1706 goto out; 1707 } 1708 } 1709 1710 cond_resched(); 1711 } 1712 1713 ret = 0; 1714out: 1715 drm_mm_for_each_node_safe(node, next, &mm) 1716 drm_mm_remove_node(node); 1717 drm_mm_takedown(&mm); 1718 kfree(order); 1719err_nodes: 1720 vfree(nodes); 1721err: 1722 return ret; 1723} 1724 1725static unsigned int node_index(const struct drm_mm_node *node) 1726{ 1727 return div64_u64(node->start, node->size); 1728} 1729 1730static int igt_topdown(void *ignored) 1731{ 1732 const struct insert_mode *topdown = &insert_modes[TOPDOWN]; 1733 DRM_RND_STATE(prng, random_seed); 1734 const unsigned int count = 8192; 1735 unsigned int size; 1736 unsigned long *bitmap; 1737 struct drm_mm mm; 1738 struct drm_mm_node *nodes, *node, *next; 1739 unsigned int *order, n, m, o = 0; 1740 int ret; 1741 1742 /* When allocating top-down, we expect to be returned a node 1743 * from a suitable hole at the top of the drm_mm. We check that 1744 * the returned node does match the highest available slot. 1745 */ 1746 1747 ret = -ENOMEM; 1748 nodes = vzalloc(array_size(count, sizeof(*nodes))); 1749 if (!nodes) 1750 goto err; 1751 1752 bitmap = bitmap_zalloc(count, GFP_KERNEL); 1753 if (!bitmap) 1754 goto err_nodes; 1755 1756 order = drm_random_order(count, &prng); 1757 if (!order) 1758 goto err_bitmap; 1759 1760 ret = -EINVAL; 1761 for (size = 1; size <= 64; size <<= 1) { 1762 drm_mm_init(&mm, 0, size*count); 1763 for (n = 0; n < count; n++) { 1764 if (!expect_insert(&mm, &nodes[n], 1765 size, 0, n, 1766 topdown)) { 1767 pr_err("insert failed, size %u step %d\n", size, n); 1768 goto out; 1769 } 1770 1771 if (drm_mm_hole_follows(&nodes[n])) { 1772 pr_err("hole after topdown insert %d, start=%llx\n, size=%u", 1773 n, nodes[n].start, size); 1774 goto out; 1775 } 1776 1777 if (!assert_one_hole(&mm, 0, size*(count - n - 1))) 1778 goto out; 1779 } 1780 1781 if (!assert_continuous(&mm, size)) 1782 goto out; 1783 1784 drm_random_reorder(order, count, &prng); 1785 for_each_prime_number_from(n, 1, min(count, max_prime)) { 1786 for (m = 0; m < n; m++) { 1787 node = &nodes[order[(o + m) % count]]; 1788 drm_mm_remove_node(node); 1789 __set_bit(node_index(node), bitmap); 1790 } 1791 1792 for (m = 0; m < n; m++) { 1793 unsigned int last; 1794 1795 node = &nodes[order[(o + m) % count]]; 1796 if (!expect_insert(&mm, node, 1797 size, 0, 0, 1798 topdown)) { 1799 pr_err("insert failed, step %d/%d\n", m, n); 1800 goto out; 1801 } 1802 1803 if (drm_mm_hole_follows(node)) { 1804 pr_err("hole after topdown insert %d/%d, start=%llx\n", 1805 m, n, node->start); 1806 goto out; 1807 } 1808 1809 last = find_last_bit(bitmap, count); 1810 if (node_index(node) != last) { 1811 pr_err("node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", 1812 m, n, size, last, node_index(node)); 1813 goto out; 1814 } 1815 1816 __clear_bit(last, bitmap); 1817 } 1818 1819 DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 1820 1821 o += n; 1822 } 1823 1824 drm_mm_for_each_node_safe(node, next, &mm) 1825 drm_mm_remove_node(node); 1826 DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1827 cond_resched(); 1828 } 1829 1830 ret = 0; 1831out: 1832 drm_mm_for_each_node_safe(node, next, &mm) 1833 drm_mm_remove_node(node); 1834 drm_mm_takedown(&mm); 1835 kfree(order); 1836err_bitmap: 1837 bitmap_free(bitmap); 1838err_nodes: 1839 vfree(nodes); 1840err: 1841 return ret; 1842} 1843 1844static int igt_bottomup(void *ignored) 1845{ 1846 const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; 1847 DRM_RND_STATE(prng, random_seed); 1848 const unsigned int count = 8192; 1849 unsigned int size; 1850 unsigned long *bitmap; 1851 struct drm_mm mm; 1852 struct drm_mm_node *nodes, *node, *next; 1853 unsigned int *order, n, m, o = 0; 1854 int ret; 1855 1856 /* Like igt_topdown, but instead of searching for the last hole, 1857 * we search for the first. 1858 */ 1859 1860 ret = -ENOMEM; 1861 nodes = vzalloc(array_size(count, sizeof(*nodes))); 1862 if (!nodes) 1863 goto err; 1864 1865 bitmap = bitmap_zalloc(count, GFP_KERNEL); 1866 if (!bitmap) 1867 goto err_nodes; 1868 1869 order = drm_random_order(count, &prng); 1870 if (!order) 1871 goto err_bitmap; 1872 1873 ret = -EINVAL; 1874 for (size = 1; size <= 64; size <<= 1) { 1875 drm_mm_init(&mm, 0, size*count); 1876 for (n = 0; n < count; n++) { 1877 if (!expect_insert(&mm, &nodes[n], 1878 size, 0, n, 1879 bottomup)) { 1880 pr_err("bottomup insert failed, size %u step %d\n", size, n); 1881 goto out; 1882 } 1883 1884 if (!assert_one_hole(&mm, size*(n + 1), size*count)) 1885 goto out; 1886 } 1887 1888 if (!assert_continuous(&mm, size)) 1889 goto out; 1890 1891 drm_random_reorder(order, count, &prng); 1892 for_each_prime_number_from(n, 1, min(count, max_prime)) { 1893 for (m = 0; m < n; m++) { 1894 node = &nodes[order[(o + m) % count]]; 1895 drm_mm_remove_node(node); 1896 __set_bit(node_index(node), bitmap); 1897 } 1898 1899 for (m = 0; m < n; m++) { 1900 unsigned int first; 1901 1902 node = &nodes[order[(o + m) % count]]; 1903 if (!expect_insert(&mm, node, 1904 size, 0, 0, 1905 bottomup)) { 1906 pr_err("insert failed, step %d/%d\n", m, n); 1907 goto out; 1908 } 1909 1910 first = find_first_bit(bitmap, count); 1911 if (node_index(node) != first) { 1912 pr_err("node %d/%d not inserted into bottom hole, expected %d, found %d\n", 1913 m, n, first, node_index(node)); 1914 goto out; 1915 } 1916 __clear_bit(first, bitmap); 1917 } 1918 1919 DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 1920 1921 o += n; 1922 } 1923 1924 drm_mm_for_each_node_safe(node, next, &mm) 1925 drm_mm_remove_node(node); 1926 DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1927 cond_resched(); 1928 } 1929 1930 ret = 0; 1931out: 1932 drm_mm_for_each_node_safe(node, next, &mm) 1933 drm_mm_remove_node(node); 1934 drm_mm_takedown(&mm); 1935 kfree(order); 1936err_bitmap: 1937 bitmap_free(bitmap); 1938err_nodes: 1939 vfree(nodes); 1940err: 1941 return ret; 1942} 1943 1944static int __igt_once(unsigned int mode) 1945{ 1946 struct drm_mm mm; 1947 struct drm_mm_node rsvd_lo, rsvd_hi, node; 1948 int err; 1949 1950 drm_mm_init(&mm, 0, 7); 1951 1952 memset(&rsvd_lo, 0, sizeof(rsvd_lo)); 1953 rsvd_lo.start = 1; 1954 rsvd_lo.size = 1; 1955 err = drm_mm_reserve_node(&mm, &rsvd_lo); 1956 if (err) { 1957 pr_err("Could not reserve low node\n"); 1958 goto err; 1959 } 1960 1961 memset(&rsvd_hi, 0, sizeof(rsvd_hi)); 1962 rsvd_hi.start = 5; 1963 rsvd_hi.size = 1; 1964 err = drm_mm_reserve_node(&mm, &rsvd_hi); 1965 if (err) { 1966 pr_err("Could not reserve low node\n"); 1967 goto err_lo; 1968 } 1969 1970 if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) { 1971 pr_err("Expected a hole after lo and high nodes!\n"); 1972 err = -EINVAL; 1973 goto err_hi; 1974 } 1975 1976 memset(&node, 0, sizeof(node)); 1977 err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode); 1978 if (err) { 1979 pr_err("Could not insert the node into the available hole!\n"); 1980 err = -EINVAL; 1981 goto err_hi; 1982 } 1983 1984 drm_mm_remove_node(&node); 1985err_hi: 1986 drm_mm_remove_node(&rsvd_hi); 1987err_lo: 1988 drm_mm_remove_node(&rsvd_lo); 1989err: 1990 drm_mm_takedown(&mm); 1991 return err; 1992} 1993 1994static int igt_lowest(void *ignored) 1995{ 1996 return __igt_once(DRM_MM_INSERT_LOW); 1997} 1998 1999static int igt_highest(void *ignored) 2000{ 2001 return __igt_once(DRM_MM_INSERT_HIGH); 2002} 2003 2004static void separate_adjacent_colors(const struct drm_mm_node *node, 2005 unsigned long color, 2006 u64 *start, 2007 u64 *end) 2008{ 2009 if (drm_mm_node_allocated(node) && node->color != color) 2010 ++*start; 2011 2012 node = list_next_entry(node, node_list); 2013 if (drm_mm_node_allocated(node) && node->color != color) 2014 --*end; 2015} 2016 2017static bool colors_abutt(const struct drm_mm_node *node) 2018{ 2019 if (!drm_mm_hole_follows(node) && 2020 drm_mm_node_allocated(list_next_entry(node, node_list))) { 2021 pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", 2022 node->color, node->start, node->size, 2023 list_next_entry(node, node_list)->color, 2024 list_next_entry(node, node_list)->start, 2025 list_next_entry(node, node_list)->size); 2026 return true; 2027 } 2028 2029 return false; 2030} 2031 2032static int igt_color(void *ignored) 2033{ 2034 const unsigned int count = min(4096u, max_iterations); 2035 const struct insert_mode *mode; 2036 struct drm_mm mm; 2037 struct drm_mm_node *node, *nn; 2038 unsigned int n; 2039 int ret = -EINVAL, err; 2040 2041 /* Color adjustment complicates everything. First we just check 2042 * that when we insert a node we apply any color_adjustment callback. 2043 * The callback we use should ensure that there is a gap between 2044 * any two nodes, and so after each insertion we check that those 2045 * holes are inserted and that they are preserved. 2046 */ 2047 2048 drm_mm_init(&mm, 0, U64_MAX); 2049 2050 for (n = 1; n <= count; n++) { 2051 node = kzalloc(sizeof(*node), GFP_KERNEL); 2052 if (!node) { 2053 ret = -ENOMEM; 2054 goto out; 2055 } 2056 2057 if (!expect_insert(&mm, node, 2058 n, 0, n, 2059 &insert_modes[0])) { 2060 pr_err("insert failed, step %d\n", n); 2061 kfree(node); 2062 goto out; 2063 } 2064 } 2065 2066 drm_mm_for_each_node_safe(node, nn, &mm) { 2067 if (node->color != node->size) { 2068 pr_err("invalid color stored: expected %lld, found %ld\n", 2069 node->size, node->color); 2070 2071 goto out; 2072 } 2073 2074 drm_mm_remove_node(node); 2075 kfree(node); 2076 } 2077 2078 /* Now, let's start experimenting with applying a color callback */ 2079 mm.color_adjust = separate_adjacent_colors; 2080 for (mode = insert_modes; mode->name; mode++) { 2081 u64 last; 2082 2083 node = kzalloc(sizeof(*node), GFP_KERNEL); 2084 if (!node) { 2085 ret = -ENOMEM; 2086 goto out; 2087 } 2088 2089 node->size = 1 + 2*count; 2090 node->color = node->size; 2091 2092 err = drm_mm_reserve_node(&mm, node); 2093 if (err) { 2094 pr_err("initial reserve failed!\n"); 2095 ret = err; 2096 goto out; 2097 } 2098 2099 last = node->start + node->size; 2100 2101 for (n = 1; n <= count; n++) { 2102 int rem; 2103 2104 node = kzalloc(sizeof(*node), GFP_KERNEL); 2105 if (!node) { 2106 ret = -ENOMEM; 2107 goto out; 2108 } 2109 2110 node->start = last; 2111 node->size = n + count; 2112 node->color = node->size; 2113 2114 err = drm_mm_reserve_node(&mm, node); 2115 if (err != -ENOSPC) { 2116 pr_err("reserve %d did not report color overlap! err=%d\n", 2117 n, err); 2118 goto out; 2119 } 2120 2121 node->start += n + 1; 2122 rem = misalignment(node, n + count); 2123 node->start += n + count - rem; 2124 2125 err = drm_mm_reserve_node(&mm, node); 2126 if (err) { 2127 pr_err("reserve %d failed, err=%d\n", n, err); 2128 ret = err; 2129 goto out; 2130 } 2131 2132 last = node->start + node->size; 2133 } 2134 2135 for (n = 1; n <= count; n++) { 2136 node = kzalloc(sizeof(*node), GFP_KERNEL); 2137 if (!node) { 2138 ret = -ENOMEM; 2139 goto out; 2140 } 2141 2142 if (!expect_insert(&mm, node, 2143 n, n, n, 2144 mode)) { 2145 pr_err("%s insert failed, step %d\n", 2146 mode->name, n); 2147 kfree(node); 2148 goto out; 2149 } 2150 } 2151 2152 drm_mm_for_each_node_safe(node, nn, &mm) { 2153 u64 rem; 2154 2155 if (node->color != node->size) { 2156 pr_err("%s invalid color stored: expected %lld, found %ld\n", 2157 mode->name, node->size, node->color); 2158 2159 goto out; 2160 } 2161 2162 if (colors_abutt(node)) 2163 goto out; 2164 2165 div64_u64_rem(node->start, node->size, &rem); 2166 if (rem) { 2167 pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", 2168 mode->name, node->start, node->size, rem); 2169 goto out; 2170 } 2171 2172 drm_mm_remove_node(node); 2173 kfree(node); 2174 } 2175 2176 cond_resched(); 2177 } 2178 2179 ret = 0; 2180out: 2181 drm_mm_for_each_node_safe(node, nn, &mm) { 2182 drm_mm_remove_node(node); 2183 kfree(node); 2184 } 2185 drm_mm_takedown(&mm); 2186 return ret; 2187} 2188 2189static int evict_color(struct drm_mm *mm, 2190 u64 range_start, u64 range_end, 2191 struct evict_node *nodes, 2192 unsigned int *order, 2193 unsigned int count, 2194 unsigned int size, 2195 unsigned int alignment, 2196 unsigned long color, 2197 const struct insert_mode *mode) 2198{ 2199 struct drm_mm_scan scan; 2200 LIST_HEAD(evict_list); 2201 struct evict_node *e; 2202 struct drm_mm_node tmp; 2203 int err; 2204 2205 drm_mm_scan_init_with_range(&scan, mm, 2206 size, alignment, color, 2207 range_start, range_end, 2208 mode->mode); 2209 if (!evict_nodes(&scan, 2210 nodes, order, count, true, 2211 &evict_list)) 2212 return -EINVAL; 2213 2214 memset(&tmp, 0, sizeof(tmp)); 2215 err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, 2216 DRM_MM_INSERT_EVICT); 2217 if (err) { 2218 pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", 2219 size, alignment, color, err); 2220 show_scan(&scan); 2221 show_holes(mm, 3); 2222 return err; 2223 } 2224 2225 if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 2226 pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 2227 tmp.start, tmp.size, range_start, range_end); 2228 err = -EINVAL; 2229 } 2230 2231 if (colors_abutt(&tmp)) 2232 err = -EINVAL; 2233 2234 if (!assert_node(&tmp, mm, size, alignment, color)) { 2235 pr_err("Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", 2236 tmp.size, size, 2237 alignment, misalignment(&tmp, alignment), tmp.start); 2238 err = -EINVAL; 2239 } 2240 2241 drm_mm_remove_node(&tmp); 2242 if (err) 2243 return err; 2244 2245 list_for_each_entry(e, &evict_list, link) { 2246 err = drm_mm_reserve_node(mm, &e->node); 2247 if (err) { 2248 pr_err("Failed to reinsert node after eviction: start=%llx\n", 2249 e->node.start); 2250 return err; 2251 } 2252 } 2253 2254 cond_resched(); 2255 return 0; 2256} 2257 2258static int igt_color_evict(void *ignored) 2259{ 2260 DRM_RND_STATE(prng, random_seed); 2261 const unsigned int total_size = min(8192u, max_iterations); 2262 const struct insert_mode *mode; 2263 unsigned long color = 0; 2264 struct drm_mm mm; 2265 struct evict_node *nodes; 2266 struct drm_mm_node *node, *next; 2267 unsigned int *order, n; 2268 int ret, err; 2269 2270 /* Check that the drm_mm_scan also honours color adjustment when 2271 * choosing its victims to create a hole. Our color_adjust does not 2272 * allow two nodes to be placed together without an intervening hole 2273 * enlarging the set of victims that must be evicted. 2274 */ 2275 2276 ret = -ENOMEM; 2277 nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 2278 if (!nodes) 2279 goto err; 2280 2281 order = drm_random_order(total_size, &prng); 2282 if (!order) 2283 goto err_nodes; 2284 2285 ret = -EINVAL; 2286 drm_mm_init(&mm, 0, 2*total_size - 1); 2287 mm.color_adjust = separate_adjacent_colors; 2288 for (n = 0; n < total_size; n++) { 2289 if (!expect_insert(&mm, &nodes[n].node, 2290 1, 0, color++, 2291 &insert_modes[0])) { 2292 pr_err("insert failed, step %d\n", n); 2293 goto out; 2294 } 2295 } 2296 2297 for (mode = evict_modes; mode->name; mode++) { 2298 for (n = 1; n <= total_size; n <<= 1) { 2299 drm_random_reorder(order, total_size, &prng); 2300 err = evict_color(&mm, 0, U64_MAX, 2301 nodes, order, total_size, 2302 n, 1, color++, 2303 mode); 2304 if (err) { 2305 pr_err("%s evict_color(size=%u) failed\n", 2306 mode->name, n); 2307 goto out; 2308 } 2309 } 2310 2311 for (n = 1; n < total_size; n <<= 1) { 2312 drm_random_reorder(order, total_size, &prng); 2313 err = evict_color(&mm, 0, U64_MAX, 2314 nodes, order, total_size, 2315 total_size/2, n, color++, 2316 mode); 2317 if (err) { 2318 pr_err("%s evict_color(size=%u, alignment=%u) failed\n", 2319 mode->name, total_size/2, n); 2320 goto out; 2321 } 2322 } 2323 2324 for_each_prime_number_from(n, 1, min(total_size, max_prime)) { 2325 unsigned int nsize = (total_size - n + 1) / 2; 2326 2327 DRM_MM_BUG_ON(!nsize); 2328 2329 drm_random_reorder(order, total_size, &prng); 2330 err = evict_color(&mm, 0, U64_MAX, 2331 nodes, order, total_size, 2332 nsize, n, color++, 2333 mode); 2334 if (err) { 2335 pr_err("%s evict_color(size=%u, alignment=%u) failed\n", 2336 mode->name, nsize, n); 2337 goto out; 2338 } 2339 } 2340 2341 cond_resched(); 2342 } 2343 2344 ret = 0; 2345out: 2346 if (ret) 2347 show_mm(&mm); 2348 drm_mm_for_each_node_safe(node, next, &mm) 2349 drm_mm_remove_node(node); 2350 drm_mm_takedown(&mm); 2351 kfree(order); 2352err_nodes: 2353 vfree(nodes); 2354err: 2355 return ret; 2356} 2357 2358static int igt_color_evict_range(void *ignored) 2359{ 2360 DRM_RND_STATE(prng, random_seed); 2361 const unsigned int total_size = 8192; 2362 const unsigned int range_size = total_size / 2; 2363 const unsigned int range_start = total_size / 4; 2364 const unsigned int range_end = range_start + range_size; 2365 const struct insert_mode *mode; 2366 unsigned long color = 0; 2367 struct drm_mm mm; 2368 struct evict_node *nodes; 2369 struct drm_mm_node *node, *next; 2370 unsigned int *order, n; 2371 int ret, err; 2372 2373 /* Like igt_color_evict(), but limited to small portion of the full 2374 * drm_mm range. 2375 */ 2376 2377 ret = -ENOMEM; 2378 nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 2379 if (!nodes) 2380 goto err; 2381 2382 order = drm_random_order(total_size, &prng); 2383 if (!order) 2384 goto err_nodes; 2385 2386 ret = -EINVAL; 2387 drm_mm_init(&mm, 0, 2*total_size - 1); 2388 mm.color_adjust = separate_adjacent_colors; 2389 for (n = 0; n < total_size; n++) { 2390 if (!expect_insert(&mm, &nodes[n].node, 2391 1, 0, color++, 2392 &insert_modes[0])) { 2393 pr_err("insert failed, step %d\n", n); 2394 goto out; 2395 } 2396 } 2397 2398 for (mode = evict_modes; mode->name; mode++) { 2399 for (n = 1; n <= range_size; n <<= 1) { 2400 drm_random_reorder(order, range_size, &prng); 2401 err = evict_color(&mm, range_start, range_end, 2402 nodes, order, total_size, 2403 n, 1, color++, 2404 mode); 2405 if (err) { 2406 pr_err("%s evict_color(size=%u) failed for range [%x, %x]\n", 2407 mode->name, n, range_start, range_end); 2408 goto out; 2409 } 2410 } 2411 2412 for (n = 1; n < range_size; n <<= 1) { 2413 drm_random_reorder(order, total_size, &prng); 2414 err = evict_color(&mm, range_start, range_end, 2415 nodes, order, total_size, 2416 range_size/2, n, color++, 2417 mode); 2418 if (err) { 2419 pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 2420 mode->name, total_size/2, n, range_start, range_end); 2421 goto out; 2422 } 2423 } 2424 2425 for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 2426 unsigned int nsize = (range_size - n + 1) / 2; 2427 2428 DRM_MM_BUG_ON(!nsize); 2429 2430 drm_random_reorder(order, total_size, &prng); 2431 err = evict_color(&mm, range_start, range_end, 2432 nodes, order, total_size, 2433 nsize, n, color++, 2434 mode); 2435 if (err) { 2436 pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 2437 mode->name, nsize, n, range_start, range_end); 2438 goto out; 2439 } 2440 } 2441 2442 cond_resched(); 2443 } 2444 2445 ret = 0; 2446out: 2447 if (ret) 2448 show_mm(&mm); 2449 drm_mm_for_each_node_safe(node, next, &mm) 2450 drm_mm_remove_node(node); 2451 drm_mm_takedown(&mm); 2452 kfree(order); 2453err_nodes: 2454 vfree(nodes); 2455err: 2456 return ret; 2457} 2458 2459#include "drm_selftest.c" 2460 2461static int __init test_drm_mm_init(void) 2462{ 2463 int err; 2464 2465 while (!random_seed) 2466 random_seed = get_random_int(); 2467 2468 pr_info("Testing DRM range manager (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n", 2469 random_seed, max_iterations, max_prime); 2470 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); 2471 2472 return err > 0 ? 0 : err; 2473} 2474 2475static void __exit test_drm_mm_exit(void) 2476{ 2477} 2478 2479module_init(test_drm_mm_init); 2480module_exit(test_drm_mm_exit); 2481 2482module_param(random_seed, uint, 0400); 2483module_param(max_iterations, uint, 0400); 2484module_param(max_prime, uint, 0400); 2485 2486MODULE_AUTHOR("Intel Corporation"); 2487MODULE_LICENSE("GPL");