Simple first test to just exercise initialisation of struct drm_mm.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 0a2e98a33ba0..8a9166f4626f 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,4 +5,5 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(init, igt_init) selftest(sanitycheck, igt_sanitycheck) /* keep last */ diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 049f36b38868..d89615987303 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -20,6 +20,47 @@ static int igt_sanitycheck(void *ignored) return 0; }
+static int igt_init(void *ignored) +{ + struct drm_mm mm; + struct drm_mm_node *hole; + struct drm_mm_node tmp; + u64 start, end; + int ret = -EINVAL; + + memset(&mm, 0xff, sizeof(mm)); + drm_mm_init(&mm, 0, 4096); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + drm_mm_for_each_hole(hole, &mm, start, end) { + if (start != 0 || end != 4096) { + pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", + start, end, + 0ull, 4096ull); + goto out; + } + } + + memset(&tmp, 0, sizeof(tmp)); + tmp.start = 0; + tmp.size = 4096; + ret = drm_mm_reserve_node(&mm, &tmp); + if (ret) { + pr_err("failed to reserve whole drm_mm\n"); + goto out; + } + drm_mm_remove_node(&tmp); + +out: + if (ret) + drm_mm_debug_table(&mm, __func__); + drm_mm_takedown(&mm); + return ret; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
Exercise drm_mm_reserve_node(), check that we can't reserve an already occupied range and that the lists are correct after reserving/removing.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 143 +++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 8a9166f4626f..204200227b3c 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,5 +5,6 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(reserve, igt_reserve) selftest(init, igt_init) selftest(sanitycheck, igt_sanitycheck) /* keep last */ diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index d89615987303..d7ab054678a8 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -61,6 +61,149 @@ static int igt_init(void *ignored) return ret; }
+static int *random_order(int count) +{ + int *order; + int n; + + order = kmalloc_array(count, sizeof(*order), GFP_TEMPORARY); + if (!order) + return order; + + for (n = 0; n < count; n++) + order[n] = n; + + for (n = count-1; n > 1; n--) { + int r = get_random_int() % (n + 1); + if (r != n) { + int tmp = order[n]; + order[n] = order[r]; + order[r] = tmp; + } + } + + return order; +} + +static int __igt_reserve(int count, u64 size) +{ + struct drm_mm mm; + struct drm_mm_node *node, *next; + int *order, n; + int ret; + + /* Fill a range with lots of nodes, check it doesn't fail too early */ + + ret = -ENOMEM; + order = random_order(count); + if (!order) + goto err; + + ret = -EINVAL; + drm_mm_init(&mm, 0, count * size); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + for (n = 0; n < count; n++) { + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + node->start = order[n] * size; + node->size = size; + + err = drm_mm_reserve_node(&mm, node); + if (err) { + pr_err("reserve failed, step %d, start %llu\n", + n, node->start); + ret = err; + goto out; + } + } + + /* Repeated use should then fail */ + for (n = 0; n < count; n++) { + struct drm_mm_node tmp = { + .start = order[n] * size, + .size = 1 + }; + + if (!drm_mm_reserve_node(&mm, &tmp)) { + drm_mm_remove_node(&tmp); + pr_err("impossible reserve succeeded, step %d, start %llu\n", + n, tmp.start); + goto out; + } + } + + /* Overlapping use should then fail */ + for (n = 0; n < count; n++) { + struct drm_mm_node tmp = { + .start = 0, + .size = size * count, + }; + + if (!drm_mm_reserve_node(&mm, &tmp)) { + drm_mm_remove_node(&tmp); + pr_err("impossible reserve succeeded, step %d, start %llu\n", + n, tmp.start); + goto out; + } + } + for (n = 0; n < count; n++) { + struct drm_mm_node tmp = { + .start = size * n, + .size = size * (count - n), + }; + + if (!drm_mm_reserve_node(&mm, &tmp)) { + drm_mm_remove_node(&tmp); + pr_err("impossible reserve succeeded, step %d, start %llu\n", + n, tmp.start); + goto out; + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, + &mm.head_node.node_list, node_list) { + drm_mm_remove_node(node); + kfree(node); + } + drm_mm_takedown(&mm); + kfree(order); +err: + return ret; +} + +static int igt_reserve(void *ignored) +{ + int n, ret; + + for (n = 1; n < 50; n++) { + ret = __igt_reserve(8192, (1ull << n) - 1); + if (ret) + return ret; + + ret = __igt_reserve(8192, 1ull << n); + if (ret) + return ret; + + ret = __igt_reserve(8192, (1ull << n) + 1); + if (ret) + return ret; + } + + return 0; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
On pe, 2016-12-09 at 13:08 +0000, Chris Wilson wrote:
Exercise drm_mm_reserve_node(), check that we can't reserve an already occupied range and that the lists are correct after reserving/removing.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk
drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 143 +++++++++++++++++++++++++++++++++++++
Once there is more thorough coverage, I think we should have drm/selftest/drm_mm.{h,c}
+static int __igt_reserve(int count, u64 size) +{
- struct drm_mm mm;
- struct drm_mm_node *node, *next;
- int *order, n;
- int ret;
- /* Fill a range with lots of nodes, check it doesn't fail too early */
- ret = -ENOMEM;
- order = random_order(count);
- if (!order)
goto err;
- ret = -EINVAL;
- drm_mm_init(&mm, 0, count * size);
- if (!drm_mm_clean(&mm)) {
pr_err("mm not empty on creation\n");
goto out;
- }
This code gets covered already done in more basic test, I think we should avoid duplication from the start as we now have trouble with runtime of tests.
+static int igt_reserve(void *ignored) +{
- int n, ret;
- for (n = 1; n < 50; n++) {
The right amount of loops might be something to discuss.
ret = __igt_reserve(8192, (1ull << n) - 1);
BIT_ULL(n) - 1?
Regards, Joonas
On Fri, Dec 09, 2016 at 04:31:50PM +0200, Joonas Lahtinen wrote:
On pe, 2016-12-09 at 13:08 +0000, Chris Wilson wrote:
+static int igt_reserve(void *ignored) +{
- int n, ret;
- for (n = 1; n < 50; n++) {
The right amount of loops might be something to discuss.
The looping here is for all power-of-two (+-1 to catch the usual interesting boundary conditions) upto total size == 1<<63 (a little room to spare). So these I regard as exercising the likely errors, with the looping inside being subject to discussion. Certainly also probably nice to run through with primes as well (though we have a few mersenne primes in this set, so that's probably overkill).
On top of these we also want to think how much error handling we want inside drm_mm_node_reserve() and add the broken usage.
ret = __igt_reserve(8192, (1ull << n) - 1);
BIT_ULL(n) - 1?
Considered it, but felt calling it BIT was misleading / distraction. -Chris
Exercise drm_mm_insert_node(), check that we can't overfill a range and that the lists are correct after reserving/removing.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 271 +++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 204200227b3c..97690bf5add3 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(insert, igt_insert) selftest(reserve, igt_reserve) selftest(init, igt_init) selftest(sanitycheck, igt_sanitycheck) /* keep last */ diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index d7ab054678a8..679f7e703218 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -14,6 +14,78 @@ #define TESTS "drm_mm_selftests.h" #include "drm_selftest.h"
+static unsigned long *primes; +static unsigned long prime_last, prime_sz; + +static unsigned long slow_next_prime_number(unsigned long x) +{ + for (;;) { + unsigned long y = int_sqrt(++x) + 1; + while (y > 1) { + if ((x % y) == 0) + break; + y--; + } + if (y == 1) + return x; + } +} + +static unsigned long mark_multiples(unsigned long x, + unsigned long *p, + unsigned long start, + unsigned long end) +{ + unsigned long m; + + m = 2*x; + if (m < start) + m = (start / x + 1) * x; + + while (m < end) { + __clear_bit(m, p); + m += x; + } + + return x; +} + +static unsigned long next_prime_number(unsigned long x) +{ + if (x == 1) + return 2; + + if (x >= prime_last) { + unsigned long sz, y; + unsigned long *nprimes; + + sz = x*x; + if (sz < x) + return slow_next_prime_number(x); + + sz = round_up(sz, BITS_PER_LONG); + nprimes = krealloc(primes, sz / sizeof(long), GFP_KERNEL); + if (!nprimes) + return slow_next_prime_number(x); + + /* Where memory permits, track the primes using the + * Sieve of Eratosthenes. + */ + memset(nprimes + prime_sz / BITS_PER_LONG, + 0xff, (sz - prime_sz) / sizeof(long)); + for (y = 2UL; y < sz; y = find_next_bit(nprimes, sz, y + 1)) + prime_last = mark_multiples(y, nprimes, prime_sz, sz); + + primes = nprimes; + prime_sz = sz; + } + + return find_next_bit(primes, prime_last, x + 1); +} + +#define for_each_prime(prime, max) \ + for (prime = 1; prime < (max); prime = next_prime_number(prime)) + static int igt_sanitycheck(void *ignored) { pr_info("%s - ok!\n", __func__); @@ -204,6 +276,204 @@ static int igt_reserve(void *ignored) return 0; }
+static int __igt_insert(int count, u64 size) +{ + struct drm_mm mm; + struct drm_mm_node *nodes, *node, *next; + int *order, n, o = 0; + int ret; + + /* Fill a range with lots of nodes, check it doesn't fail too early */ + + ret = -ENOMEM; + nodes = vzalloc(count * sizeof(*nodes)); + if (!nodes) + goto err; + + order = random_order(count); + if (!order) + goto err_nodes; + + ret = -EINVAL; + drm_mm_init(&mm, 0, count * size); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + for (n = 0; n < count; n++) { + int err; + + err = drm_mm_insert_node(&mm, &nodes[n], size, 0, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("insert failed, step %d, start %llu\n", + n, nodes[n].start); + ret = err; + goto out; + } + } + + /* Repeated use should then fail */ + if (1) { + struct drm_mm_node tmp; + + memset(&tmp, 0, sizeof(tmp)); + if (!drm_mm_insert_node(&mm, &tmp, size, 0, + DRM_MM_SEARCH_DEFAULT)) { + drm_mm_remove_node(&tmp); + pr_err("impossible insert succeeded, step %d, start %llu\n", + n, tmp.start); + goto out; + } + } + + n = 0; + drm_mm_for_each_node(node, &mm) { + if (node->start != n * size) { + pr_err("node %d out of order, expected start %llx, found %llx\n", + n, n * size, node->start); + goto out; + } + + if (node->size != size) { + pr_err("node %d has wrong size, expected size %llx, found %llx\n", + n, size, node->size); + goto out; + } + + if (node->hole_follows) { + pr_err("node %d is followed by a hole!\n", n); + goto out; + } + + n++; + } + + for (n = 0; n < count; n++) { + drm_mm_for_each_node_in_range(node, &mm, n * size, (n + 1) * size) { + if (node->start != n * size) { + pr_err("lookup node %d out of order, expected start %llx, found %llx\n", + n, n * size, node->start); + goto out; + } + } + } + + /* Remove one and reinsert, as the only hole it should refill itself */ + for (n = 0; n < count; n++) { + int err; + + drm_mm_remove_node(&nodes[n]); + err = drm_mm_insert_node(&mm, &nodes[n], size, 0, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("reinsert failed, step %d\n", n); + ret = err; + goto out; + } + + if (nodes[n].start != n * size) { + pr_err("reinsert node moved, step %d, expected %llx, found %llx\n", + n, n * size, nodes[n].start); + goto out; + } + } + + /* Remove several, reinsert, check full */ + for_each_prime(n, min(128, count)) { + int m; + + for (m = 0; m < n; m++) { + node = &nodes[order[(o + m) % count]]; + drm_mm_remove_node(node); + } + + for (m = 0; m < n; m++) { + int err; + + node = &nodes[order[(o + m) % count]]; + err = drm_mm_insert_node(&mm, node, size, 0, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("insert failed, step %d, start %llu\n", + n, node->start); + ret = err; + goto out; + } + } + + o += n; + + if (1) { + struct drm_mm_node tmp; + + memset(&tmp, 0, sizeof(tmp)); + if (!drm_mm_insert_node(&mm, &tmp, size, 0, + DRM_MM_SEARCH_DEFAULT)) { + drm_mm_remove_node(&tmp); + pr_err("impossible insert succeeded, start %llu\n", + tmp.start); + goto out; + } + } + + m = 0; + drm_mm_for_each_node(node, &mm) { + if (node->start != m * size) { + pr_err("node %d out of order, expected start %llx, found %llx\n", + m, m * size, node->start); + goto out; + } + + if (node->size != size) { + pr_err("node %d has wrong size, expected size %llx, found %llx\n", + m, size, node->size); + goto out; + } + + if (node->hole_follows) { + pr_err("node %d is followed by a hole!\n", m); + goto out; + } + + m++; + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, &mm.head_node.node_list, node_list) + drm_mm_remove_node(node); + drm_mm_takedown(&mm); + kfree(order); +err_nodes: + vfree(nodes); +err: + return ret; +} + +static int igt_insert(void *ignored) +{ + int n, ret; + + for (n = 1; n < 50; n++) { + ret = __igt_insert(8192, (1ull << n) - 1); + if (ret) + return ret; + + ret = __igt_insert(8192, 1ull << n); + if (ret) + return ret; + + ret = __igt_insert(8192, (1ull << n) + 1); + if (ret) + return ret; + } + + return 0; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void) @@ -218,6 +488,7 @@ static int __init test_drm_mm_init(void)
static void __exit test_drm_mm_exit(void) { + kfree(primes); }
module_init(test_drm_mm_init);
Exercise drm_mm_insert_node_in_range(), check that we only allocate from the specified range.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 188 +++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 97690bf5add3..4070123daffc 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(insert_range, igt_insert_range) selftest(insert, igt_insert) selftest(reserve, igt_reserve) selftest(init, igt_init) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 679f7e703218..494a470e08f3 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -474,6 +474,194 @@ static int igt_insert(void *ignored) return 0; }
+static int __igt_insert_range(int count, u64 size, u64 start, u64 end) +{ + struct drm_mm mm; + struct drm_mm_node *nodes, *node, *next; + int n, start_n, end_n; + int ret, err; + + /* Fill a range with lots of nodes, check it doesn't fail too early */ + pr_debug("%s: count=%d, size=%llx, start=%llx, end=%llx\n", + __func__, count, size, start, end); + + ret = -ENOMEM; + nodes = vzalloc(count * sizeof(*nodes)); + if (!nodes) + goto err; + + ret = -EINVAL; + drm_mm_init(&mm, 0, count * size); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + for (n = 0; n < count; n++) { + err = drm_mm_insert_node(&mm, &nodes[n], size, 0, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("insert failed, step %d, start %llu\n", + n, nodes[n].start); + ret = err; + goto out; + } + } + + /* Repeated use should then fail */ + if (1) { + struct drm_mm_node tmp; + + memset(&tmp, 0, sizeof(tmp)); + if (!drm_mm_insert_node_in_range(&mm, &tmp, + size, 0, + start, end, + DRM_MM_SEARCH_DEFAULT)) { + drm_mm_remove_node(&tmp); + pr_err("impossible insert succeeded, step %d, start %llu\n", + n, tmp.start); + goto out; + } + } + + n = div64_u64(start, size); + drm_mm_for_each_node_in_range(node, &mm, start, end) { + if (node->start > end) { + pr_err("node %d out of rangei [%d, %d]\n", + n, + (int)div64_u64(start, size), + (int)div64_u64(start + size - 1, size)); + goto out; + } + + if (node->start != n * size) { + pr_err("node %d out of order, expected start %llx, found %llx\n", + n, n * size, node->start); + goto out; + } + + if (node->size != size) { + pr_err("node %d has wrong size, expected size %llx, found %llx\n", + n, size, node->size); + goto out; + } + + if (node->hole_follows) { + pr_err("node %d is followed by a hole!\n", n); + goto out; + } + + n++; + } + + /* Remove one and reinsert, as the only hole it should refill itself */ + start_n = div64_u64(start + size - 1, size); + end_n = div64_u64(end - size, size); + for (n = start_n; n <= end_n; n++) { + drm_mm_remove_node(&nodes[n]); + err = drm_mm_insert_node_in_range(&mm, &nodes[n], size, 0, + start, end, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("reinsert failed, step %d\n", n); + ret = err; + goto out; + } + + if (nodes[n].start != n * size) { + pr_err("reinsert node moved, step %d, expected %llx, found %llx\n", + n, n * size, nodes[n].start); + goto out; + } + } + + /* Remove the entire block, reinsert (order will then be undefined) */ + for (n = start_n; n <= end_n; n++) + drm_mm_remove_node(&nodes[n]); + + for (n = start_n; n <= end_n; n++) { + err = drm_mm_insert_node_in_range(&mm, &nodes[n], size, 0, + start, end, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("reinsert failed, step %d\n", n); + ret = err; + goto out; + } + } + + n = div64_u64(start, size); + drm_mm_for_each_node_in_range(node, &mm, start, end) { + if (node->start > end) { + pr_err("node %d out of rangei [%d, %d]\n", + n, + (int)div64_u64(start, size), + (int)div64_u64(start + size - 1, size)); + goto out; + } + + if (node->start != n * size) { + pr_err("node %d out of order, expected start %llx, found %llx\n", + n, n * size, node->start); + goto out; + } + + if (node->size != size) { + pr_err("node %d has wrong size, expected size %llx, found %llx\n", + n, size, node->size); + goto out; + } + + if (node->hole_follows) { + pr_err("node %d is followed by a hole!\n", n); + goto out; + } + + n++; + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, &mm.head_node.node_list, node_list) + drm_mm_remove_node(node); + drm_mm_takedown(&mm); + vfree(nodes); +err: + return ret; +} + +static int igt_insert_range(void *ignored) +{ + const int max = 4096 * 8192; + int ret; + + ret = __igt_insert_range(8192, 4096, 0, max); + if (ret) + return ret; + + ret = __igt_insert_range(8192, 4096, 1, max); + if (ret) + return ret; + + ret = __igt_insert_range(8192, 4096, 0, max - 1); + if (ret) + return ret; + + ret = __igt_insert_range(8192, 4096, 0, max/2); + if (ret) + return ret; + + ret = __igt_insert_range(8192, 4096, max/2, max); + if (ret) + return ret; + + ret = __igt_insert_range(8192, 4096, max/4+1, 3*max/4-1); + if (ret) + return ret; + + return 0; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
Check that we can request alignment to any power-of-two or prime using a plain drm_mm_node_insert().
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 3 + drivers/gpu/drm/test-drm_mm.c | 113 +++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 4070123daffc..591d34aa233a 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,9 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(align64, igt_align64) +selftest(align32, igt_align32) +selftest(align, igt_align) selftest(insert_range, igt_insert_range) selftest(insert, igt_insert) selftest(reserve, igt_reserve) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 494a470e08f3..8cdcde580da3 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -662,6 +662,119 @@ static int igt_insert_range(void *ignored) return 0; }
+static int igt_align(void *ignored) +{ + struct drm_mm mm; + struct drm_mm_node *node, *next; + int ret = -EINVAL; + int n; + + drm_mm_init(&mm, 1, -2); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + for_each_prime(n, 8192) { + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + err = drm_mm_insert_node_generic(&mm, node, + next_prime_number(n),/* size */ + n, /* alignment */ + 0, + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); + if (err) { + pr_err("insert failed with alignment=%d", n); + ret = err; + goto out; + } + + if (node->start % n) { + pr_err("node inserted into wrong location %llx, expected alignment to %d\n", + node->start, n); + goto out; + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, + &mm.head_node.node_list, node_list) { + drm_mm_remove_node(node); + kfree(node); + } + drm_mm_takedown(&mm); + return ret; +} + +static int igt_align_pot(int max) +{ + struct drm_mm mm; + struct drm_mm_node *node, *next; + int bit; + int ret = -EINVAL; + + drm_mm_init(&mm, 1, -2); + if (!drm_mm_clean(&mm)) { + pr_err("mm not empty on creation\n"); + goto out; + } + + for (bit = max - 1; bit; bit--) { + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + err = drm_mm_insert_node_generic(&mm, node, 1, + BIT_ULL(bit), bit, + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); + if (err) { + pr_err("insert failed with alignment=%llx [%d]", + BIT_ULL(bit), bit); + ret = err; + goto out; + } + + if (node->start & (BIT_ULL(bit) - 1)) { + pr_err("node inserted into wrong location %llx, expected alignment to %llx [%d]\n", + node->start, BIT_ULL(bit), bit); + goto out; + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, + &mm.head_node.node_list, node_list) { + drm_mm_remove_node(node); + kfree(node); + } + drm_mm_takedown(&mm); + return ret; +} + +static int igt_align32(void *ignored) +{ + return igt_align_pot(32); +} + +static int igt_align64(void *ignored) +{ + return igt_align_pot(64); +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
On pe, 2016-12-09 at 13:08 +0000, Chris Wilson wrote:
Check that we can request alignment to any power-of-two or prime using a plain drm_mm_node_insert().
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk
<SNIP>
+static int igt_align(void *ignored) +{
- struct drm_mm mm;
- struct drm_mm_node *node, *next;
- int ret = -EINVAL;
- int n;
- drm_mm_init(&mm, 1, -2);
U64_MAX - 1?
- if (!drm_mm_clean(&mm)) {
pr_err("mm not empty on creation\n");
goto out;
- }
Can be dropped.
- for_each_prime(n, 8192) {
This is one more spot, how about DRM_SELFTEST_MAX_PRIME or so?
int err;
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
ret = -ENOMEM;
goto out;
}
err = drm_mm_insert_node_generic(&mm, node,
next_prime_number(n),/* size */
n, /* alignment */
<rant>If there just was a way of naming variables so this comments was not needed.</rant> Maybe the variable could be "align".
+static int igt_align_pot(int max) +{
- struct drm_mm mm;
- struct drm_mm_node *node, *next;
- int bit;
- int ret = -EINVAL;
- drm_mm_init(&mm, 1, -2);
- if (!drm_mm_clean(&mm)) {
pr_err("mm not empty on creation\n");
goto out;
- }
- for (bit = max - 1; bit; bit--) {
int err;
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
ret = -ENOMEM;
goto out;
}
err = drm_mm_insert_node_generic(&mm, node, 1,
BIT_ULL(bit), bit,
The color is not used, so just set it to 0.
Reviewed-by: Joonas Lahtinen joonas.lahtinen@linux.intel.com
Regards, Joonas
Check that we add arbitrary blocks to the eviction scanner in order to find the first minimal hole that matches our request.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 167 +++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 591d34aa233a..a3ee623b5f59 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(evict, igt_evict) selftest(align64, igt_align64) selftest(align32, igt_align32) selftest(align, igt_align) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 8cdcde580da3..ab9ddfba5cf5 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -775,6 +775,173 @@ static int igt_align64(void *ignored) return igt_align_pot(64); }
+static int igt_evict(void *ignored) +{ + const int size = 8192; + struct drm_mm mm; + struct evict_node { + struct drm_mm_node node; + struct list_head link; + } *nodes; + struct drm_mm_node *node, *next; + int *order, n, m; + int ret; + + ret = -ENOMEM; + nodes = vzalloc(size * sizeof(*nodes)); + if (!nodes) + goto err; + + order = random_order(size); + if (!order) + goto err_nodes; + + ret = -EINVAL; + drm_mm_init(&mm, 0, size); + for (n = 0; n < size; n++) { + int err; + + err = drm_mm_insert_node(&mm, &nodes[n].node, 1, 0, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("insert failed, step %d\n", n); + ret = err; + goto out; + } + } + + for (n = 1; n < size; n <<= 1) { + const int nsize = size / 2; + LIST_HEAD(evict_list); + struct evict_node *e, *en; + struct drm_mm_node tmp; + bool found = false; + int err; + + drm_mm_init_scan(&mm, nsize, n, 0); + for (m = 0; m < size; m++) { + e = &nodes[order[m]]; + list_add(&e->link, &evict_list); + if (drm_mm_scan_add_block(&e->node)) { + found = true; + break; + } + } + if (!found) { + pr_err("Failed to fail eviction: size=%d, align=%d\n", + nsize, n); + goto out; + } + + list_for_each_entry_safe(e, en, &evict_list, link) { + if (!drm_mm_scan_remove_block(&e->node)) + list_del(&e->link); + } + + list_for_each_entry(e, &evict_list, link) + drm_mm_remove_node(&e->node); + + memset(&tmp, 0, sizeof(tmp)); + err = drm_mm_insert_node(&mm, &tmp, nsize, n, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", + nsize, n); + goto out; + } + + if (tmp.start % n || tmp.size != nsize || tmp.hole_follows) { + pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d, start=%llx, hole-follows?=%d\n", + tmp.size, nsize, n, tmp.start, tmp.hole_follows); + + drm_mm_remove_node(&tmp); + goto out; + } + + drm_mm_remove_node(&tmp); + list_for_each_entry(e, &evict_list, link) { + err = drm_mm_reserve_node(&mm, &e->node); + if (err) { + pr_err("Failed to reinsert node after eviction: start=%llx\n", + e->node.start); + ret = err; + goto out; + } + } + } + + for_each_prime(n, size) { + LIST_HEAD(evict_list); + struct evict_node *e, *en; + struct drm_mm_node tmp; + int nsize = (size - n + 1) / 2; + bool found = false; + int err; + + drm_mm_init_scan(&mm, nsize, n, 0); + for (m = 0; m < size; m++) { + e = &nodes[order[m]]; + list_add(&e->link, &evict_list); + if (drm_mm_scan_add_block(&e->node)) { + found = true; + break; + } + } + if (!found) { + pr_err("Failed to fail eviction: size=%d, align=%d\n", + nsize, n); + goto out; + } + + list_for_each_entry_safe(e, en, &evict_list, link) { + if (!drm_mm_scan_remove_block(&e->node)) + list_del(&e->link); + } + + list_for_each_entry(e, &evict_list, link) + drm_mm_remove_node(&e->node); + + memset(&tmp, 0, sizeof(tmp)); + err = drm_mm_insert_node(&mm, &tmp, nsize, n, + DRM_MM_SEARCH_DEFAULT); + if (err) { + pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", + nsize, n); + goto out; + } + + if (tmp.start % n || tmp.size != nsize || tmp.hole_follows) { + pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d, start=%llx, hole-follows?=%d\n", + tmp.size, nsize, n, tmp.start, tmp.hole_follows); + + drm_mm_remove_node(&tmp); + goto out; + } + + drm_mm_remove_node(&tmp); + list_for_each_entry(e, &evict_list, link) { + err = drm_mm_reserve_node(&mm, &e->node); + if (err) { + pr_err("Failed to reinsert node after eviction: start=%llx\n", + e->node.start); + ret = err; + goto out; + } + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, &mm.head_node.node_list, node_list) + drm_mm_remove_node(node); + drm_mm_takedown(&mm); + kfree(order); +err_nodes: + vfree(nodes); +err: + return ret; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
Check that if we request top-down allocation from drm_mm_insert_node() we receive the next available hole from the top.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 96 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index a3ee623b5f59..d435234e0e86 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(topdown, igt_topdown) selftest(evict, igt_evict) selftest(align64, igt_align64) selftest(align32, igt_align32) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index ab9ddfba5cf5..270d0732f1ab 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -942,6 +942,102 @@ static int igt_evict(void *ignored) return ret; }
+static int igt_topdown(void *ignored) +{ + const int size = 8192; + unsigned long *bitmap; + struct drm_mm mm; + struct drm_mm_node *nodes, *node, *next; + int *order, n, m, o = 0; + int ret; + + ret = -ENOMEM; + nodes = vzalloc(size * sizeof(*nodes)); + if (!nodes) + goto err; + + bitmap = kzalloc(size / BITS_PER_LONG * sizeof(unsigned long), + GFP_TEMPORARY); + if (!bitmap) + goto err_nodes; + + order = random_order(size); + if (!order) + goto err_bitmap; + + ret = -EINVAL; + drm_mm_init(&mm, 0, size); + for (n = 0; n < size; n++) { + int err; + + err = drm_mm_insert_node_generic(&mm, &nodes[n], 1, 0, 0, + DRM_MM_SEARCH_BELOW, + DRM_MM_CREATE_TOP); + if (err) { + pr_err("insert failed, step %d\n", n); + ret = err; + goto out; + } + + if (nodes[n].hole_follows) { + pr_err("hole after topdown insert %d, start=%llx\n", + n, nodes[n].start); + goto out; + } + } + + for_each_prime(n, size) { + for (m = 0; m < n; m++) { + node = &nodes[order[(o + m) % size]]; + drm_mm_remove_node(node); + __set_bit(node->start, bitmap); + } + + for (m = 0; m < n; m++) { + int err, last; + + node = &nodes[order[(o + m) % size]]; + err = drm_mm_insert_node_generic(&mm, node, 1, 0, 0, + DRM_MM_SEARCH_BELOW, + DRM_MM_CREATE_TOP); + if (err) { + pr_err("insert failed, step %d/%d\n", m, n); + ret = err; + goto out; + } + + if (node->hole_follows) { + pr_err("hole after topdown insert %d/%d, start=%llx\n", + m, n, node->start); + goto out; + } + + last = find_last_bit(bitmap, size); + if (node->start != last) { + pr_err("node %d/%d not inserted into upmost hole, expected %d, found %lld\n", + m, n, last, node->start); + goto out; + } + __clear_bit(last, bitmap); + } + + o += n; + } + + ret = 0; +out: + list_for_each_entry_safe(node, next, &mm.head_node.node_list, node_list) + drm_mm_remove_node(node); + drm_mm_takedown(&mm); + kfree(order); +err_bitmap: + kfree(bitmap); +err_nodes: + vfree(nodes); +err: + return ret; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
Check that if we request top-down allocation with a particular alignment from drm_mm_insert_node() that the start of the node matches our request.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 92 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index d435234e0e86..6bbdbb929714 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(topdown_align, igt_topdown_align) selftest(topdown, igt_topdown) selftest(evict, igt_evict) selftest(align64, igt_align64) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 270d0732f1ab..7699e7e2c698 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -1038,6 +1038,98 @@ static int igt_topdown(void *ignored) return ret; }
+static int igt_topdown_align(void *ignored) +{ + struct drm_mm mm; + struct drm_mm_node tmp, resv; + int ret = -EINVAL; + int n, m, err; + + drm_mm_init(&mm, 0, ~0ull); + memset(&tmp, 0, sizeof(tmp)); + memset(&resv, 0, sizeof(resv)); + + for (m = 0; m < 32; m++) { + u64 end = ~0ull; + + if (m) { + resv.size = BIT_ULL(m); + end -= resv.size; + resv.start = end; + + err = drm_mm_reserve_node(&mm, &resv); + if (err) { + pr_err("reservation of sentinel node failed\n"); + ret = err; + goto out; + } + } + + for (n = 0; n < 63 - m; n++) { + u64 align = BIT_ULL(n); + + err = drm_mm_insert_node_generic(&mm, &tmp, 1, align, 0, + DRM_MM_SEARCH_BELOW, + DRM_MM_CREATE_TOP); + drm_mm_remove_node(&tmp); + if (err) { + pr_err("insert failed, ret=%d\n", err); + ret = err; + goto out; + } + + if (tmp.start & (align - 1)) { + pr_err("insert alignment failed, aligment=%llx, start=%llx\n", + align, tmp.start); + goto out; + } + + if (tmp.start < end - align) { + pr_err("topdown insert failed, start=%llx, align=%llx, end=%llx\n", + tmp.start, align, end); + goto out; + } + } + + for_each_prime(n, min(8192ull, end - 1)) { + u64 rem; + + err = drm_mm_insert_node_generic(&mm, &tmp, n, 0, 0, + DRM_MM_SEARCH_BELOW, + DRM_MM_CREATE_TOP); + drm_mm_remove_node(&tmp); + if (err) { + pr_err("insert failed, ret=%d\n", err); + ret = err; + goto out; + } + + div64_u64_rem(tmp.start, n, &rem); + if (rem) { + pr_err("insert alignment failed, aligment=%d, start=%llx (offset %d)\n", + n, tmp.start, (int)rem); + goto out; + } + + if (tmp.start < end - n) { + pr_err("topdown insert failed, start=%llx, align=%d, end=%llx\n", + tmp.start, n, end); + goto out; + } + } + + if (resv.allocated) + drm_mm_remove_node(&resv); + } + + ret = 0; +out: + if (resv.allocated) + drm_mm_remove_node(&resv); + drm_mm_takedown(&mm); + return ret; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
On pe, 2016-12-09 at 13:08 +0000, Chris Wilson wrote:
Check that if we request top-down allocation with a particular alignment from drm_mm_insert_node() that the start of the node matches our request.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk
<SNIP>
@@ -1038,6 +1038,98 @@ static int igt_topdown(void *ignored) return ret; } +static int igt_topdown_align(void *ignored) +{
- struct drm_mm mm;
- struct drm_mm_node tmp, resv;
- int ret = -EINVAL;
- int n, m, err;
- drm_mm_init(&mm, 0, ~0ull);
U64_MAX
- memset(&tmp, 0, sizeof(tmp));
- memset(&resv, 0, sizeof(resv));
- for (m = 0; m < 32; m++) {
u64 end = ~0ull;
if (m) {
resv.size = BIT_ULL(m);
end -= resv.size;
resv.start = end;
err = drm_mm_reserve_node(&mm, &resv);
if (err) {
pr_err("reservation of sentinel node failed\n");
ret = err;
goto out;
}
}
for (n = 0; n < 63 - m; n++) {
u64 align = BIT_ULL(n);
err = drm_mm_insert_node_generic(&mm, &tmp, 1, align, 0,
DRM_MM_SEARCH_BELOW,
DRM_MM_CREATE_TOP);
drm_mm_remove_node(&tmp);
if (err) {
pr_err("insert failed, ret=%d\n", err);
ret = err;
goto out;
}
Just drm_mm_remove_node(&tmp) here to avoid an unnecessary extra splat. I think the tests should be valid code.
if (tmp.start & (align - 1)) {
pr_err("insert alignment failed, aligment=%llx, start=%llx\n",
align, tmp.start);
goto out;
}
if (tmp.start < end - align) {
pr_err("topdown insert failed, start=%llx, align=%llx, end=%llx\n",
tmp.start, align, end);
goto out;
}
}
for_each_prime(n, min(8192ull, end - 1)) {
u64 rem;
err = drm_mm_insert_node_generic(&mm, &tmp, n, 0, 0,
DRM_MM_SEARCH_BELOW,
DRM_MM_CREATE_TOP);
drm_mm_remove_node(&tmp);
if (err) {
pr_err("insert failed, ret=%d\n", err);
ret = err;
goto out;
}
Ditto.
In addition to those, I would use more meaningful variable names than m & n.
Regards, Joonas
Check that after applying the driver's color adjustment, fitting of the node and its alignment are still correct.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm_selftests.h | 1 + drivers/gpu/drm/test-drm_mm.c | 178 +++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+)
diff --git a/drivers/gpu/drm/drm_mm_selftests.h b/drivers/gpu/drm/drm_mm_selftests.h index 6bbdbb929714..30b4f2134248 100644 --- a/drivers/gpu/drm/drm_mm_selftests.h +++ b/drivers/gpu/drm/drm_mm_selftests.h @@ -5,6 +5,7 @@ * * Tests are executed in reverse order by igt/drm_mm */ +selftest(color, igt_color) selftest(topdown_align, igt_topdown_align) selftest(topdown, igt_topdown) selftest(evict, igt_evict) diff --git a/drivers/gpu/drm/test-drm_mm.c b/drivers/gpu/drm/test-drm_mm.c index 7699e7e2c698..f320ded75cab 100644 --- a/drivers/gpu/drm/test-drm_mm.c +++ b/drivers/gpu/drm/test-drm_mm.c @@ -1130,6 +1130,184 @@ static int igt_topdown_align(void *ignored) return ret; }
+static void no_color_touching(struct drm_mm_node *node, + unsigned long color, + u64 *start, + u64 *end) +{ + if (node->allocated && node->color != color) + ++*start; + + node = list_next_entry(node, node_list); + if (node->allocated && node->color != color) + --*end; +} + +static int igt_color(void *ignored) +{ + const int count = 4096; + struct drm_mm mm; + struct drm_mm_node *node, *nn; + const struct modes { + const char *name; + unsigned int search; + unsigned int create; + } modes[] = { + { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT }, + { "best", DRM_MM_SEARCH_BEST, DRM_MM_CREATE_DEFAULT }, + { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP }, + }; + int ret = -EINVAL; + int n, m; + + drm_mm_init(&mm, 0, ~0ull); + + for (n = 1; n <= count; n++) { + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + err = drm_mm_insert_node_generic(&mm, node, n, 0, n, + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); + if (err) { + pr_err("insert failed, step %d\n", n); + kfree(node); + ret = err; + goto out; + } + } + + list_for_each_entry_safe(node, nn, &mm.head_node.node_list, node_list) { + if (node->color != node->size) { + pr_err("invalid color stored: expected %lld, found %ld\n", + node->size, node->color); + + goto out; + } + + drm_mm_remove_node(node); + kfree(node); + } + + /* Now, let's start experimenting with applying a color callback */ + mm.color_adjust = no_color_touching; + for (m = 0; m < ARRAY_SIZE(modes); m++) { + u64 last; + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + node->size = 1 + 2*count; + node->color = node->size; + + err = drm_mm_reserve_node(&mm, node); + if (err) { + pr_err("intial reserve failed!\n"); + goto out; + } + + last = node->start + node->size; + + for (n = 1; n <= count; n++) { + int rem; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + node->start = last; + node->size = n + count; + node->color = node->size; + + err = drm_mm_reserve_node(&mm, node); + if (err != -ENOSPC) { + pr_err("reserve %d did not report color overlap! err=%d\n", + n, err); + goto out; + } + + node->start += n + 1; + rem = node->start; + rem %= n + count; + node->start += n + count - rem; + + err = drm_mm_reserve_node(&mm, node); + if (err) { + pr_err("reserve %d failed, err=%d\n", n, err); + goto out; + } + + last = node->start + node->size; + } + + for (n = 1; n <= count; n++) { + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + ret = -ENOMEM; + goto out; + } + + err = drm_mm_insert_node_generic(&mm, node, n, n, n, + modes[m].search, + modes[m].create); + if (err) { + pr_err("%s insert failed, step %d, err=%d\n", + modes[m].name, n, err); + kfree(node); + ret = err; + goto out; + } + } + + list_for_each_entry_safe(node, nn, + &mm.head_node.node_list, node_list) { + u64 rem; + + if (node->color != node->size) { + pr_err("%s invalid color stored: expected %lld, found %ld\n", + modes[m].name, node->size, node->color); + + goto out; + } + + if (!node->hole_follows) { + pr_err("%s colors abutt!\n", modes[m].name); + goto out; + } + + div64_u64_rem(node->start, node->size, &rem); + if (rem) { + pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", + modes[m].name, node->start, node->size, rem); + goto out; + } + + drm_mm_remove_node(node); + kfree(node); + } + } + + ret = 0; +out: + list_for_each_entry_safe(node, nn, &mm.head_node.node_list, node_list) { + drm_mm_remove_node(node); + kfree(node); + } + drm_mm_takedown(&mm); + return ret; +} + #include "drm_selftest.c"
static int __init test_drm_mm_init(void)
On pe, 2016-12-09 at 13:08 +0000, Chris Wilson wrote:
Simple first test to just exercise initialisation of struct drm_mm.
Signed-off-by: Chris Wilson chris@chris-wilson.co.uk
Reviewed-by: Joonas Lahtinen joonas.lahtinen@linux.intel.com
Regards, Joonas
dri-devel@lists.freedesktop.org