blob: d49115186967a1260ac1db48645ac7f2832c72e2 [file] [log] [blame]
Chris Wilson50f00332016-12-22 08:36:09 +00001/*
2 * Test cases for the drm_mm range manager
3 */
4
5#define pr_fmt(fmt) "drm_mm: " fmt
6
7#include <linux/module.h>
8#include <linux/prime_numbers.h>
9#include <linux/slab.h>
10#include <linux/random.h>
11#include <linux/vmalloc.h>
12
13#include <drm/drm_mm.h>
14
15#include "../lib/drm_random.h"
16
17#define TESTS "drm_mm_selftests.h"
18#include "drm_selftest.h"
19
20static unsigned int random_seed;
21static unsigned int max_iterations = 8192;
22static unsigned int max_prime = 128;
23
Chris Wilson78866922016-12-22 08:36:13 +000024enum {
25 DEFAULT,
26 TOPDOWN,
27 BEST,
28};
29
30static const struct insert_mode {
31 const char *name;
32 unsigned int search_flags;
33 unsigned int create_flags;
34} insert_modes[] = {
35 [DEFAULT] = { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT },
36 [TOPDOWN] = { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP },
37 [BEST] = { "best", DRM_MM_SEARCH_BEST, DRM_MM_CREATE_DEFAULT },
38 {}
Chris Wilson560b3282016-12-22 08:36:17 +000039}, evict_modes[] = {
40 { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT },
41 { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP },
42 {}
Chris Wilson78866922016-12-22 08:36:13 +000043};
44
Chris Wilson50f00332016-12-22 08:36:09 +000045static int igt_sanitycheck(void *ignored)
46{
47 pr_info("%s - ok!\n", __func__);
48 return 0;
49}
50
Chris Wilson393b50f2016-12-22 08:36:10 +000051static bool assert_no_holes(const struct drm_mm *mm)
52{
53 struct drm_mm_node *hole;
54 u64 hole_start, hole_end;
55 unsigned long count;
56
57 count = 0;
58 drm_mm_for_each_hole(hole, mm, hole_start, hole_end)
59 count++;
60 if (count) {
61 pr_err("Expected to find no holes (after reserve), found %lu instead\n", count);
62 return false;
63 }
64
65 drm_mm_for_each_node(hole, mm) {
66 if (hole->hole_follows) {
67 pr_err("Hole follows node, expected none!\n");
68 return false;
69 }
70 }
71
72 return true;
73}
74
75static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end)
76{
77 struct drm_mm_node *hole;
78 u64 hole_start, hole_end;
79 unsigned long count;
80 bool ok = true;
81
82 if (end <= start)
83 return true;
84
85 count = 0;
86 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
87 if (start != hole_start || end != hole_end) {
88 if (ok)
89 pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n",
90 hole_start, hole_end,
91 start, end);
92 ok = false;
93 }
94 count++;
95 }
96 if (count != 1) {
97 pr_err("Expected to find one hole, found %lu instead\n", count);
98 ok = false;
99 }
100
101 return ok;
102}
103
Chris Wilson900537d2016-12-22 08:36:12 +0000104static bool assert_continuous(const struct drm_mm *mm, u64 size)
105{
106 struct drm_mm_node *node, *check, *found;
107 unsigned long n;
108 u64 addr;
109
110 if (!assert_no_holes(mm))
111 return false;
112
113 n = 0;
114 addr = 0;
115 drm_mm_for_each_node(node, mm) {
116 if (node->start != addr) {
117 pr_err("node[%ld] list out of order, expected %llx found %llx\n",
118 n, addr, node->start);
119 return false;
120 }
121
122 if (node->size != size) {
123 pr_err("node[%ld].size incorrect, expected %llx, found %llx\n",
124 n, size, node->size);
125 return false;
126 }
127
128 if (node->hole_follows) {
129 pr_err("node[%ld] is followed by a hole!\n", n);
130 return false;
131 }
132
133 found = NULL;
134 drm_mm_for_each_node_in_range(check, mm, addr, addr + size) {
135 if (node != check) {
136 pr_err("lookup return wrong node, expected start %llx, found %llx\n",
137 node->start, check->start);
138 return false;
139 }
140 found = check;
141 }
142 if (!found) {
143 pr_err("lookup failed for node %llx + %llx\n",
144 addr, size);
145 return false;
146 }
147
148 addr += size;
149 n++;
150 }
151
152 return true;
153}
154
Chris Wilson78866922016-12-22 08:36:13 +0000155static u64 misalignment(struct drm_mm_node *node, u64 alignment)
156{
157 u64 rem;
158
159 if (!alignment)
160 return 0;
161
162 div64_u64_rem(node->start, alignment, &rem);
163 return rem;
164}
165
166static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm,
167 u64 size, u64 alignment, unsigned long color)
168{
169 bool ok = true;
170
171 if (!drm_mm_node_allocated(node) || node->mm != mm) {
172 pr_err("node not allocated\n");
173 ok = false;
174 }
175
176 if (node->size != size) {
177 pr_err("node has wrong size, found %llu, expected %llu\n",
178 node->size, size);
179 ok = false;
180 }
181
182 if (misalignment(node, alignment)) {
183 pr_err("node is misalinged, start %llx rem %llu, expected alignment %llu\n",
184 node->start, misalignment(node, alignment), alignment);
185 ok = false;
186 }
187
188 if (node->color != color) {
189 pr_err("node has wrong color, found %lu, expected %lu\n",
190 node->color, color);
191 ok = false;
192 }
193
194 return ok;
195}
196
Chris Wilson393b50f2016-12-22 08:36:10 +0000197static int igt_init(void *ignored)
198{
199 const unsigned int size = 4096;
200 struct drm_mm mm;
201 struct drm_mm_node tmp;
202 int ret = -EINVAL;
203
204 /* Start with some simple checks on initialising the struct drm_mm */
205 memset(&mm, 0, sizeof(mm));
206 if (drm_mm_initialized(&mm)) {
207 pr_err("zeroed mm claims to be initialized\n");
208 return ret;
209 }
210
211 memset(&mm, 0xff, sizeof(mm));
212 drm_mm_init(&mm, 0, size);
213 if (!drm_mm_initialized(&mm)) {
214 pr_err("mm claims not to be initialized\n");
215 goto out;
216 }
217
218 if (!drm_mm_clean(&mm)) {
219 pr_err("mm not empty on creation\n");
220 goto out;
221 }
222
223 /* After creation, it should all be one massive hole */
224 if (!assert_one_hole(&mm, 0, size)) {
225 ret = -EINVAL;
226 goto out;
227 }
228
229 memset(&tmp, 0, sizeof(tmp));
230 tmp.start = 0;
231 tmp.size = size;
232 ret = drm_mm_reserve_node(&mm, &tmp);
233 if (ret) {
234 pr_err("failed to reserve whole drm_mm\n");
235 goto out;
236 }
237
238 /* After filling the range entirely, there should be no holes */
239 if (!assert_no_holes(&mm)) {
240 ret = -EINVAL;
241 goto out;
242 }
243
244 /* And then after emptying it again, the massive hole should be back */
245 drm_mm_remove_node(&tmp);
246 if (!assert_one_hole(&mm, 0, size)) {
247 ret = -EINVAL;
248 goto out;
249 }
250
251out:
252 if (ret)
253 drm_mm_debug_table(&mm, __func__);
254 drm_mm_takedown(&mm);
255 return ret;
256}
257
Chris Wilson06df8ac2016-12-22 08:36:11 +0000258static int igt_debug(void *ignored)
259{
260 struct drm_mm mm;
261 struct drm_mm_node nodes[2];
262 int ret;
263
264 /* Create a small drm_mm with a couple of nodes and a few holes, and
265 * check that the debug iterator doesn't explode over a trivial drm_mm.
266 */
267
268 drm_mm_init(&mm, 0, 4096);
269
270 memset(nodes, 0, sizeof(nodes));
271 nodes[0].start = 512;
272 nodes[0].size = 1024;
273 ret = drm_mm_reserve_node(&mm, &nodes[0]);
274 if (ret) {
275 pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n",
276 nodes[0].start, nodes[0].size);
277 return ret;
278 }
279
280 nodes[1].size = 1024;
281 nodes[1].start = 4096 - 512 - nodes[1].size;
282 ret = drm_mm_reserve_node(&mm, &nodes[1]);
283 if (ret) {
284 pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n",
285 nodes[1].start, nodes[1].size);
286 return ret;
287 }
288
289 drm_mm_debug_table(&mm, __func__);
290 return 0;
291}
292
Chris Wilson900537d2016-12-22 08:36:12 +0000293static struct drm_mm_node *set_node(struct drm_mm_node *node,
294 u64 start, u64 size)
295{
296 node->start = start;
297 node->size = size;
298 return node;
299}
300
301static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node)
302{
303 int err;
304
305 err = drm_mm_reserve_node(mm, node);
306 if (likely(err == -ENOSPC))
307 return true;
308
309 if (!err) {
310 pr_err("impossible reserve succeeded, node %llu + %llu\n",
311 node->start, node->size);
312 drm_mm_remove_node(node);
313 } else {
314 pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n",
315 err, -ENOSPC, node->start, node->size);
316 }
317 return false;
318}
319
320static bool check_reserve_boundaries(struct drm_mm *mm,
321 unsigned int count,
322 u64 size)
323{
324 const struct boundary {
325 u64 start, size;
326 const char *name;
327 } boundaries[] = {
328#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" }
329 B(0, 0),
330 B(-size, 0),
331 B(size, 0),
332 B(size * count, 0),
333 B(-size, size),
334 B(-size, -size),
335 B(-size, 2*size),
336 B(0, -size),
337 B(size, -size),
338 B(count*size, size),
339 B(count*size, -size),
340 B(count*size, count*size),
341 B(count*size, -count*size),
342 B(count*size, -(count+1)*size),
343 B((count+1)*size, size),
344 B((count+1)*size, -size),
345 B((count+1)*size, -2*size),
346#undef B
347 };
348 struct drm_mm_node tmp = {};
349 int n;
350
351 for (n = 0; n < ARRAY_SIZE(boundaries); n++) {
352 if (!expect_reserve_fail(mm,
353 set_node(&tmp,
354 boundaries[n].start,
355 boundaries[n].size))) {
356 pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n",
357 n, boundaries[n].name, count, size);
358 return false;
359 }
360 }
361
362 return true;
363}
364
365static int __igt_reserve(unsigned int count, u64 size)
366{
367 DRM_RND_STATE(prng, random_seed);
368 struct drm_mm mm;
369 struct drm_mm_node tmp, *nodes, *node, *next;
370 unsigned int *order, n, m, o = 0;
371 int ret, err;
372
373 /* For exercising drm_mm_reserve_node(), we want to check that
374 * reservations outside of the drm_mm range are rejected, and to
375 * overlapping and otherwise already occupied ranges. Afterwards,
376 * the tree and nodes should be intact.
377 */
378
379 DRM_MM_BUG_ON(!count);
380 DRM_MM_BUG_ON(!size);
381
382 ret = -ENOMEM;
383 order = drm_random_order(count, &prng);
384 if (!order)
385 goto err;
386
387 nodes = vzalloc(sizeof(*nodes) * count);
388 if (!nodes)
389 goto err_order;
390
391 ret = -EINVAL;
392 drm_mm_init(&mm, 0, count * size);
393
394 if (!check_reserve_boundaries(&mm, count, size))
395 goto out;
396
397 for (n = 0; n < count; n++) {
398 nodes[n].start = order[n] * size;
399 nodes[n].size = size;
400
401 err = drm_mm_reserve_node(&mm, &nodes[n]);
402 if (err) {
403 pr_err("reserve failed, step %d, start %llu\n",
404 n, nodes[n].start);
405 ret = err;
406 goto out;
407 }
408
409 if (!drm_mm_node_allocated(&nodes[n])) {
410 pr_err("reserved node not allocated! step %d, start %llu\n",
411 n, nodes[n].start);
412 goto out;
413 }
414
415 if (!expect_reserve_fail(&mm, &nodes[n]))
416 goto out;
417 }
418
419 /* After random insertion the nodes should be in order */
420 if (!assert_continuous(&mm, size))
421 goto out;
422
423 /* Repeated use should then fail */
424 drm_random_reorder(order, count, &prng);
425 for (n = 0; n < count; n++) {
426 if (!expect_reserve_fail(&mm,
427 set_node(&tmp, order[n] * size, 1)))
428 goto out;
429
430 /* Remove and reinsert should work */
431 drm_mm_remove_node(&nodes[order[n]]);
432 err = drm_mm_reserve_node(&mm, &nodes[order[n]]);
433 if (err) {
434 pr_err("reserve failed, step %d, start %llu\n",
435 n, nodes[n].start);
436 ret = err;
437 goto out;
438 }
439 }
440
441 if (!assert_continuous(&mm, size))
442 goto out;
443
444 /* Overlapping use should then fail */
445 for (n = 0; n < count; n++) {
446 if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count)))
447 goto out;
448 }
449 for (n = 0; n < count; n++) {
450 if (!expect_reserve_fail(&mm,
451 set_node(&tmp,
452 size * n,
453 size * (count - n))))
454 goto out;
455 }
456
457 /* Remove several, reinsert, check full */
458 for_each_prime_number(n, min(max_prime, count)) {
459 for (m = 0; m < n; m++) {
460 node = &nodes[order[(o + m) % count]];
461 drm_mm_remove_node(node);
462 }
463
464 for (m = 0; m < n; m++) {
465 node = &nodes[order[(o + m) % count]];
466 err = drm_mm_reserve_node(&mm, node);
467 if (err) {
468 pr_err("reserve failed, step %d/%d, start %llu\n",
469 m, n, node->start);
470 ret = err;
471 goto out;
472 }
473 }
474
475 o += n;
476
477 if (!assert_continuous(&mm, size))
478 goto out;
479 }
480
481 ret = 0;
482out:
483 drm_mm_for_each_node_safe(node, next, &mm)
484 drm_mm_remove_node(node);
485 drm_mm_takedown(&mm);
486 vfree(nodes);
487err_order:
488 kfree(order);
489err:
490 return ret;
491}
492
493static int igt_reserve(void *ignored)
494{
495 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
496 int n, ret;
497
498 for_each_prime_number_from(n, 1, 54) {
499 u64 size = BIT_ULL(n);
500
501 ret = __igt_reserve(count, size - 1);
502 if (ret)
503 return ret;
504
505 ret = __igt_reserve(count, size);
506 if (ret)
507 return ret;
508
509 ret = __igt_reserve(count, size + 1);
510 if (ret)
511 return ret;
512 }
513
514 return 0;
515}
516
Chris Wilson78866922016-12-22 08:36:13 +0000517static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
518 u64 size, u64 alignment, unsigned long color,
519 const struct insert_mode *mode)
520{
521 int err;
522
523 err = drm_mm_insert_node_generic(mm, node,
524 size, alignment, color,
525 mode->search_flags,
526 mode->create_flags);
527 if (err) {
528 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n",
529 size, alignment, color, mode->name, err);
530 return false;
531 }
532
533 if (!assert_node(node, mm, size, alignment, color)) {
534 drm_mm_remove_node(node);
535 return false;
536 }
537
538 return true;
539}
540
541static bool expect_insert_fail(struct drm_mm *mm, u64 size)
542{
543 struct drm_mm_node tmp = {};
544 int err;
545
546 err = drm_mm_insert_node(mm, &tmp, size, 0, DRM_MM_SEARCH_DEFAULT);
547 if (likely(err == -ENOSPC))
548 return true;
549
550 if (!err) {
551 pr_err("impossible insert succeeded, node %llu + %llu\n",
552 tmp.start, tmp.size);
553 drm_mm_remove_node(&tmp);
554 } else {
555 pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n",
556 err, -ENOSPC, size);
557 }
558 return false;
559}
560
Chris Wilson2bd966d2016-12-22 08:36:14 +0000561static int __igt_insert(unsigned int count, u64 size, bool replace)
Chris Wilson78866922016-12-22 08:36:13 +0000562{
563 DRM_RND_STATE(prng, random_seed);
564 const struct insert_mode *mode;
565 struct drm_mm mm;
566 struct drm_mm_node *nodes, *node, *next;
567 unsigned int *order, n, m, o = 0;
568 int ret;
569
570 /* Fill a range with lots of nodes, check it doesn't fail too early */
571
572 DRM_MM_BUG_ON(!count);
573 DRM_MM_BUG_ON(!size);
574
575 ret = -ENOMEM;
Chris Wilson2bd966d2016-12-22 08:36:14 +0000576 nodes = vmalloc(count * sizeof(*nodes));
Chris Wilson78866922016-12-22 08:36:13 +0000577 if (!nodes)
578 goto err;
579
580 order = drm_random_order(count, &prng);
581 if (!order)
582 goto err_nodes;
583
584 ret = -EINVAL;
585 drm_mm_init(&mm, 0, count * size);
586
587 for (mode = insert_modes; mode->name; mode++) {
588 for (n = 0; n < count; n++) {
Chris Wilson2bd966d2016-12-22 08:36:14 +0000589 struct drm_mm_node tmp;
590
591 node = replace ? &tmp : &nodes[n];
592 memset(node, 0, sizeof(*node));
593 if (!expect_insert(&mm, node, size, 0, n, mode)) {
Chris Wilson78866922016-12-22 08:36:13 +0000594 pr_err("%s insert failed, size %llu step %d\n",
595 mode->name, size, n);
596 goto out;
597 }
Chris Wilson2bd966d2016-12-22 08:36:14 +0000598
599 if (replace) {
600 drm_mm_replace_node(&tmp, &nodes[n]);
601 if (drm_mm_node_allocated(&tmp)) {
602 pr_err("replaced old-node still allocated! step %d\n",
603 n);
604 goto out;
605 }
606
607 if (!assert_node(&nodes[n], &mm, size, 0, n)) {
608 pr_err("replaced node did not inherit parameters, size %llu step %d\n",
609 size, n);
610 goto out;
611 }
612
613 if (tmp.start != nodes[n].start) {
614 pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n",
615 tmp.start, size,
616 nodes[n].start, nodes[n].size);
617 goto out;
618 }
619 }
Chris Wilson78866922016-12-22 08:36:13 +0000620 }
621
622 /* After random insertion the nodes should be in order */
623 if (!assert_continuous(&mm, size))
624 goto out;
625
626 /* Repeated use should then fail */
627 if (!expect_insert_fail(&mm, size))
628 goto out;
629
630 /* Remove one and reinsert, as the only hole it should refill itself */
631 for (n = 0; n < count; n++) {
632 u64 addr = nodes[n].start;
633
634 drm_mm_remove_node(&nodes[n]);
635 if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) {
636 pr_err("%s reinsert failed, size %llu step %d\n",
637 mode->name, size, n);
638 goto out;
639 }
640
641 if (nodes[n].start != addr) {
642 pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
643 mode->name, n, addr, nodes[n].start);
644 goto out;
645 }
646
647 if (!assert_continuous(&mm, size))
648 goto out;
649 }
650
651 /* Remove several, reinsert, check full */
652 for_each_prime_number(n, min(max_prime, count)) {
653 for (m = 0; m < n; m++) {
654 node = &nodes[order[(o + m) % count]];
655 drm_mm_remove_node(node);
656 }
657
658 for (m = 0; m < n; m++) {
659 node = &nodes[order[(o + m) % count]];
660 if (!expect_insert(&mm, node, size, 0, n, mode)) {
661 pr_err("%s multiple reinsert failed, size %llu step %d\n",
662 mode->name, size, n);
663 goto out;
664 }
665 }
666
667 o += n;
668
669 if (!assert_continuous(&mm, size))
670 goto out;
671
672 if (!expect_insert_fail(&mm, size))
673 goto out;
674 }
675
676 drm_mm_for_each_node_safe(node, next, &mm)
677 drm_mm_remove_node(node);
678 DRM_MM_BUG_ON(!drm_mm_clean(&mm));
679 }
680
681 ret = 0;
682out:
683 drm_mm_for_each_node_safe(node, next, &mm)
684 drm_mm_remove_node(node);
685 drm_mm_takedown(&mm);
686 kfree(order);
687err_nodes:
688 vfree(nodes);
689err:
690 return ret;
691}
692
693static int igt_insert(void *ignored)
694{
695 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
696 unsigned int n;
697 int ret;
698
699 for_each_prime_number_from(n, 1, 54) {
700 u64 size = BIT_ULL(n);
701
Chris Wilson2bd966d2016-12-22 08:36:14 +0000702 ret = __igt_insert(count, size - 1, false);
Chris Wilson78866922016-12-22 08:36:13 +0000703 if (ret)
704 return ret;
705
Chris Wilson2bd966d2016-12-22 08:36:14 +0000706 ret = __igt_insert(count, size, false);
Chris Wilson78866922016-12-22 08:36:13 +0000707 if (ret)
708 return ret;
709
Chris Wilson2bd966d2016-12-22 08:36:14 +0000710 ret = __igt_insert(count, size + 1, false);
711 }
712
713 return 0;
714}
715
716static int igt_replace(void *ignored)
717{
718 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
719 unsigned int n;
720 int ret;
721
722 /* Reuse igt_insert to exercise replacement by inserting a dummy node,
723 * then replacing it with the intended node. We want to check that
724 * the tree is intact and all the information we need is carried
725 * across to the target node.
726 */
727
728 for_each_prime_number_from(n, 1, 54) {
729 u64 size = BIT_ULL(n);
730
731 ret = __igt_insert(count, size - 1, true);
Chris Wilson78866922016-12-22 08:36:13 +0000732 if (ret)
733 return ret;
Chris Wilson2bd966d2016-12-22 08:36:14 +0000734
735 ret = __igt_insert(count, size, true);
736 if (ret)
737 return ret;
738
739 ret = __igt_insert(count, size + 1, true);
Chris Wilson78866922016-12-22 08:36:13 +0000740 }
741
742 return 0;
743}
744
Chris Wilson2fba0de2016-12-22 08:36:15 +0000745static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node,
746 u64 size, u64 alignment, unsigned long color,
747 u64 range_start, u64 range_end,
748 const struct insert_mode *mode)
749{
750 int err;
751
752 err = drm_mm_insert_node_in_range_generic(mm, node,
753 size, alignment, color,
754 range_start, range_end,
755 mode->search_flags,
756 mode->create_flags);
757 if (err) {
758 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n",
759 size, alignment, color, mode->name,
760 range_start, range_end, err);
761 return false;
762 }
763
764 if (!assert_node(node, mm, size, alignment, color)) {
765 drm_mm_remove_node(node);
766 return false;
767 }
768
769 return true;
770}
771
772static bool expect_insert_in_range_fail(struct drm_mm *mm,
773 u64 size,
774 u64 range_start,
775 u64 range_end)
776{
777 struct drm_mm_node tmp = {};
778 int err;
779
780 err = drm_mm_insert_node_in_range_generic(mm, &tmp,
781 size, 0, 0,
782 range_start, range_end,
783 DRM_MM_SEARCH_DEFAULT,
784 DRM_MM_CREATE_DEFAULT);
785 if (likely(err == -ENOSPC))
786 return true;
787
788 if (!err) {
789 pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n",
790 tmp.start, tmp.size, range_start, range_end);
791 drm_mm_remove_node(&tmp);
792 } else {
793 pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n",
794 err, -ENOSPC, size, range_start, range_end);
795 }
796
797 return false;
798}
799
800static bool assert_contiguous_in_range(struct drm_mm *mm,
801 u64 size,
802 u64 start,
803 u64 end)
804{
805 struct drm_mm_node *node;
806 unsigned int n;
807
808 if (!expect_insert_in_range_fail(mm, size, start, end))
809 return false;
810
811 n = div64_u64(start + size - 1, size);
812 drm_mm_for_each_node(node, mm) {
813 if (node->start < start || node->start + node->size > end) {
814 pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n",
815 n, node->start, node->start + node->size, start, end);
816 return false;
817 }
818
819 if (node->start != n * size) {
820 pr_err("node %d out of order, expected start %llx, found %llx\n",
821 n, n * size, node->start);
822 return false;
823 }
824
825 if (node->size != size) {
826 pr_err("node %d has wrong size, expected size %llx, found %llx\n",
827 n, size, node->size);
828 return false;
829 }
830
831 if (node->hole_follows && drm_mm_hole_node_end(node) < end) {
832 pr_err("node %d is followed by a hole!\n", n);
833 return false;
834 }
835
836 n++;
837 }
838
839 drm_mm_for_each_node_in_range(node, mm, 0, start) {
840 if (node) {
841 pr_err("node before start: node=%llx+%llu, start=%llx\n",
842 node->start, node->size, start);
843 return false;
844 }
845 }
846
847 drm_mm_for_each_node_in_range(node, mm, end, U64_MAX) {
848 if (node) {
849 pr_err("node after end: node=%llx+%llu, end=%llx\n",
850 node->start, node->size, end);
851 return false;
852 }
853 }
854
855 return true;
856}
857
858static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end)
859{
860 const struct insert_mode *mode;
861 struct drm_mm mm;
862 struct drm_mm_node *nodes, *node, *next;
863 unsigned int n, start_n, end_n;
864 int ret;
865
866 DRM_MM_BUG_ON(!count);
867 DRM_MM_BUG_ON(!size);
868 DRM_MM_BUG_ON(end <= start);
869
870 /* Very similar to __igt_insert(), but now instead of populating the
871 * full range of the drm_mm, we try to fill a small portion of it.
872 */
873
874 ret = -ENOMEM;
875 nodes = vzalloc(count * sizeof(*nodes));
876 if (!nodes)
877 goto err;
878
879 ret = -EINVAL;
880 drm_mm_init(&mm, 0, count * size);
881
882 start_n = div64_u64(start + size - 1, size);
883 end_n = div64_u64(end - size, size);
884
885 for (mode = insert_modes; mode->name; mode++) {
886 for (n = start_n; n <= end_n; n++) {
887 if (!expect_insert_in_range(&mm, &nodes[n],
888 size, size, n,
889 start, end, mode)) {
890 pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n",
891 mode->name, size, n,
892 start_n, end_n,
893 start, end);
894 goto out;
895 }
896 }
897
898 if (!assert_contiguous_in_range(&mm, size, start, end)) {
899 pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n",
900 mode->name, start, end, size);
901 goto out;
902 }
903
904 /* Remove one and reinsert, it should refill itself */
905 for (n = start_n; n <= end_n; n++) {
906 u64 addr = nodes[n].start;
907
908 drm_mm_remove_node(&nodes[n]);
909 if (!expect_insert_in_range(&mm, &nodes[n],
910 size, size, n,
911 start, end, mode)) {
912 pr_err("%s reinsert failed, step %d\n", mode->name, n);
913 goto out;
914 }
915
916 if (nodes[n].start != addr) {
917 pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
918 mode->name, n, addr, nodes[n].start);
919 goto out;
920 }
921 }
922
923 if (!assert_contiguous_in_range(&mm, size, start, end)) {
924 pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n",
925 mode->name, start, end, size);
926 goto out;
927 }
928
929 drm_mm_for_each_node_safe(node, next, &mm)
930 drm_mm_remove_node(node);
931 DRM_MM_BUG_ON(!drm_mm_clean(&mm));
932 }
933
934 ret = 0;
935out:
936 drm_mm_for_each_node_safe(node, next, &mm)
937 drm_mm_remove_node(node);
938 drm_mm_takedown(&mm);
939 vfree(nodes);
940err:
941 return ret;
942}
943
944static int insert_outside_range(void)
945{
946 struct drm_mm mm;
947 const unsigned int start = 1024;
948 const unsigned int end = 2048;
949 const unsigned int size = end - start;
950
951 drm_mm_init(&mm, start, size);
952
953 if (!expect_insert_in_range_fail(&mm, 1, 0, start))
954 return -EINVAL;
955
956 if (!expect_insert_in_range_fail(&mm, size,
957 start - size/2, start + (size+1)/2))
958 return -EINVAL;
959
960 if (!expect_insert_in_range_fail(&mm, size,
961 end - (size+1)/2, end + size/2))
962 return -EINVAL;
963
964 if (!expect_insert_in_range_fail(&mm, 1, end, end + size))
965 return -EINVAL;
966
967 drm_mm_takedown(&mm);
968 return 0;
969}
970
971static int igt_insert_range(void *ignored)
972{
973 const unsigned int count = min_t(unsigned int, BIT(13), max_iterations);
974 unsigned int n;
975 int ret;
976
977 /* Check that requests outside the bounds of drm_mm are rejected. */
978 ret = insert_outside_range();
979 if (ret)
980 return ret;
981
982 for_each_prime_number_from(n, 1, 50) {
983 const u64 size = BIT_ULL(n);
984 const u64 max = count * size;
985
986 ret = __igt_insert_range(count, size, 0, max);
987 if (ret)
988 return ret;
989
990 ret = __igt_insert_range(count, size, 1, max);
991 if (ret)
992 return ret;
993
994 ret = __igt_insert_range(count, size, 0, max - 1);
995 if (ret)
996 return ret;
997
998 ret = __igt_insert_range(count, size, 0, max/2);
999 if (ret)
1000 return ret;
1001
1002 ret = __igt_insert_range(count, size, max/2, max);
1003 if (ret)
1004 return ret;
1005
1006 ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1);
1007 if (ret)
1008 return ret;
1009 }
1010
1011 return 0;
1012}
1013
Chris Wilson9b26f2e2016-12-22 08:36:16 +00001014static int igt_align(void *ignored)
1015{
1016 const struct insert_mode *mode;
1017 const unsigned int max_count = min(8192u, max_prime);
1018 struct drm_mm mm;
1019 struct drm_mm_node *nodes, *node, *next;
1020 unsigned int prime;
1021 int ret = -EINVAL;
1022
1023 /* For each of the possible insertion modes, we pick a few
1024 * arbitrary alignments and check that the inserted node
1025 * meets our requirements.
1026 */
1027
1028 nodes = vzalloc(max_count * sizeof(*nodes));
1029 if (!nodes)
1030 goto err;
1031
1032 drm_mm_init(&mm, 1, U64_MAX - 2);
1033
1034 for (mode = insert_modes; mode->name; mode++) {
1035 unsigned int i = 0;
1036
1037 for_each_prime_number_from(prime, 1, max_count) {
1038 u64 size = next_prime_number(prime);
1039
1040 if (!expect_insert(&mm, &nodes[i],
1041 size, prime, i,
1042 mode)) {
1043 pr_err("%s insert failed with alignment=%d",
1044 mode->name, prime);
1045 goto out;
1046 }
1047
1048 i++;
1049 }
1050
1051 drm_mm_for_each_node_safe(node, next, &mm)
1052 drm_mm_remove_node(node);
1053 DRM_MM_BUG_ON(!drm_mm_clean(&mm));
1054 }
1055
1056 ret = 0;
1057out:
1058 drm_mm_for_each_node_safe(node, next, &mm)
1059 drm_mm_remove_node(node);
1060 drm_mm_takedown(&mm);
1061 vfree(nodes);
1062err:
1063 return ret;
1064}
1065
1066static int igt_align_pot(int max)
1067{
1068 struct drm_mm mm;
1069 struct drm_mm_node *node, *next;
1070 int bit;
1071 int ret = -EINVAL;
1072
1073 /* Check that we can align to the full u64 address space */
1074
1075 drm_mm_init(&mm, 1, U64_MAX - 2);
1076
1077 for (bit = max - 1; bit; bit--) {
1078 u64 align, size;
1079
1080 node = kzalloc(sizeof(*node), GFP_KERNEL);
1081 if (!node) {
1082 ret = -ENOMEM;
1083 goto out;
1084 }
1085
1086 align = BIT_ULL(bit);
1087 size = BIT_ULL(bit-1) + 1;
1088 if (!expect_insert(&mm, node,
1089 size, align, bit,
1090 &insert_modes[0])) {
1091 pr_err("insert failed with alignment=%llx [%d]",
1092 align, bit);
1093 goto out;
1094 }
1095 }
1096
1097 ret = 0;
1098out:
1099 drm_mm_for_each_node_safe(node, next, &mm) {
1100 drm_mm_remove_node(node);
1101 kfree(node);
1102 }
1103 drm_mm_takedown(&mm);
1104 return ret;
1105}
1106
1107static int igt_align32(void *ignored)
1108{
1109 return igt_align_pot(32);
1110}
1111
1112static int igt_align64(void *ignored)
1113{
1114 return igt_align_pot(64);
1115}
1116
Chris Wilson560b3282016-12-22 08:36:17 +00001117static void show_scan(const struct drm_mm *scan)
1118{
1119 pr_info("scan: hit [%llx, %llx], size=%lld, align=%d, color=%ld\n",
1120 scan->scan_hit_start, scan->scan_hit_end,
1121 scan->scan_size, scan->scan_alignment, scan->scan_color);
1122}
1123
1124static void show_holes(const struct drm_mm *mm, int count)
1125{
1126 u64 hole_start, hole_end;
1127 struct drm_mm_node *hole;
1128
1129 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
1130 struct drm_mm_node *next = list_next_entry(hole, node_list);
1131 const char *node1 = NULL, *node2 = NULL;
1132
1133 if (hole->allocated)
1134 node1 = kasprintf(GFP_KERNEL,
1135 "[%llx + %lld, color=%ld], ",
1136 hole->start, hole->size, hole->color);
1137
1138 if (next->allocated)
1139 node2 = kasprintf(GFP_KERNEL,
1140 ", [%llx + %lld, color=%ld]",
1141 next->start, next->size, next->color);
1142
1143 pr_info("%sHole [%llx - %llx, size %lld]%s\n",
1144 node1,
1145 hole_start, hole_end, hole_end - hole_start,
1146 node2);
1147
1148 kfree(node2);
1149 kfree(node1);
1150
1151 if (!--count)
1152 break;
1153 }
1154}
1155
1156struct evict_node {
1157 struct drm_mm_node node;
1158 struct list_head link;
1159};
1160
1161static bool evict_nodes(struct drm_mm *mm,
1162 struct evict_node *nodes,
1163 unsigned int *order,
1164 unsigned int count,
1165 struct list_head *evict_list)
1166{
1167 struct evict_node *e, *en;
1168 unsigned int i;
1169
1170 for (i = 0; i < count; i++) {
1171 e = &nodes[order ? order[i] : i];
1172 list_add(&e->link, evict_list);
1173 if (drm_mm_scan_add_block(&e->node))
1174 break;
1175 }
1176 list_for_each_entry_safe(e, en, evict_list, link) {
1177 if (!drm_mm_scan_remove_block(&e->node))
1178 list_del(&e->link);
1179 }
1180 if (list_empty(evict_list)) {
1181 pr_err("Failed to find eviction: size=%lld [avail=%d], align=%d (color=%lu)\n",
1182 mm->scan_size, count,
1183 mm->scan_alignment,
1184 mm->scan_color);
1185 return false;
1186 }
1187
1188 list_for_each_entry(e, evict_list, link)
1189 drm_mm_remove_node(&e->node);
1190
1191 return true;
1192}
1193
1194static bool evict_nothing(struct drm_mm *mm,
1195 unsigned int total_size,
1196 struct evict_node *nodes)
1197{
1198 LIST_HEAD(evict_list);
1199 struct evict_node *e;
1200 struct drm_mm_node *node;
1201 unsigned int n;
1202
1203 drm_mm_init_scan(mm, 1, 0, 0);
1204 for (n = 0; n < total_size; n++) {
1205 e = &nodes[n];
1206 list_add(&e->link, &evict_list);
1207 drm_mm_scan_add_block(&e->node);
1208 }
1209 list_for_each_entry(e, &evict_list, link)
1210 drm_mm_scan_remove_block(&e->node);
1211
1212 for (n = 0; n < total_size; n++) {
1213 e = &nodes[n];
1214
1215 if (!drm_mm_node_allocated(&e->node)) {
1216 pr_err("node[%d] no longer allocated!\n", n);
1217 return false;
1218 }
1219
1220 e->link.next = NULL;
1221 }
1222
1223 drm_mm_for_each_node(node, mm) {
1224 e = container_of(node, typeof(*e), node);
1225 e->link.next = &e->link;
1226 }
1227
1228 for (n = 0; n < total_size; n++) {
1229 e = &nodes[n];
1230
1231 if (!e->link.next) {
1232 pr_err("node[%d] no longer connected!\n", n);
1233 return false;
1234 }
1235 }
1236
1237 return assert_continuous(mm, nodes[0].node.size);
1238}
1239
1240static bool evict_everything(struct drm_mm *mm,
1241 unsigned int total_size,
1242 struct evict_node *nodes)
1243{
1244 LIST_HEAD(evict_list);
1245 struct evict_node *e;
1246 unsigned int n;
1247 int err;
1248
1249 drm_mm_init_scan(mm, total_size, 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(&e->node);
1254 }
1255 list_for_each_entry(e, &evict_list, link) {
1256 if (!drm_mm_scan_remove_block(&e->node)) {
1257 pr_err("Node %lld not marked for eviction!\n",
1258 e->node.start);
1259 list_del(&e->link);
1260 }
1261 }
1262
1263 list_for_each_entry(e, &evict_list, link)
1264 drm_mm_remove_node(&e->node);
1265
1266 if (!assert_one_hole(mm, 0, total_size))
1267 return false;
1268
1269 list_for_each_entry(e, &evict_list, link) {
1270 err = drm_mm_reserve_node(mm, &e->node);
1271 if (err) {
1272 pr_err("Failed to reinsert node after eviction: start=%llx\n",
1273 e->node.start);
1274 return false;
1275 }
1276 }
1277
1278 return assert_continuous(mm, nodes[0].node.size);
1279}
1280
1281static int evict_something(struct drm_mm *mm,
Chris Wilson0e483252016-12-22 08:36:18 +00001282 u64 range_start, u64 range_end,
Chris Wilson560b3282016-12-22 08:36:17 +00001283 struct evict_node *nodes,
1284 unsigned int *order,
1285 unsigned int count,
1286 unsigned int size,
1287 unsigned int alignment,
1288 const struct insert_mode *mode)
1289{
1290 LIST_HEAD(evict_list);
1291 struct evict_node *e;
1292 struct drm_mm_node tmp;
1293 int err;
1294
Chris Wilson0e483252016-12-22 08:36:18 +00001295 drm_mm_init_scan_with_range(mm,
1296 size, alignment, 0,
1297 range_start, range_end);
Chris Wilson560b3282016-12-22 08:36:17 +00001298 if (!evict_nodes(mm,
1299 nodes, order, count,
1300 &evict_list))
1301 return -EINVAL;
1302
1303 memset(&tmp, 0, sizeof(tmp));
1304 err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0,
1305 mode->search_flags,
1306 mode->create_flags);
1307 if (err) {
1308 pr_err("Failed to insert into eviction hole: size=%d, align=%d\n",
1309 size, alignment);
1310 show_scan(mm);
1311 show_holes(mm, 3);
1312 return err;
1313 }
1314
Chris Wilson0e483252016-12-22 08:36:18 +00001315 if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
1316 pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
1317 tmp.start, tmp.size, range_start, range_end);
1318 err = -EINVAL;
1319 }
1320
Chris Wilson560b3282016-12-22 08:36:17 +00001321 if (!assert_node(&tmp, mm, size, alignment, 0) || tmp.hole_follows) {
1322 pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n",
1323 tmp.size, size,
1324 alignment, misalignment(&tmp, alignment),
1325 tmp.start, tmp.hole_follows);
1326 err = -EINVAL;
1327 }
1328
1329 drm_mm_remove_node(&tmp);
1330 if (err)
1331 return err;
1332
1333 list_for_each_entry(e, &evict_list, link) {
1334 err = drm_mm_reserve_node(mm, &e->node);
1335 if (err) {
1336 pr_err("Failed to reinsert node after eviction: start=%llx\n",
1337 e->node.start);
1338 return err;
1339 }
1340 }
1341
1342 if (!assert_continuous(mm, nodes[0].node.size)) {
1343 pr_err("range is no longer continuous\n");
1344 return -EINVAL;
1345 }
1346
1347 return 0;
1348}
1349
1350static int igt_evict(void *ignored)
1351{
1352 DRM_RND_STATE(prng, random_seed);
1353 const unsigned int size = 8192;
1354 const struct insert_mode *mode;
1355 struct drm_mm mm;
1356 struct evict_node *nodes;
1357 struct drm_mm_node *node, *next;
1358 unsigned int *order, n;
1359 int ret, err;
1360
1361 /* Here we populate a full drm_mm and then try and insert a new node
1362 * by evicting other nodes in a random order. The drm_mm_scan should
1363 * pick the first matching hole it finds from the random list. We
1364 * repeat that for different allocation strategies, alignments and
1365 * sizes to try and stress the hole finder.
1366 */
1367
1368 ret = -ENOMEM;
1369 nodes = vzalloc(size * sizeof(*nodes));
1370 if (!nodes)
1371 goto err;
1372
1373 order = drm_random_order(size, &prng);
1374 if (!order)
1375 goto err_nodes;
1376
1377 ret = -EINVAL;
1378 drm_mm_init(&mm, 0, size);
1379 for (n = 0; n < size; n++) {
1380 err = drm_mm_insert_node(&mm, &nodes[n].node, 1, 0,
1381 DRM_MM_SEARCH_DEFAULT);
1382 if (err) {
1383 pr_err("insert failed, step %d\n", n);
1384 ret = err;
1385 goto out;
1386 }
1387 }
1388
1389 /* First check that using the scanner doesn't break the mm */
1390 if (!evict_nothing(&mm, size, nodes)) {
1391 pr_err("evict_nothing() failed\n");
1392 goto out;
1393 }
1394 if (!evict_everything(&mm, size, nodes)) {
1395 pr_err("evict_everything() failed\n");
1396 goto out;
1397 }
1398
1399 for (mode = evict_modes; mode->name; mode++) {
1400 for (n = 1; n <= size; n <<= 1) {
1401 drm_random_reorder(order, size, &prng);
Chris Wilson0e483252016-12-22 08:36:18 +00001402 err = evict_something(&mm, 0, U64_MAX,
Chris Wilson560b3282016-12-22 08:36:17 +00001403 nodes, order, size,
1404 n, 1,
1405 mode);
1406 if (err) {
1407 pr_err("%s evict_something(size=%u) failed\n",
1408 mode->name, n);
1409 ret = err;
1410 goto out;
1411 }
1412 }
1413
1414 for (n = 1; n < size; n <<= 1) {
1415 drm_random_reorder(order, size, &prng);
Chris Wilson0e483252016-12-22 08:36:18 +00001416 err = evict_something(&mm, 0, U64_MAX,
Chris Wilson560b3282016-12-22 08:36:17 +00001417 nodes, order, size,
1418 size/2, n,
1419 mode);
1420 if (err) {
1421 pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
1422 mode->name, size/2, n);
1423 ret = err;
1424 goto out;
1425 }
1426 }
1427
1428 for_each_prime_number_from(n, 1, min(size, max_prime)) {
1429 unsigned int nsize = (size - n + 1) / 2;
1430
1431 DRM_MM_BUG_ON(!nsize);
1432
1433 drm_random_reorder(order, size, &prng);
Chris Wilson0e483252016-12-22 08:36:18 +00001434 err = evict_something(&mm, 0, U64_MAX,
Chris Wilson560b3282016-12-22 08:36:17 +00001435 nodes, order, size,
1436 nsize, n,
1437 mode);
1438 if (err) {
1439 pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
1440 mode->name, nsize, n);
1441 ret = err;
1442 goto out;
1443 }
1444 }
1445 }
1446
1447 ret = 0;
1448out:
1449 drm_mm_for_each_node_safe(node, next, &mm)
1450 drm_mm_remove_node(node);
1451 drm_mm_takedown(&mm);
1452 kfree(order);
1453err_nodes:
1454 vfree(nodes);
1455err:
1456 return ret;
1457}
1458
Chris Wilson0e483252016-12-22 08:36:18 +00001459static int igt_evict_range(void *ignored)
1460{
1461 DRM_RND_STATE(prng, random_seed);
1462 const unsigned int size = 8192;
1463 const unsigned int range_size = size / 2;
1464 const unsigned int range_start = size / 4;
1465 const unsigned int range_end = range_start + range_size;
1466 const struct insert_mode *mode;
1467 struct drm_mm mm;
1468 struct evict_node *nodes;
1469 struct drm_mm_node *node, *next;
1470 unsigned int *order, n;
1471 int ret, err;
1472
1473 /* Like igt_evict() but now we are limiting the search to a
1474 * small portion of the full drm_mm.
1475 */
1476
1477 ret = -ENOMEM;
1478 nodes = vzalloc(size * sizeof(*nodes));
1479 if (!nodes)
1480 goto err;
1481
1482 order = drm_random_order(size, &prng);
1483 if (!order)
1484 goto err_nodes;
1485
1486 ret = -EINVAL;
1487 drm_mm_init(&mm, 0, size);
1488 for (n = 0; n < size; n++) {
1489 err = drm_mm_insert_node(&mm, &nodes[n].node, 1, 0,
1490 DRM_MM_SEARCH_DEFAULT);
1491 if (err) {
1492 pr_err("insert failed, step %d\n", n);
1493 ret = err;
1494 goto out;
1495 }
1496 }
1497
1498 for (mode = evict_modes; mode->name; mode++) {
1499 for (n = 1; n <= range_size; n <<= 1) {
1500 drm_random_reorder(order, size, &prng);
1501 err = evict_something(&mm, range_start, range_end,
1502 nodes, order, size,
1503 n, 1,
1504 mode);
1505 if (err) {
1506 pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n",
1507 mode->name, n, range_start, range_end);
1508 goto out;
1509 }
1510 }
1511
1512 for (n = 1; n <= range_size; n <<= 1) {
1513 drm_random_reorder(order, size, &prng);
1514 err = evict_something(&mm, range_start, range_end,
1515 nodes, order, size,
1516 range_size/2, n,
1517 mode);
1518 if (err) {
1519 pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
1520 mode->name, range_size/2, n, range_start, range_end);
1521 goto out;
1522 }
1523 }
1524
1525 for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
1526 unsigned int nsize = (range_size - n + 1) / 2;
1527
1528 DRM_MM_BUG_ON(!nsize);
1529
1530 drm_random_reorder(order, size, &prng);
1531 err = evict_something(&mm, range_start, range_end,
1532 nodes, order, size,
1533 nsize, n,
1534 mode);
1535 if (err) {
1536 pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
1537 mode->name, nsize, n, range_start, range_end);
1538 goto out;
1539 }
1540 }
1541 }
1542
1543 ret = 0;
1544out:
1545 drm_mm_for_each_node_safe(node, next, &mm)
1546 drm_mm_remove_node(node);
1547 drm_mm_takedown(&mm);
1548 kfree(order);
1549err_nodes:
1550 vfree(nodes);
1551err:
1552 return ret;
1553}
1554
Chris Wilson50f00332016-12-22 08:36:09 +00001555#include "drm_selftest.c"
1556
1557static int __init test_drm_mm_init(void)
1558{
1559 int err;
1560
1561 while (!random_seed)
1562 random_seed = get_random_int();
1563
1564 pr_info("Testing DRM range manger (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n",
1565 random_seed, max_iterations, max_prime);
1566 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
1567
1568 return err > 0 ? 0 : err;
1569}
1570
1571static void __exit test_drm_mm_exit(void)
1572{
1573}
1574
1575module_init(test_drm_mm_init);
1576module_exit(test_drm_mm_exit);
1577
1578module_param(random_seed, uint, 0400);
1579module_param(max_iterations, uint, 0400);
1580module_param(max_prime, uint, 0400);
1581
1582MODULE_AUTHOR("Intel Corporation");
1583MODULE_LICENSE("GPL");