dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/9] drm: kselftest for drm_mm_init()
@ 2016-12-09 13:08 Chris Wilson
  2016-12-09 13:08 ` [PATCH 2/9] drm: kselftest for drm_mm_reserve_node() Chris Wilson
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, joonas.lahtinen

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)
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/9] drm: kselftest for drm_mm_reserve_node()
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 14:31   ` Joonas Lahtinen
  2016-12-09 13:08 ` [PATCH 3/9] drm: kselftest for drm_mm_insert_node() Chris Wilson
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

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)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/9] drm: kselftest for drm_mm_insert_node()
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
  2016-12-09 13:08 ` [PATCH 2/9] drm: kselftest for drm_mm_reserve_node() Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 13:08 ` [PATCH 4/9] drm: kselftest for drm_mm_insert_node_in_range() Chris Wilson
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

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);
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/9] drm: kselftest for drm_mm_insert_node_in_range()
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
  2016-12-09 13:08 ` [PATCH 2/9] drm: kselftest for drm_mm_reserve_node() Chris Wilson
  2016-12-09 13:08 ` [PATCH 3/9] drm: kselftest for drm_mm_insert_node() Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 13:08 ` [PATCH 5/9] drm: kselftest for drm_mm and alignment Chris Wilson
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

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)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/9] drm: kselftest for drm_mm and alignment
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (2 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 4/9] drm: kselftest for drm_mm_insert_node_in_range() Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 16:14   ` Joonas Lahtinen
  2016-12-09 13:08 ` [PATCH 6/9] drm: kselftest for drm_mm and eviction Chris Wilson
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, joonas.lahtinen

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)
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/9] drm: kselftest for drm_mm and eviction
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (3 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 5/9] drm: kselftest for drm_mm and alignment Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 13:08 ` [PATCH 7/9] drm: kselftest for drm_mm and top-down allocation Chris Wilson
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, joonas.lahtinen

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)
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 7/9] drm: kselftest for drm_mm and top-down allocation
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (4 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 6/9] drm: kselftest for drm_mm and eviction Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 13:08 ` [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment Chris Wilson
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

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)
-- 
2.11.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (5 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 7/9] drm: kselftest for drm_mm and top-down allocation Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 15:41   ` Joonas Lahtinen
  2016-12-09 13:08 ` [PATCH 9/9] drm: kselftest for drm_mm and color adjustment Chris Wilson
  2016-12-09 13:46 ` [PATCH 1/9] drm: kselftest for drm_mm_init() Joonas Lahtinen
  8 siblings, 1 reply; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, joonas.lahtinen

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)
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 9/9] drm: kselftest for drm_mm and color adjustment
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (6 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment Chris Wilson
@ 2016-12-09 13:08 ` Chris Wilson
  2016-12-09 13:46 ` [PATCH 1/9] drm: kselftest for drm_mm_init() Joonas Lahtinen
  8 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 13:08 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, joonas.lahtinen

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)
-- 
2.11.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/9] drm: kselftest for drm_mm_init()
  2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
                   ` (7 preceding siblings ...)
  2016-12-09 13:08 ` [PATCH 9/9] drm: kselftest for drm_mm and color adjustment Chris Wilson
@ 2016-12-09 13:46 ` Joonas Lahtinen
  8 siblings, 0 replies; 14+ messages in thread
From: Joonas Lahtinen @ 2016-12-09 13:46 UTC (permalink / raw)
  To: Chris Wilson, dri-devel; +Cc: intel-gfx

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
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/9] drm: kselftest for drm_mm_reserve_node()
  2016-12-09 13:08 ` [PATCH 2/9] drm: kselftest for drm_mm_reserve_node() Chris Wilson
@ 2016-12-09 14:31   ` Joonas Lahtinen
  2016-12-09 14:43     ` Chris Wilson
  0 siblings, 1 reply; 14+ messages in thread
From: Joonas Lahtinen @ 2016-12-09 14:31 UTC (permalink / raw)
  To: Chris Wilson, dri-devel; +Cc: intel-gfx

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
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/9] drm: kselftest for drm_mm_reserve_node()
  2016-12-09 14:31   ` Joonas Lahtinen
@ 2016-12-09 14:43     ` Chris Wilson
  0 siblings, 0 replies; 14+ messages in thread
From: Chris Wilson @ 2016-12-09 14:43 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: intel-gfx, dri-devel

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

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment
  2016-12-09 13:08 ` [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment Chris Wilson
@ 2016-12-09 15:41   ` Joonas Lahtinen
  0 siblings, 0 replies; 14+ messages in thread
From: Joonas Lahtinen @ 2016-12-09 15:41 UTC (permalink / raw)
  To: Chris Wilson, dri-devel; +Cc: intel-gfx

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
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/9] drm: kselftest for drm_mm and alignment
  2016-12-09 13:08 ` [PATCH 5/9] drm: kselftest for drm_mm and alignment Chris Wilson
@ 2016-12-09 16:14   ` Joonas Lahtinen
  0 siblings, 0 replies; 14+ messages in thread
From: Joonas Lahtinen @ 2016-12-09 16:14 UTC (permalink / raw)
  To: Chris Wilson, dri-devel; +Cc: intel-gfx

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
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2016-12-09 16:14 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-09 13:08 [PATCH 1/9] drm: kselftest for drm_mm_init() Chris Wilson
2016-12-09 13:08 ` [PATCH 2/9] drm: kselftest for drm_mm_reserve_node() Chris Wilson
2016-12-09 14:31   ` Joonas Lahtinen
2016-12-09 14:43     ` Chris Wilson
2016-12-09 13:08 ` [PATCH 3/9] drm: kselftest for drm_mm_insert_node() Chris Wilson
2016-12-09 13:08 ` [PATCH 4/9] drm: kselftest for drm_mm_insert_node_in_range() Chris Wilson
2016-12-09 13:08 ` [PATCH 5/9] drm: kselftest for drm_mm and alignment Chris Wilson
2016-12-09 16:14   ` Joonas Lahtinen
2016-12-09 13:08 ` [PATCH 6/9] drm: kselftest for drm_mm and eviction Chris Wilson
2016-12-09 13:08 ` [PATCH 7/9] drm: kselftest for drm_mm and top-down allocation Chris Wilson
2016-12-09 13:08 ` [PATCH 8/9] drm: kselftest for drm_mm and top-down alignment Chris Wilson
2016-12-09 15:41   ` Joonas Lahtinen
2016-12-09 13:08 ` [PATCH 9/9] drm: kselftest for drm_mm and color adjustment Chris Wilson
2016-12-09 13:46 ` [PATCH 1/9] drm: kselftest for drm_mm_init() Joonas Lahtinen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).