blob: feb5985abdc265b4ceed3e74e2596edd6b33466c [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 {}
39};
40
Chris Wilson50f00332016-12-22 08:36:09 +000041static int igt_sanitycheck(void *ignored)
42{
43 pr_info("%s - ok!\n", __func__);
44 return 0;
45}
46
Chris Wilson393b50f2016-12-22 08:36:10 +000047static bool assert_no_holes(const struct drm_mm *mm)
48{
49 struct drm_mm_node *hole;
50 u64 hole_start, hole_end;
51 unsigned long count;
52
53 count = 0;
54 drm_mm_for_each_hole(hole, mm, hole_start, hole_end)
55 count++;
56 if (count) {
57 pr_err("Expected to find no holes (after reserve), found %lu instead\n", count);
58 return false;
59 }
60
61 drm_mm_for_each_node(hole, mm) {
62 if (hole->hole_follows) {
63 pr_err("Hole follows node, expected none!\n");
64 return false;
65 }
66 }
67
68 return true;
69}
70
71static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end)
72{
73 struct drm_mm_node *hole;
74 u64 hole_start, hole_end;
75 unsigned long count;
76 bool ok = true;
77
78 if (end <= start)
79 return true;
80
81 count = 0;
82 drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
83 if (start != hole_start || end != hole_end) {
84 if (ok)
85 pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n",
86 hole_start, hole_end,
87 start, end);
88 ok = false;
89 }
90 count++;
91 }
92 if (count != 1) {
93 pr_err("Expected to find one hole, found %lu instead\n", count);
94 ok = false;
95 }
96
97 return ok;
98}
99
Chris Wilson900537d2016-12-22 08:36:12 +0000100static bool assert_continuous(const struct drm_mm *mm, u64 size)
101{
102 struct drm_mm_node *node, *check, *found;
103 unsigned long n;
104 u64 addr;
105
106 if (!assert_no_holes(mm))
107 return false;
108
109 n = 0;
110 addr = 0;
111 drm_mm_for_each_node(node, mm) {
112 if (node->start != addr) {
113 pr_err("node[%ld] list out of order, expected %llx found %llx\n",
114 n, addr, node->start);
115 return false;
116 }
117
118 if (node->size != size) {
119 pr_err("node[%ld].size incorrect, expected %llx, found %llx\n",
120 n, size, node->size);
121 return false;
122 }
123
124 if (node->hole_follows) {
125 pr_err("node[%ld] is followed by a hole!\n", n);
126 return false;
127 }
128
129 found = NULL;
130 drm_mm_for_each_node_in_range(check, mm, addr, addr + size) {
131 if (node != check) {
132 pr_err("lookup return wrong node, expected start %llx, found %llx\n",
133 node->start, check->start);
134 return false;
135 }
136 found = check;
137 }
138 if (!found) {
139 pr_err("lookup failed for node %llx + %llx\n",
140 addr, size);
141 return false;
142 }
143
144 addr += size;
145 n++;
146 }
147
148 return true;
149}
150
Chris Wilson78866922016-12-22 08:36:13 +0000151static u64 misalignment(struct drm_mm_node *node, u64 alignment)
152{
153 u64 rem;
154
155 if (!alignment)
156 return 0;
157
158 div64_u64_rem(node->start, alignment, &rem);
159 return rem;
160}
161
162static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm,
163 u64 size, u64 alignment, unsigned long color)
164{
165 bool ok = true;
166
167 if (!drm_mm_node_allocated(node) || node->mm != mm) {
168 pr_err("node not allocated\n");
169 ok = false;
170 }
171
172 if (node->size != size) {
173 pr_err("node has wrong size, found %llu, expected %llu\n",
174 node->size, size);
175 ok = false;
176 }
177
178 if (misalignment(node, alignment)) {
179 pr_err("node is misalinged, start %llx rem %llu, expected alignment %llu\n",
180 node->start, misalignment(node, alignment), alignment);
181 ok = false;
182 }
183
184 if (node->color != color) {
185 pr_err("node has wrong color, found %lu, expected %lu\n",
186 node->color, color);
187 ok = false;
188 }
189
190 return ok;
191}
192
Chris Wilson393b50f2016-12-22 08:36:10 +0000193static int igt_init(void *ignored)
194{
195 const unsigned int size = 4096;
196 struct drm_mm mm;
197 struct drm_mm_node tmp;
198 int ret = -EINVAL;
199
200 /* Start with some simple checks on initialising the struct drm_mm */
201 memset(&mm, 0, sizeof(mm));
202 if (drm_mm_initialized(&mm)) {
203 pr_err("zeroed mm claims to be initialized\n");
204 return ret;
205 }
206
207 memset(&mm, 0xff, sizeof(mm));
208 drm_mm_init(&mm, 0, size);
209 if (!drm_mm_initialized(&mm)) {
210 pr_err("mm claims not to be initialized\n");
211 goto out;
212 }
213
214 if (!drm_mm_clean(&mm)) {
215 pr_err("mm not empty on creation\n");
216 goto out;
217 }
218
219 /* After creation, it should all be one massive hole */
220 if (!assert_one_hole(&mm, 0, size)) {
221 ret = -EINVAL;
222 goto out;
223 }
224
225 memset(&tmp, 0, sizeof(tmp));
226 tmp.start = 0;
227 tmp.size = size;
228 ret = drm_mm_reserve_node(&mm, &tmp);
229 if (ret) {
230 pr_err("failed to reserve whole drm_mm\n");
231 goto out;
232 }
233
234 /* After filling the range entirely, there should be no holes */
235 if (!assert_no_holes(&mm)) {
236 ret = -EINVAL;
237 goto out;
238 }
239
240 /* And then after emptying it again, the massive hole should be back */
241 drm_mm_remove_node(&tmp);
242 if (!assert_one_hole(&mm, 0, size)) {
243 ret = -EINVAL;
244 goto out;
245 }
246
247out:
248 if (ret)
249 drm_mm_debug_table(&mm, __func__);
250 drm_mm_takedown(&mm);
251 return ret;
252}
253
Chris Wilson06df8ac2016-12-22 08:36:11 +0000254static int igt_debug(void *ignored)
255{
256 struct drm_mm mm;
257 struct drm_mm_node nodes[2];
258 int ret;
259
260 /* Create a small drm_mm with a couple of nodes and a few holes, and
261 * check that the debug iterator doesn't explode over a trivial drm_mm.
262 */
263
264 drm_mm_init(&mm, 0, 4096);
265
266 memset(nodes, 0, sizeof(nodes));
267 nodes[0].start = 512;
268 nodes[0].size = 1024;
269 ret = drm_mm_reserve_node(&mm, &nodes[0]);
270 if (ret) {
271 pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n",
272 nodes[0].start, nodes[0].size);
273 return ret;
274 }
275
276 nodes[1].size = 1024;
277 nodes[1].start = 4096 - 512 - nodes[1].size;
278 ret = drm_mm_reserve_node(&mm, &nodes[1]);
279 if (ret) {
280 pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n",
281 nodes[1].start, nodes[1].size);
282 return ret;
283 }
284
285 drm_mm_debug_table(&mm, __func__);
286 return 0;
287}
288
Chris Wilson900537d2016-12-22 08:36:12 +0000289static struct drm_mm_node *set_node(struct drm_mm_node *node,
290 u64 start, u64 size)
291{
292 node->start = start;
293 node->size = size;
294 return node;
295}
296
297static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node)
298{
299 int err;
300
301 err = drm_mm_reserve_node(mm, node);
302 if (likely(err == -ENOSPC))
303 return true;
304
305 if (!err) {
306 pr_err("impossible reserve succeeded, node %llu + %llu\n",
307 node->start, node->size);
308 drm_mm_remove_node(node);
309 } else {
310 pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n",
311 err, -ENOSPC, node->start, node->size);
312 }
313 return false;
314}
315
316static bool check_reserve_boundaries(struct drm_mm *mm,
317 unsigned int count,
318 u64 size)
319{
320 const struct boundary {
321 u64 start, size;
322 const char *name;
323 } boundaries[] = {
324#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" }
325 B(0, 0),
326 B(-size, 0),
327 B(size, 0),
328 B(size * count, 0),
329 B(-size, size),
330 B(-size, -size),
331 B(-size, 2*size),
332 B(0, -size),
333 B(size, -size),
334 B(count*size, size),
335 B(count*size, -size),
336 B(count*size, count*size),
337 B(count*size, -count*size),
338 B(count*size, -(count+1)*size),
339 B((count+1)*size, size),
340 B((count+1)*size, -size),
341 B((count+1)*size, -2*size),
342#undef B
343 };
344 struct drm_mm_node tmp = {};
345 int n;
346
347 for (n = 0; n < ARRAY_SIZE(boundaries); n++) {
348 if (!expect_reserve_fail(mm,
349 set_node(&tmp,
350 boundaries[n].start,
351 boundaries[n].size))) {
352 pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n",
353 n, boundaries[n].name, count, size);
354 return false;
355 }
356 }
357
358 return true;
359}
360
361static int __igt_reserve(unsigned int count, u64 size)
362{
363 DRM_RND_STATE(prng, random_seed);
364 struct drm_mm mm;
365 struct drm_mm_node tmp, *nodes, *node, *next;
366 unsigned int *order, n, m, o = 0;
367 int ret, err;
368
369 /* For exercising drm_mm_reserve_node(), we want to check that
370 * reservations outside of the drm_mm range are rejected, and to
371 * overlapping and otherwise already occupied ranges. Afterwards,
372 * the tree and nodes should be intact.
373 */
374
375 DRM_MM_BUG_ON(!count);
376 DRM_MM_BUG_ON(!size);
377
378 ret = -ENOMEM;
379 order = drm_random_order(count, &prng);
380 if (!order)
381 goto err;
382
383 nodes = vzalloc(sizeof(*nodes) * count);
384 if (!nodes)
385 goto err_order;
386
387 ret = -EINVAL;
388 drm_mm_init(&mm, 0, count * size);
389
390 if (!check_reserve_boundaries(&mm, count, size))
391 goto out;
392
393 for (n = 0; n < count; n++) {
394 nodes[n].start = order[n] * size;
395 nodes[n].size = size;
396
397 err = drm_mm_reserve_node(&mm, &nodes[n]);
398 if (err) {
399 pr_err("reserve failed, step %d, start %llu\n",
400 n, nodes[n].start);
401 ret = err;
402 goto out;
403 }
404
405 if (!drm_mm_node_allocated(&nodes[n])) {
406 pr_err("reserved node not allocated! step %d, start %llu\n",
407 n, nodes[n].start);
408 goto out;
409 }
410
411 if (!expect_reserve_fail(&mm, &nodes[n]))
412 goto out;
413 }
414
415 /* After random insertion the nodes should be in order */
416 if (!assert_continuous(&mm, size))
417 goto out;
418
419 /* Repeated use should then fail */
420 drm_random_reorder(order, count, &prng);
421 for (n = 0; n < count; n++) {
422 if (!expect_reserve_fail(&mm,
423 set_node(&tmp, order[n] * size, 1)))
424 goto out;
425
426 /* Remove and reinsert should work */
427 drm_mm_remove_node(&nodes[order[n]]);
428 err = drm_mm_reserve_node(&mm, &nodes[order[n]]);
429 if (err) {
430 pr_err("reserve failed, step %d, start %llu\n",
431 n, nodes[n].start);
432 ret = err;
433 goto out;
434 }
435 }
436
437 if (!assert_continuous(&mm, size))
438 goto out;
439
440 /* Overlapping use should then fail */
441 for (n = 0; n < count; n++) {
442 if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count)))
443 goto out;
444 }
445 for (n = 0; n < count; n++) {
446 if (!expect_reserve_fail(&mm,
447 set_node(&tmp,
448 size * n,
449 size * (count - n))))
450 goto out;
451 }
452
453 /* Remove several, reinsert, check full */
454 for_each_prime_number(n, min(max_prime, count)) {
455 for (m = 0; m < n; m++) {
456 node = &nodes[order[(o + m) % count]];
457 drm_mm_remove_node(node);
458 }
459
460 for (m = 0; m < n; m++) {
461 node = &nodes[order[(o + m) % count]];
462 err = drm_mm_reserve_node(&mm, node);
463 if (err) {
464 pr_err("reserve failed, step %d/%d, start %llu\n",
465 m, n, node->start);
466 ret = err;
467 goto out;
468 }
469 }
470
471 o += n;
472
473 if (!assert_continuous(&mm, size))
474 goto out;
475 }
476
477 ret = 0;
478out:
479 drm_mm_for_each_node_safe(node, next, &mm)
480 drm_mm_remove_node(node);
481 drm_mm_takedown(&mm);
482 vfree(nodes);
483err_order:
484 kfree(order);
485err:
486 return ret;
487}
488
489static int igt_reserve(void *ignored)
490{
491 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
492 int n, ret;
493
494 for_each_prime_number_from(n, 1, 54) {
495 u64 size = BIT_ULL(n);
496
497 ret = __igt_reserve(count, size - 1);
498 if (ret)
499 return ret;
500
501 ret = __igt_reserve(count, size);
502 if (ret)
503 return ret;
504
505 ret = __igt_reserve(count, size + 1);
506 if (ret)
507 return ret;
508 }
509
510 return 0;
511}
512
Chris Wilson78866922016-12-22 08:36:13 +0000513static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
514 u64 size, u64 alignment, unsigned long color,
515 const struct insert_mode *mode)
516{
517 int err;
518
519 err = drm_mm_insert_node_generic(mm, node,
520 size, alignment, color,
521 mode->search_flags,
522 mode->create_flags);
523 if (err) {
524 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n",
525 size, alignment, color, mode->name, err);
526 return false;
527 }
528
529 if (!assert_node(node, mm, size, alignment, color)) {
530 drm_mm_remove_node(node);
531 return false;
532 }
533
534 return true;
535}
536
537static bool expect_insert_fail(struct drm_mm *mm, u64 size)
538{
539 struct drm_mm_node tmp = {};
540 int err;
541
542 err = drm_mm_insert_node(mm, &tmp, size, 0, DRM_MM_SEARCH_DEFAULT);
543 if (likely(err == -ENOSPC))
544 return true;
545
546 if (!err) {
547 pr_err("impossible insert succeeded, node %llu + %llu\n",
548 tmp.start, tmp.size);
549 drm_mm_remove_node(&tmp);
550 } else {
551 pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n",
552 err, -ENOSPC, size);
553 }
554 return false;
555}
556
557static int __igt_insert(unsigned int count, u64 size)
558{
559 DRM_RND_STATE(prng, random_seed);
560 const struct insert_mode *mode;
561 struct drm_mm mm;
562 struct drm_mm_node *nodes, *node, *next;
563 unsigned int *order, n, m, o = 0;
564 int ret;
565
566 /* Fill a range with lots of nodes, check it doesn't fail too early */
567
568 DRM_MM_BUG_ON(!count);
569 DRM_MM_BUG_ON(!size);
570
571 ret = -ENOMEM;
572 nodes = vzalloc(count * sizeof(*nodes));
573 if (!nodes)
574 goto err;
575
576 order = drm_random_order(count, &prng);
577 if (!order)
578 goto err_nodes;
579
580 ret = -EINVAL;
581 drm_mm_init(&mm, 0, count * size);
582
583 for (mode = insert_modes; mode->name; mode++) {
584 for (n = 0; n < count; n++) {
585 if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) {
586 pr_err("%s insert failed, size %llu step %d\n",
587 mode->name, size, n);
588 goto out;
589 }
590 }
591
592 /* After random insertion the nodes should be in order */
593 if (!assert_continuous(&mm, size))
594 goto out;
595
596 /* Repeated use should then fail */
597 if (!expect_insert_fail(&mm, size))
598 goto out;
599
600 /* Remove one and reinsert, as the only hole it should refill itself */
601 for (n = 0; n < count; n++) {
602 u64 addr = nodes[n].start;
603
604 drm_mm_remove_node(&nodes[n]);
605 if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) {
606 pr_err("%s reinsert failed, size %llu step %d\n",
607 mode->name, size, n);
608 goto out;
609 }
610
611 if (nodes[n].start != addr) {
612 pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
613 mode->name, n, addr, nodes[n].start);
614 goto out;
615 }
616
617 if (!assert_continuous(&mm, size))
618 goto out;
619 }
620
621 /* Remove several, reinsert, check full */
622 for_each_prime_number(n, min(max_prime, count)) {
623 for (m = 0; m < n; m++) {
624 node = &nodes[order[(o + m) % count]];
625 drm_mm_remove_node(node);
626 }
627
628 for (m = 0; m < n; m++) {
629 node = &nodes[order[(o + m) % count]];
630 if (!expect_insert(&mm, node, size, 0, n, mode)) {
631 pr_err("%s multiple reinsert failed, size %llu step %d\n",
632 mode->name, size, n);
633 goto out;
634 }
635 }
636
637 o += n;
638
639 if (!assert_continuous(&mm, size))
640 goto out;
641
642 if (!expect_insert_fail(&mm, size))
643 goto out;
644 }
645
646 drm_mm_for_each_node_safe(node, next, &mm)
647 drm_mm_remove_node(node);
648 DRM_MM_BUG_ON(!drm_mm_clean(&mm));
649 }
650
651 ret = 0;
652out:
653 drm_mm_for_each_node_safe(node, next, &mm)
654 drm_mm_remove_node(node);
655 drm_mm_takedown(&mm);
656 kfree(order);
657err_nodes:
658 vfree(nodes);
659err:
660 return ret;
661}
662
663static int igt_insert(void *ignored)
664{
665 const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
666 unsigned int n;
667 int ret;
668
669 for_each_prime_number_from(n, 1, 54) {
670 u64 size = BIT_ULL(n);
671
672 ret = __igt_insert(count, size - 1);
673 if (ret)
674 return ret;
675
676 ret = __igt_insert(count, size);
677 if (ret)
678 return ret;
679
680 ret = __igt_insert(count, size + 1);
681 if (ret)
682 return ret;
683 }
684
685 return 0;
686}
687
Chris Wilson50f00332016-12-22 08:36:09 +0000688#include "drm_selftest.c"
689
690static int __init test_drm_mm_init(void)
691{
692 int err;
693
694 while (!random_seed)
695 random_seed = get_random_int();
696
697 pr_info("Testing DRM range manger (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n",
698 random_seed, max_iterations, max_prime);
699 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
700
701 return err > 0 ? 0 : err;
702}
703
704static void __exit test_drm_mm_exit(void)
705{
706}
707
708module_init(test_drm_mm_init);
709module_exit(test_drm_mm_exit);
710
711module_param(random_seed, uint, 0400);
712module_param(max_iterations, uint, 0400);
713module_param(max_prime, uint, 0400);
714
715MODULE_AUTHOR("Intel Corporation");
716MODULE_LICENSE("GPL");