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