18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Test cases for the drm_mm range manager
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "drm_mm: " fmt
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/prime_numbers.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/random.h>
128c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
138c2ecf20Sopenharmony_ci#include <linux/ktime.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <drm/drm_mm.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "../lib/drm_random.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define TESTS "drm_mm_selftests.h"
208c2ecf20Sopenharmony_ci#include "drm_selftest.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic unsigned int random_seed;
238c2ecf20Sopenharmony_cistatic unsigned int max_iterations = 8192;
248c2ecf20Sopenharmony_cistatic unsigned int max_prime = 128;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cienum {
278c2ecf20Sopenharmony_ci	BEST,
288c2ecf20Sopenharmony_ci	BOTTOMUP,
298c2ecf20Sopenharmony_ci	TOPDOWN,
308c2ecf20Sopenharmony_ci	EVICT,
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct insert_mode {
348c2ecf20Sopenharmony_ci	const char *name;
358c2ecf20Sopenharmony_ci	enum drm_mm_insert_mode mode;
368c2ecf20Sopenharmony_ci} insert_modes[] = {
378c2ecf20Sopenharmony_ci	[BEST] = { "best", DRM_MM_INSERT_BEST },
388c2ecf20Sopenharmony_ci	[BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW },
398c2ecf20Sopenharmony_ci	[TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH },
408c2ecf20Sopenharmony_ci	[EVICT] = { "evict", DRM_MM_INSERT_EVICT },
418c2ecf20Sopenharmony_ci	{}
428c2ecf20Sopenharmony_ci}, evict_modes[] = {
438c2ecf20Sopenharmony_ci	{ "bottom-up", DRM_MM_INSERT_LOW },
448c2ecf20Sopenharmony_ci	{ "top-down", DRM_MM_INSERT_HIGH },
458c2ecf20Sopenharmony_ci	{}
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int igt_sanitycheck(void *ignored)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	pr_info("%s - ok!\n", __func__);
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic bool assert_no_holes(const struct drm_mm *mm)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct drm_mm_node *hole;
578c2ecf20Sopenharmony_ci	u64 hole_start, hole_end;
588c2ecf20Sopenharmony_ci	unsigned long count;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	count = 0;
618c2ecf20Sopenharmony_ci	drm_mm_for_each_hole(hole, mm, hole_start, hole_end)
628c2ecf20Sopenharmony_ci		count++;
638c2ecf20Sopenharmony_ci	if (count) {
648c2ecf20Sopenharmony_ci		pr_err("Expected to find no holes (after reserve), found %lu instead\n", count);
658c2ecf20Sopenharmony_ci		return false;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	drm_mm_for_each_node(hole, mm) {
698c2ecf20Sopenharmony_ci		if (drm_mm_hole_follows(hole)) {
708c2ecf20Sopenharmony_ci			pr_err("Hole follows node, expected none!\n");
718c2ecf20Sopenharmony_ci			return false;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return true;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct drm_mm_node *hole;
818c2ecf20Sopenharmony_ci	u64 hole_start, hole_end;
828c2ecf20Sopenharmony_ci	unsigned long count;
838c2ecf20Sopenharmony_ci	bool ok = true;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (end <= start)
868c2ecf20Sopenharmony_ci		return true;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	count = 0;
898c2ecf20Sopenharmony_ci	drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
908c2ecf20Sopenharmony_ci		if (start != hole_start || end != hole_end) {
918c2ecf20Sopenharmony_ci			if (ok)
928c2ecf20Sopenharmony_ci				pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n",
938c2ecf20Sopenharmony_ci				       hole_start, hole_end,
948c2ecf20Sopenharmony_ci				       start, end);
958c2ecf20Sopenharmony_ci			ok = false;
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci		count++;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	if (count != 1) {
1008c2ecf20Sopenharmony_ci		pr_err("Expected to find one hole, found %lu instead\n", count);
1018c2ecf20Sopenharmony_ci		ok = false;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return ok;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic bool assert_continuous(const struct drm_mm *mm, u64 size)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *check, *found;
1108c2ecf20Sopenharmony_ci	unsigned long n;
1118c2ecf20Sopenharmony_ci	u64 addr;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!assert_no_holes(mm))
1148c2ecf20Sopenharmony_ci		return false;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	n = 0;
1178c2ecf20Sopenharmony_ci	addr = 0;
1188c2ecf20Sopenharmony_ci	drm_mm_for_each_node(node, mm) {
1198c2ecf20Sopenharmony_ci		if (node->start != addr) {
1208c2ecf20Sopenharmony_ci			pr_err("node[%ld] list out of order, expected %llx found %llx\n",
1218c2ecf20Sopenharmony_ci			       n, addr, node->start);
1228c2ecf20Sopenharmony_ci			return false;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		if (node->size != size) {
1268c2ecf20Sopenharmony_ci			pr_err("node[%ld].size incorrect, expected %llx, found %llx\n",
1278c2ecf20Sopenharmony_ci			       n, size, node->size);
1288c2ecf20Sopenharmony_ci			return false;
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		if (drm_mm_hole_follows(node)) {
1328c2ecf20Sopenharmony_ci			pr_err("node[%ld] is followed by a hole!\n", n);
1338c2ecf20Sopenharmony_ci			return false;
1348c2ecf20Sopenharmony_ci		}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		found = NULL;
1378c2ecf20Sopenharmony_ci		drm_mm_for_each_node_in_range(check, mm, addr, addr + size) {
1388c2ecf20Sopenharmony_ci			if (node != check) {
1398c2ecf20Sopenharmony_ci				pr_err("lookup return wrong node, expected start %llx, found %llx\n",
1408c2ecf20Sopenharmony_ci				       node->start, check->start);
1418c2ecf20Sopenharmony_ci				return false;
1428c2ecf20Sopenharmony_ci			}
1438c2ecf20Sopenharmony_ci			found = check;
1448c2ecf20Sopenharmony_ci		}
1458c2ecf20Sopenharmony_ci		if (!found) {
1468c2ecf20Sopenharmony_ci			pr_err("lookup failed for node %llx + %llx\n",
1478c2ecf20Sopenharmony_ci			       addr, size);
1488c2ecf20Sopenharmony_ci			return false;
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		addr += size;
1528c2ecf20Sopenharmony_ci		n++;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return true;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic u64 misalignment(struct drm_mm_node *node, u64 alignment)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	u64 rem;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (!alignment)
1638c2ecf20Sopenharmony_ci		return 0;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	div64_u64_rem(node->start, alignment, &rem);
1668c2ecf20Sopenharmony_ci	return rem;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic bool assert_node(struct drm_mm_node *node, struct drm_mm *mm,
1708c2ecf20Sopenharmony_ci			u64 size, u64 alignment, unsigned long color)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	bool ok = true;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (!drm_mm_node_allocated(node) || node->mm != mm) {
1758c2ecf20Sopenharmony_ci		pr_err("node not allocated\n");
1768c2ecf20Sopenharmony_ci		ok = false;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (node->size != size) {
1808c2ecf20Sopenharmony_ci		pr_err("node has wrong size, found %llu, expected %llu\n",
1818c2ecf20Sopenharmony_ci		       node->size, size);
1828c2ecf20Sopenharmony_ci		ok = false;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (misalignment(node, alignment)) {
1868c2ecf20Sopenharmony_ci		pr_err("node is misaligned, start %llx rem %llu, expected alignment %llu\n",
1878c2ecf20Sopenharmony_ci		       node->start, misalignment(node, alignment), alignment);
1888c2ecf20Sopenharmony_ci		ok = false;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (node->color != color) {
1928c2ecf20Sopenharmony_ci		pr_err("node has wrong color, found %lu, expected %lu\n",
1938c2ecf20Sopenharmony_ci		       node->color, color);
1948c2ecf20Sopenharmony_ci		ok = false;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return ok;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define show_mm(mm) do { \
2018c2ecf20Sopenharmony_ci	struct drm_printer __p = drm_debug_printer(__func__); \
2028c2ecf20Sopenharmony_ci	drm_mm_print((mm), &__p); } while (0)
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int igt_init(void *ignored)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	const unsigned int size = 4096;
2078c2ecf20Sopenharmony_ci	struct drm_mm mm;
2088c2ecf20Sopenharmony_ci	struct drm_mm_node tmp;
2098c2ecf20Sopenharmony_ci	int ret = -EINVAL;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Start with some simple checks on initialising the struct drm_mm */
2128c2ecf20Sopenharmony_ci	memset(&mm, 0, sizeof(mm));
2138c2ecf20Sopenharmony_ci	if (drm_mm_initialized(&mm)) {
2148c2ecf20Sopenharmony_ci		pr_err("zeroed mm claims to be initialized\n");
2158c2ecf20Sopenharmony_ci		return ret;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	memset(&mm, 0xff, sizeof(mm));
2198c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, size);
2208c2ecf20Sopenharmony_ci	if (!drm_mm_initialized(&mm)) {
2218c2ecf20Sopenharmony_ci		pr_err("mm claims not to be initialized\n");
2228c2ecf20Sopenharmony_ci		goto out;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (!drm_mm_clean(&mm)) {
2268c2ecf20Sopenharmony_ci		pr_err("mm not empty on creation\n");
2278c2ecf20Sopenharmony_ci		goto out;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/* After creation, it should all be one massive hole */
2318c2ecf20Sopenharmony_ci	if (!assert_one_hole(&mm, 0, size)) {
2328c2ecf20Sopenharmony_ci		ret = -EINVAL;
2338c2ecf20Sopenharmony_ci		goto out;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	memset(&tmp, 0, sizeof(tmp));
2378c2ecf20Sopenharmony_ci	tmp.start = 0;
2388c2ecf20Sopenharmony_ci	tmp.size = size;
2398c2ecf20Sopenharmony_ci	ret = drm_mm_reserve_node(&mm, &tmp);
2408c2ecf20Sopenharmony_ci	if (ret) {
2418c2ecf20Sopenharmony_ci		pr_err("failed to reserve whole drm_mm\n");
2428c2ecf20Sopenharmony_ci		goto out;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* After filling the range entirely, there should be no holes */
2468c2ecf20Sopenharmony_ci	if (!assert_no_holes(&mm)) {
2478c2ecf20Sopenharmony_ci		ret = -EINVAL;
2488c2ecf20Sopenharmony_ci		goto out;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* And then after emptying it again, the massive hole should be back */
2528c2ecf20Sopenharmony_ci	drm_mm_remove_node(&tmp);
2538c2ecf20Sopenharmony_ci	if (!assert_one_hole(&mm, 0, size)) {
2548c2ecf20Sopenharmony_ci		ret = -EINVAL;
2558c2ecf20Sopenharmony_ci		goto out;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ciout:
2598c2ecf20Sopenharmony_ci	if (ret)
2608c2ecf20Sopenharmony_ci		show_mm(&mm);
2618c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
2628c2ecf20Sopenharmony_ci	return ret;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int igt_debug(void *ignored)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct drm_mm mm;
2688c2ecf20Sopenharmony_ci	struct drm_mm_node nodes[2];
2698c2ecf20Sopenharmony_ci	int ret;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* Create a small drm_mm with a couple of nodes and a few holes, and
2728c2ecf20Sopenharmony_ci	 * check that the debug iterator doesn't explode over a trivial drm_mm.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, 4096);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	memset(nodes, 0, sizeof(nodes));
2788c2ecf20Sopenharmony_ci	nodes[0].start = 512;
2798c2ecf20Sopenharmony_ci	nodes[0].size = 1024;
2808c2ecf20Sopenharmony_ci	ret = drm_mm_reserve_node(&mm, &nodes[0]);
2818c2ecf20Sopenharmony_ci	if (ret) {
2828c2ecf20Sopenharmony_ci		pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n",
2838c2ecf20Sopenharmony_ci		       nodes[0].start, nodes[0].size);
2848c2ecf20Sopenharmony_ci		return ret;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	nodes[1].size = 1024;
2888c2ecf20Sopenharmony_ci	nodes[1].start = 4096 - 512 - nodes[1].size;
2898c2ecf20Sopenharmony_ci	ret = drm_mm_reserve_node(&mm, &nodes[1]);
2908c2ecf20Sopenharmony_ci	if (ret) {
2918c2ecf20Sopenharmony_ci		pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n",
2928c2ecf20Sopenharmony_ci		       nodes[1].start, nodes[1].size);
2938c2ecf20Sopenharmony_ci		return ret;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	show_mm(&mm);
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic struct drm_mm_node *set_node(struct drm_mm_node *node,
3018c2ecf20Sopenharmony_ci				    u64 start, u64 size)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	node->start = start;
3048c2ecf20Sopenharmony_ci	node->size = size;
3058c2ecf20Sopenharmony_ci	return node;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	int err;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	err = drm_mm_reserve_node(mm, node);
3138c2ecf20Sopenharmony_ci	if (likely(err == -ENOSPC))
3148c2ecf20Sopenharmony_ci		return true;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (!err) {
3178c2ecf20Sopenharmony_ci		pr_err("impossible reserve succeeded, node %llu + %llu\n",
3188c2ecf20Sopenharmony_ci		       node->start, node->size);
3198c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
3208c2ecf20Sopenharmony_ci	} else {
3218c2ecf20Sopenharmony_ci		pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n",
3228c2ecf20Sopenharmony_ci		       err, -ENOSPC, node->start, node->size);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	return false;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic bool check_reserve_boundaries(struct drm_mm *mm,
3288c2ecf20Sopenharmony_ci				     unsigned int count,
3298c2ecf20Sopenharmony_ci				     u64 size)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	const struct boundary {
3328c2ecf20Sopenharmony_ci		u64 start, size;
3338c2ecf20Sopenharmony_ci		const char *name;
3348c2ecf20Sopenharmony_ci	} boundaries[] = {
3358c2ecf20Sopenharmony_ci#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" }
3368c2ecf20Sopenharmony_ci		B(0, 0),
3378c2ecf20Sopenharmony_ci		B(-size, 0),
3388c2ecf20Sopenharmony_ci		B(size, 0),
3398c2ecf20Sopenharmony_ci		B(size * count, 0),
3408c2ecf20Sopenharmony_ci		B(-size, size),
3418c2ecf20Sopenharmony_ci		B(-size, -size),
3428c2ecf20Sopenharmony_ci		B(-size, 2*size),
3438c2ecf20Sopenharmony_ci		B(0, -size),
3448c2ecf20Sopenharmony_ci		B(size, -size),
3458c2ecf20Sopenharmony_ci		B(count*size, size),
3468c2ecf20Sopenharmony_ci		B(count*size, -size),
3478c2ecf20Sopenharmony_ci		B(count*size, count*size),
3488c2ecf20Sopenharmony_ci		B(count*size, -count*size),
3498c2ecf20Sopenharmony_ci		B(count*size, -(count+1)*size),
3508c2ecf20Sopenharmony_ci		B((count+1)*size, size),
3518c2ecf20Sopenharmony_ci		B((count+1)*size, -size),
3528c2ecf20Sopenharmony_ci		B((count+1)*size, -2*size),
3538c2ecf20Sopenharmony_ci#undef B
3548c2ecf20Sopenharmony_ci	};
3558c2ecf20Sopenharmony_ci	struct drm_mm_node tmp = {};
3568c2ecf20Sopenharmony_ci	int n;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	for (n = 0; n < ARRAY_SIZE(boundaries); n++) {
3598c2ecf20Sopenharmony_ci		if (!expect_reserve_fail(mm,
3608c2ecf20Sopenharmony_ci					 set_node(&tmp,
3618c2ecf20Sopenharmony_ci						  boundaries[n].start,
3628c2ecf20Sopenharmony_ci						  boundaries[n].size))) {
3638c2ecf20Sopenharmony_ci			pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n",
3648c2ecf20Sopenharmony_ci			       n, boundaries[n].name, count, size);
3658c2ecf20Sopenharmony_ci			return false;
3668c2ecf20Sopenharmony_ci		}
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return true;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic int __igt_reserve(unsigned int count, u64 size)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
3758c2ecf20Sopenharmony_ci	struct drm_mm mm;
3768c2ecf20Sopenharmony_ci	struct drm_mm_node tmp, *nodes, *node, *next;
3778c2ecf20Sopenharmony_ci	unsigned int *order, n, m, o = 0;
3788c2ecf20Sopenharmony_ci	int ret, err;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* For exercising drm_mm_reserve_node(), we want to check that
3818c2ecf20Sopenharmony_ci	 * reservations outside of the drm_mm range are rejected, and to
3828c2ecf20Sopenharmony_ci	 * overlapping and otherwise already occupied ranges. Afterwards,
3838c2ecf20Sopenharmony_ci	 * the tree and nodes should be intact.
3848c2ecf20Sopenharmony_ci	 */
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!count);
3878c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!size);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	ret = -ENOMEM;
3908c2ecf20Sopenharmony_ci	order = drm_random_order(count, &prng);
3918c2ecf20Sopenharmony_ci	if (!order)
3928c2ecf20Sopenharmony_ci		goto err;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(count, sizeof(*nodes)));
3958c2ecf20Sopenharmony_ci	if (!nodes)
3968c2ecf20Sopenharmony_ci		goto err_order;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	ret = -EINVAL;
3998c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, count * size);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (!check_reserve_boundaries(&mm, count, size))
4028c2ecf20Sopenharmony_ci		goto out;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	for (n = 0; n < count; n++) {
4058c2ecf20Sopenharmony_ci		nodes[n].start = order[n] * size;
4068c2ecf20Sopenharmony_ci		nodes[n].size = size;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(&mm, &nodes[n]);
4098c2ecf20Sopenharmony_ci		if (err) {
4108c2ecf20Sopenharmony_ci			pr_err("reserve failed, step %d, start %llu\n",
4118c2ecf20Sopenharmony_ci			       n, nodes[n].start);
4128c2ecf20Sopenharmony_ci			ret = err;
4138c2ecf20Sopenharmony_ci			goto out;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		if (!drm_mm_node_allocated(&nodes[n])) {
4178c2ecf20Sopenharmony_ci			pr_err("reserved node not allocated! step %d, start %llu\n",
4188c2ecf20Sopenharmony_ci			       n, nodes[n].start);
4198c2ecf20Sopenharmony_ci			goto out;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		if (!expect_reserve_fail(&mm, &nodes[n]))
4238c2ecf20Sopenharmony_ci			goto out;
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* After random insertion the nodes should be in order */
4278c2ecf20Sopenharmony_ci	if (!assert_continuous(&mm, size))
4288c2ecf20Sopenharmony_ci		goto out;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* Repeated use should then fail */
4318c2ecf20Sopenharmony_ci	drm_random_reorder(order, count, &prng);
4328c2ecf20Sopenharmony_ci	for (n = 0; n < count; n++) {
4338c2ecf20Sopenharmony_ci		if (!expect_reserve_fail(&mm,
4348c2ecf20Sopenharmony_ci					 set_node(&tmp, order[n] * size, 1)))
4358c2ecf20Sopenharmony_ci			goto out;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		/* Remove and reinsert should work */
4388c2ecf20Sopenharmony_ci		drm_mm_remove_node(&nodes[order[n]]);
4398c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(&mm, &nodes[order[n]]);
4408c2ecf20Sopenharmony_ci		if (err) {
4418c2ecf20Sopenharmony_ci			pr_err("reserve failed, step %d, start %llu\n",
4428c2ecf20Sopenharmony_ci			       n, nodes[n].start);
4438c2ecf20Sopenharmony_ci			ret = err;
4448c2ecf20Sopenharmony_ci			goto out;
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (!assert_continuous(&mm, size))
4498c2ecf20Sopenharmony_ci		goto out;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* Overlapping use should then fail */
4528c2ecf20Sopenharmony_ci	for (n = 0; n < count; n++) {
4538c2ecf20Sopenharmony_ci		if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count)))
4548c2ecf20Sopenharmony_ci			goto out;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci	for (n = 0; n < count; n++) {
4578c2ecf20Sopenharmony_ci		if (!expect_reserve_fail(&mm,
4588c2ecf20Sopenharmony_ci					 set_node(&tmp,
4598c2ecf20Sopenharmony_ci						  size * n,
4608c2ecf20Sopenharmony_ci						  size * (count - n))))
4618c2ecf20Sopenharmony_ci			goto out;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* Remove several, reinsert, check full */
4658c2ecf20Sopenharmony_ci	for_each_prime_number(n, min(max_prime, count)) {
4668c2ecf20Sopenharmony_ci		for (m = 0; m < n; m++) {
4678c2ecf20Sopenharmony_ci			node = &nodes[order[(o + m) % count]];
4688c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
4698c2ecf20Sopenharmony_ci		}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		for (m = 0; m < n; m++) {
4728c2ecf20Sopenharmony_ci			node = &nodes[order[(o + m) % count]];
4738c2ecf20Sopenharmony_ci			err = drm_mm_reserve_node(&mm, node);
4748c2ecf20Sopenharmony_ci			if (err) {
4758c2ecf20Sopenharmony_ci				pr_err("reserve failed, step %d/%d, start %llu\n",
4768c2ecf20Sopenharmony_ci				       m, n, node->start);
4778c2ecf20Sopenharmony_ci				ret = err;
4788c2ecf20Sopenharmony_ci				goto out;
4798c2ecf20Sopenharmony_ci			}
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		o += n;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		if (!assert_continuous(&mm, size))
4858c2ecf20Sopenharmony_ci			goto out;
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	ret = 0;
4898c2ecf20Sopenharmony_ciout:
4908c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
4918c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
4928c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
4938c2ecf20Sopenharmony_ci	vfree(nodes);
4948c2ecf20Sopenharmony_cierr_order:
4958c2ecf20Sopenharmony_ci	kfree(order);
4968c2ecf20Sopenharmony_cierr:
4978c2ecf20Sopenharmony_ci	return ret;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int igt_reserve(void *ignored)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
5038c2ecf20Sopenharmony_ci	int n, ret;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	for_each_prime_number_from(n, 1, 54) {
5068c2ecf20Sopenharmony_ci		u64 size = BIT_ULL(n);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		ret = __igt_reserve(count, size - 1);
5098c2ecf20Sopenharmony_ci		if (ret)
5108c2ecf20Sopenharmony_ci			return ret;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		ret = __igt_reserve(count, size);
5138c2ecf20Sopenharmony_ci		if (ret)
5148c2ecf20Sopenharmony_ci			return ret;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		ret = __igt_reserve(count, size + 1);
5178c2ecf20Sopenharmony_ci		if (ret)
5188c2ecf20Sopenharmony_ci			return ret;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		cond_resched();
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	return 0;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
5278c2ecf20Sopenharmony_ci			  u64 size, u64 alignment, unsigned long color,
5288c2ecf20Sopenharmony_ci			  const struct insert_mode *mode)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	int err;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_generic(mm, node,
5338c2ecf20Sopenharmony_ci					 size, alignment, color,
5348c2ecf20Sopenharmony_ci					 mode->mode);
5358c2ecf20Sopenharmony_ci	if (err) {
5368c2ecf20Sopenharmony_ci		pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n",
5378c2ecf20Sopenharmony_ci		       size, alignment, color, mode->name, err);
5388c2ecf20Sopenharmony_ci		return false;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (!assert_node(node, mm, size, alignment, color)) {
5428c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
5438c2ecf20Sopenharmony_ci		return false;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return true;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic bool expect_insert_fail(struct drm_mm *mm, u64 size)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct drm_mm_node tmp = {};
5528c2ecf20Sopenharmony_ci	int err;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	err = drm_mm_insert_node(mm, &tmp, size);
5558c2ecf20Sopenharmony_ci	if (likely(err == -ENOSPC))
5568c2ecf20Sopenharmony_ci		return true;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	if (!err) {
5598c2ecf20Sopenharmony_ci		pr_err("impossible insert succeeded, node %llu + %llu\n",
5608c2ecf20Sopenharmony_ci		       tmp.start, tmp.size);
5618c2ecf20Sopenharmony_ci		drm_mm_remove_node(&tmp);
5628c2ecf20Sopenharmony_ci	} else {
5638c2ecf20Sopenharmony_ci		pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n",
5648c2ecf20Sopenharmony_ci		       err, -ENOSPC, size);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci	return false;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic int __igt_insert(unsigned int count, u64 size, bool replace)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
5728c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
5738c2ecf20Sopenharmony_ci	struct drm_mm mm;
5748c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
5758c2ecf20Sopenharmony_ci	unsigned int *order, n, m, o = 0;
5768c2ecf20Sopenharmony_ci	int ret;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* Fill a range with lots of nodes, check it doesn't fail too early */
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!count);
5818c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!size);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	ret = -ENOMEM;
5848c2ecf20Sopenharmony_ci	nodes = vmalloc(array_size(count, sizeof(*nodes)));
5858c2ecf20Sopenharmony_ci	if (!nodes)
5868c2ecf20Sopenharmony_ci		goto err;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	order = drm_random_order(count, &prng);
5898c2ecf20Sopenharmony_ci	if (!order)
5908c2ecf20Sopenharmony_ci		goto err_nodes;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	ret = -EINVAL;
5938c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, count * size);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for (mode = insert_modes; mode->name; mode++) {
5968c2ecf20Sopenharmony_ci		for (n = 0; n < count; n++) {
5978c2ecf20Sopenharmony_ci			struct drm_mm_node tmp;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci			node = replace ? &tmp : &nodes[n];
6008c2ecf20Sopenharmony_ci			memset(node, 0, sizeof(*node));
6018c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, node, size, 0, n, mode)) {
6028c2ecf20Sopenharmony_ci				pr_err("%s insert failed, size %llu step %d\n",
6038c2ecf20Sopenharmony_ci				       mode->name, size, n);
6048c2ecf20Sopenharmony_ci				goto out;
6058c2ecf20Sopenharmony_ci			}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci			if (replace) {
6088c2ecf20Sopenharmony_ci				drm_mm_replace_node(&tmp, &nodes[n]);
6098c2ecf20Sopenharmony_ci				if (drm_mm_node_allocated(&tmp)) {
6108c2ecf20Sopenharmony_ci					pr_err("replaced old-node still allocated! step %d\n",
6118c2ecf20Sopenharmony_ci					       n);
6128c2ecf20Sopenharmony_ci					goto out;
6138c2ecf20Sopenharmony_ci				}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci				if (!assert_node(&nodes[n], &mm, size, 0, n)) {
6168c2ecf20Sopenharmony_ci					pr_err("replaced node did not inherit parameters, size %llu step %d\n",
6178c2ecf20Sopenharmony_ci					       size, n);
6188c2ecf20Sopenharmony_ci					goto out;
6198c2ecf20Sopenharmony_ci				}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci				if (tmp.start != nodes[n].start) {
6228c2ecf20Sopenharmony_ci					pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n",
6238c2ecf20Sopenharmony_ci					       tmp.start, size,
6248c2ecf20Sopenharmony_ci					       nodes[n].start, nodes[n].size);
6258c2ecf20Sopenharmony_ci					goto out;
6268c2ecf20Sopenharmony_ci				}
6278c2ecf20Sopenharmony_ci			}
6288c2ecf20Sopenharmony_ci		}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		/* After random insertion the nodes should be in order */
6318c2ecf20Sopenharmony_ci		if (!assert_continuous(&mm, size))
6328c2ecf20Sopenharmony_ci			goto out;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci		/* Repeated use should then fail */
6358c2ecf20Sopenharmony_ci		if (!expect_insert_fail(&mm, size))
6368c2ecf20Sopenharmony_ci			goto out;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		/* Remove one and reinsert, as the only hole it should refill itself */
6398c2ecf20Sopenharmony_ci		for (n = 0; n < count; n++) {
6408c2ecf20Sopenharmony_ci			u64 addr = nodes[n].start;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci			drm_mm_remove_node(&nodes[n]);
6438c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) {
6448c2ecf20Sopenharmony_ci				pr_err("%s reinsert failed, size %llu step %d\n",
6458c2ecf20Sopenharmony_ci				       mode->name, size, n);
6468c2ecf20Sopenharmony_ci				goto out;
6478c2ecf20Sopenharmony_ci			}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci			if (nodes[n].start != addr) {
6508c2ecf20Sopenharmony_ci				pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
6518c2ecf20Sopenharmony_ci				       mode->name, n, addr, nodes[n].start);
6528c2ecf20Sopenharmony_ci				goto out;
6538c2ecf20Sopenharmony_ci			}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci			if (!assert_continuous(&mm, size))
6568c2ecf20Sopenharmony_ci				goto out;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		/* Remove several, reinsert, check full */
6608c2ecf20Sopenharmony_ci		for_each_prime_number(n, min(max_prime, count)) {
6618c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
6628c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
6638c2ecf20Sopenharmony_ci				drm_mm_remove_node(node);
6648c2ecf20Sopenharmony_ci			}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
6678c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
6688c2ecf20Sopenharmony_ci				if (!expect_insert(&mm, node, size, 0, n, mode)) {
6698c2ecf20Sopenharmony_ci					pr_err("%s multiple reinsert failed, size %llu step %d\n",
6708c2ecf20Sopenharmony_ci					       mode->name, size, n);
6718c2ecf20Sopenharmony_ci					goto out;
6728c2ecf20Sopenharmony_ci				}
6738c2ecf20Sopenharmony_ci			}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci			o += n;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci			if (!assert_continuous(&mm, size))
6788c2ecf20Sopenharmony_ci				goto out;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci			if (!expect_insert_fail(&mm, size))
6818c2ecf20Sopenharmony_ci				goto out;
6828c2ecf20Sopenharmony_ci		}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
6858c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
6868c2ecf20Sopenharmony_ci		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		cond_resched();
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	ret = 0;
6928c2ecf20Sopenharmony_ciout:
6938c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
6948c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
6958c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
6968c2ecf20Sopenharmony_ci	kfree(order);
6978c2ecf20Sopenharmony_cierr_nodes:
6988c2ecf20Sopenharmony_ci	vfree(nodes);
6998c2ecf20Sopenharmony_cierr:
7008c2ecf20Sopenharmony_ci	return ret;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic int igt_insert(void *ignored)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
7068c2ecf20Sopenharmony_ci	unsigned int n;
7078c2ecf20Sopenharmony_ci	int ret;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	for_each_prime_number_from(n, 1, 54) {
7108c2ecf20Sopenharmony_ci		u64 size = BIT_ULL(n);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size - 1, false);
7138c2ecf20Sopenharmony_ci		if (ret)
7148c2ecf20Sopenharmony_ci			return ret;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size, false);
7178c2ecf20Sopenharmony_ci		if (ret)
7188c2ecf20Sopenharmony_ci			return ret;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size + 1, false);
7218c2ecf20Sopenharmony_ci		if (ret)
7228c2ecf20Sopenharmony_ci			return ret;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		cond_resched();
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	return 0;
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic int igt_replace(void *ignored)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
7338c2ecf20Sopenharmony_ci	unsigned int n;
7348c2ecf20Sopenharmony_ci	int ret;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/* Reuse igt_insert to exercise replacement by inserting a dummy node,
7378c2ecf20Sopenharmony_ci	 * then replacing it with the intended node. We want to check that
7388c2ecf20Sopenharmony_ci	 * the tree is intact and all the information we need is carried
7398c2ecf20Sopenharmony_ci	 * across to the target node.
7408c2ecf20Sopenharmony_ci	 */
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	for_each_prime_number_from(n, 1, 54) {
7438c2ecf20Sopenharmony_ci		u64 size = BIT_ULL(n);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size - 1, true);
7468c2ecf20Sopenharmony_ci		if (ret)
7478c2ecf20Sopenharmony_ci			return ret;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size, true);
7508c2ecf20Sopenharmony_ci		if (ret)
7518c2ecf20Sopenharmony_ci			return ret;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		ret = __igt_insert(count, size + 1, true);
7548c2ecf20Sopenharmony_ci		if (ret)
7558c2ecf20Sopenharmony_ci			return ret;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		cond_resched();
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	return 0;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node,
7648c2ecf20Sopenharmony_ci				   u64 size, u64 alignment, unsigned long color,
7658c2ecf20Sopenharmony_ci				   u64 range_start, u64 range_end,
7668c2ecf20Sopenharmony_ci				   const struct insert_mode *mode)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	int err;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_in_range(mm, node,
7718c2ecf20Sopenharmony_ci					  size, alignment, color,
7728c2ecf20Sopenharmony_ci					  range_start, range_end,
7738c2ecf20Sopenharmony_ci					  mode->mode);
7748c2ecf20Sopenharmony_ci	if (err) {
7758c2ecf20Sopenharmony_ci		pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n",
7768c2ecf20Sopenharmony_ci		       size, alignment, color, mode->name,
7778c2ecf20Sopenharmony_ci		       range_start, range_end, err);
7788c2ecf20Sopenharmony_ci		return false;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if (!assert_node(node, mm, size, alignment, color)) {
7828c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
7838c2ecf20Sopenharmony_ci		return false;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return true;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic bool expect_insert_in_range_fail(struct drm_mm *mm,
7908c2ecf20Sopenharmony_ci					u64 size,
7918c2ecf20Sopenharmony_ci					u64 range_start,
7928c2ecf20Sopenharmony_ci					u64 range_end)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	struct drm_mm_node tmp = {};
7958c2ecf20Sopenharmony_ci	int err;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_in_range(mm, &tmp,
7988c2ecf20Sopenharmony_ci					  size, 0, 0,
7998c2ecf20Sopenharmony_ci					  range_start, range_end,
8008c2ecf20Sopenharmony_ci					  0);
8018c2ecf20Sopenharmony_ci	if (likely(err == -ENOSPC))
8028c2ecf20Sopenharmony_ci		return true;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if (!err) {
8058c2ecf20Sopenharmony_ci		pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n",
8068c2ecf20Sopenharmony_ci		       tmp.start, tmp.size, range_start, range_end);
8078c2ecf20Sopenharmony_ci		drm_mm_remove_node(&tmp);
8088c2ecf20Sopenharmony_ci	} else {
8098c2ecf20Sopenharmony_ci		pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n",
8108c2ecf20Sopenharmony_ci		       err, -ENOSPC, size, range_start, range_end);
8118c2ecf20Sopenharmony_ci	}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return false;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic bool assert_contiguous_in_range(struct drm_mm *mm,
8178c2ecf20Sopenharmony_ci				       u64 size,
8188c2ecf20Sopenharmony_ci				       u64 start,
8198c2ecf20Sopenharmony_ci				       u64 end)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	struct drm_mm_node *node;
8228c2ecf20Sopenharmony_ci	unsigned int n;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (!expect_insert_in_range_fail(mm, size, start, end))
8258c2ecf20Sopenharmony_ci		return false;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	n = div64_u64(start + size - 1, size);
8288c2ecf20Sopenharmony_ci	drm_mm_for_each_node(node, mm) {
8298c2ecf20Sopenharmony_ci		if (node->start < start || node->start + node->size > end) {
8308c2ecf20Sopenharmony_ci			pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n",
8318c2ecf20Sopenharmony_ci			       n, node->start, node->start + node->size, start, end);
8328c2ecf20Sopenharmony_ci			return false;
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		if (node->start != n * size) {
8368c2ecf20Sopenharmony_ci			pr_err("node %d out of order, expected start %llx, found %llx\n",
8378c2ecf20Sopenharmony_ci			       n, n * size, node->start);
8388c2ecf20Sopenharmony_ci			return false;
8398c2ecf20Sopenharmony_ci		}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		if (node->size != size) {
8428c2ecf20Sopenharmony_ci			pr_err("node %d has wrong size, expected size %llx, found %llx\n",
8438c2ecf20Sopenharmony_ci			       n, size, node->size);
8448c2ecf20Sopenharmony_ci			return false;
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		if (drm_mm_hole_follows(node) &&
8488c2ecf20Sopenharmony_ci		    drm_mm_hole_node_end(node) < end) {
8498c2ecf20Sopenharmony_ci			pr_err("node %d is followed by a hole!\n", n);
8508c2ecf20Sopenharmony_ci			return false;
8518c2ecf20Sopenharmony_ci		}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci		n++;
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	if (start > 0) {
8578c2ecf20Sopenharmony_ci		node = __drm_mm_interval_first(mm, 0, start - 1);
8588c2ecf20Sopenharmony_ci		if (drm_mm_node_allocated(node)) {
8598c2ecf20Sopenharmony_ci			pr_err("node before start: node=%llx+%llu, start=%llx\n",
8608c2ecf20Sopenharmony_ci			       node->start, node->size, start);
8618c2ecf20Sopenharmony_ci			return false;
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	if (end < U64_MAX) {
8668c2ecf20Sopenharmony_ci		node = __drm_mm_interval_first(mm, end, U64_MAX);
8678c2ecf20Sopenharmony_ci		if (drm_mm_node_allocated(node)) {
8688c2ecf20Sopenharmony_ci			pr_err("node after end: node=%llx+%llu, end=%llx\n",
8698c2ecf20Sopenharmony_ci			       node->start, node->size, end);
8708c2ecf20Sopenharmony_ci			return false;
8718c2ecf20Sopenharmony_ci		}
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return true;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
8808c2ecf20Sopenharmony_ci	struct drm_mm mm;
8818c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
8828c2ecf20Sopenharmony_ci	unsigned int n, start_n, end_n;
8838c2ecf20Sopenharmony_ci	int ret;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!count);
8868c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(!size);
8878c2ecf20Sopenharmony_ci	DRM_MM_BUG_ON(end <= start);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	/* Very similar to __igt_insert(), but now instead of populating the
8908c2ecf20Sopenharmony_ci	 * full range of the drm_mm, we try to fill a small portion of it.
8918c2ecf20Sopenharmony_ci	 */
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	ret = -ENOMEM;
8948c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(count, sizeof(*nodes)));
8958c2ecf20Sopenharmony_ci	if (!nodes)
8968c2ecf20Sopenharmony_ci		goto err;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	ret = -EINVAL;
8998c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, count * size);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	start_n = div64_u64(start + size - 1, size);
9028c2ecf20Sopenharmony_ci	end_n = div64_u64(end - size, size);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	for (mode = insert_modes; mode->name; mode++) {
9058c2ecf20Sopenharmony_ci		for (n = start_n; n <= end_n; n++) {
9068c2ecf20Sopenharmony_ci			if (!expect_insert_in_range(&mm, &nodes[n],
9078c2ecf20Sopenharmony_ci						    size, size, n,
9088c2ecf20Sopenharmony_ci						    start, end, mode)) {
9098c2ecf20Sopenharmony_ci				pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n",
9108c2ecf20Sopenharmony_ci				       mode->name, size, n,
9118c2ecf20Sopenharmony_ci				       start_n, end_n,
9128c2ecf20Sopenharmony_ci				       start, end);
9138c2ecf20Sopenharmony_ci				goto out;
9148c2ecf20Sopenharmony_ci			}
9158c2ecf20Sopenharmony_ci		}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci		if (!assert_contiguous_in_range(&mm, size, start, end)) {
9188c2ecf20Sopenharmony_ci			pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n",
9198c2ecf20Sopenharmony_ci			       mode->name, start, end, size);
9208c2ecf20Sopenharmony_ci			goto out;
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		/* Remove one and reinsert, it should refill itself */
9248c2ecf20Sopenharmony_ci		for (n = start_n; n <= end_n; n++) {
9258c2ecf20Sopenharmony_ci			u64 addr = nodes[n].start;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci			drm_mm_remove_node(&nodes[n]);
9288c2ecf20Sopenharmony_ci			if (!expect_insert_in_range(&mm, &nodes[n],
9298c2ecf20Sopenharmony_ci						    size, size, n,
9308c2ecf20Sopenharmony_ci						    start, end, mode)) {
9318c2ecf20Sopenharmony_ci				pr_err("%s reinsert failed, step %d\n", mode->name, n);
9328c2ecf20Sopenharmony_ci				goto out;
9338c2ecf20Sopenharmony_ci			}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci			if (nodes[n].start != addr) {
9368c2ecf20Sopenharmony_ci				pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
9378c2ecf20Sopenharmony_ci				       mode->name, n, addr, nodes[n].start);
9388c2ecf20Sopenharmony_ci				goto out;
9398c2ecf20Sopenharmony_ci			}
9408c2ecf20Sopenharmony_ci		}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		if (!assert_contiguous_in_range(&mm, size, start, end)) {
9438c2ecf20Sopenharmony_ci			pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n",
9448c2ecf20Sopenharmony_ci			       mode->name, start, end, size);
9458c2ecf20Sopenharmony_ci			goto out;
9468c2ecf20Sopenharmony_ci		}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
9498c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
9508c2ecf20Sopenharmony_ci		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		cond_resched();
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	ret = 0;
9568c2ecf20Sopenharmony_ciout:
9578c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
9588c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
9598c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
9608c2ecf20Sopenharmony_ci	vfree(nodes);
9618c2ecf20Sopenharmony_cierr:
9628c2ecf20Sopenharmony_ci	return ret;
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic int insert_outside_range(void)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct drm_mm mm;
9688c2ecf20Sopenharmony_ci	const unsigned int start = 1024;
9698c2ecf20Sopenharmony_ci	const unsigned int end = 2048;
9708c2ecf20Sopenharmony_ci	const unsigned int size = end - start;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	drm_mm_init(&mm, start, size);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	if (!expect_insert_in_range_fail(&mm, 1, 0, start))
9758c2ecf20Sopenharmony_ci		return -EINVAL;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (!expect_insert_in_range_fail(&mm, size,
9788c2ecf20Sopenharmony_ci					 start - size/2, start + (size+1)/2))
9798c2ecf20Sopenharmony_ci		return -EINVAL;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (!expect_insert_in_range_fail(&mm, size,
9828c2ecf20Sopenharmony_ci					 end - (size+1)/2, end + size/2))
9838c2ecf20Sopenharmony_ci		return -EINVAL;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (!expect_insert_in_range_fail(&mm, 1, end, end + size))
9868c2ecf20Sopenharmony_ci		return -EINVAL;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
9898c2ecf20Sopenharmony_ci	return 0;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic int igt_insert_range(void *ignored)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	const unsigned int count = min_t(unsigned int, BIT(13), max_iterations);
9958c2ecf20Sopenharmony_ci	unsigned int n;
9968c2ecf20Sopenharmony_ci	int ret;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/* Check that requests outside the bounds of drm_mm are rejected. */
9998c2ecf20Sopenharmony_ci	ret = insert_outside_range();
10008c2ecf20Sopenharmony_ci	if (ret)
10018c2ecf20Sopenharmony_ci		return ret;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	for_each_prime_number_from(n, 1, 50) {
10048c2ecf20Sopenharmony_ci		const u64 size = BIT_ULL(n);
10058c2ecf20Sopenharmony_ci		const u64 max = count * size;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, 0, max);
10088c2ecf20Sopenharmony_ci		if (ret)
10098c2ecf20Sopenharmony_ci			return ret;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, 1, max);
10128c2ecf20Sopenharmony_ci		if (ret)
10138c2ecf20Sopenharmony_ci			return ret;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, 0, max - 1);
10168c2ecf20Sopenharmony_ci		if (ret)
10178c2ecf20Sopenharmony_ci			return ret;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, 0, max/2);
10208c2ecf20Sopenharmony_ci		if (ret)
10218c2ecf20Sopenharmony_ci			return ret;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, max/2, max);
10248c2ecf20Sopenharmony_ci		if (ret)
10258c2ecf20Sopenharmony_ci			return ret;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci		ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1);
10288c2ecf20Sopenharmony_ci		if (ret)
10298c2ecf20Sopenharmony_ci			return ret;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci		cond_resched();
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	return 0;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic int prepare_igt_frag(struct drm_mm *mm,
10388c2ecf20Sopenharmony_ci			    struct drm_mm_node *nodes,
10398c2ecf20Sopenharmony_ci			    unsigned int num_insert,
10408c2ecf20Sopenharmony_ci			    const struct insert_mode *mode)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	unsigned int size = 4096;
10438c2ecf20Sopenharmony_ci	unsigned int i;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	for (i = 0; i < num_insert; i++) {
10468c2ecf20Sopenharmony_ci		if (!expect_insert(mm, &nodes[i], size, 0, i,
10478c2ecf20Sopenharmony_ci				   mode) != 0) {
10488c2ecf20Sopenharmony_ci			pr_err("%s insert failed\n", mode->name);
10498c2ecf20Sopenharmony_ci			return -EINVAL;
10508c2ecf20Sopenharmony_ci		}
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* introduce fragmentation by freeing every other node */
10548c2ecf20Sopenharmony_ci	for (i = 0; i < num_insert; i++) {
10558c2ecf20Sopenharmony_ci		if (i % 2 == 0)
10568c2ecf20Sopenharmony_ci			drm_mm_remove_node(&nodes[i]);
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_cistatic u64 get_insert_time(struct drm_mm *mm,
10648c2ecf20Sopenharmony_ci			   unsigned int num_insert,
10658c2ecf20Sopenharmony_ci			   struct drm_mm_node *nodes,
10668c2ecf20Sopenharmony_ci			   const struct insert_mode *mode)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	unsigned int size = 8192;
10698c2ecf20Sopenharmony_ci	ktime_t start;
10708c2ecf20Sopenharmony_ci	unsigned int i;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	start = ktime_get();
10738c2ecf20Sopenharmony_ci	for (i = 0; i < num_insert; i++) {
10748c2ecf20Sopenharmony_ci		if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) {
10758c2ecf20Sopenharmony_ci			pr_err("%s insert failed\n", mode->name);
10768c2ecf20Sopenharmony_ci			return 0;
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return ktime_to_ns(ktime_sub(ktime_get(), start));
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic int igt_frag(void *ignored)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct drm_mm mm;
10868c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
10878c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
10888c2ecf20Sopenharmony_ci	unsigned int insert_size = 10000;
10898c2ecf20Sopenharmony_ci	unsigned int scale_factor = 4;
10908c2ecf20Sopenharmony_ci	int ret = -EINVAL;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	/* We need 4 * insert_size nodes to hold intermediate allocated
10938c2ecf20Sopenharmony_ci	 * drm_mm nodes.
10948c2ecf20Sopenharmony_ci	 * 1 times for prepare_igt_frag()
10958c2ecf20Sopenharmony_ci	 * 1 times for get_insert_time()
10968c2ecf20Sopenharmony_ci	 * 2 times for get_insert_time()
10978c2ecf20Sopenharmony_ci	 */
10988c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes)));
10998c2ecf20Sopenharmony_ci	if (!nodes)
11008c2ecf20Sopenharmony_ci		return -ENOMEM;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	/* For BOTTOMUP and TOPDOWN, we first fragment the
11038c2ecf20Sopenharmony_ci	 * address space using prepare_igt_frag() and then try to verify
11048c2ecf20Sopenharmony_ci	 * that that insertions scale quadratically from 10k to 20k insertions
11058c2ecf20Sopenharmony_ci	 */
11068c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 1, U64_MAX - 2);
11078c2ecf20Sopenharmony_ci	for (mode = insert_modes; mode->name; mode++) {
11088c2ecf20Sopenharmony_ci		u64 insert_time1, insert_time2;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci		if (mode->mode != DRM_MM_INSERT_LOW &&
11118c2ecf20Sopenharmony_ci		    mode->mode != DRM_MM_INSERT_HIGH)
11128c2ecf20Sopenharmony_ci			continue;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		ret = prepare_igt_frag(&mm, nodes, insert_size, mode);
11158c2ecf20Sopenharmony_ci		if (ret)
11168c2ecf20Sopenharmony_ci			goto err;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		insert_time1 = get_insert_time(&mm, insert_size,
11198c2ecf20Sopenharmony_ci					       nodes + insert_size, mode);
11208c2ecf20Sopenharmony_ci		if (insert_time1 == 0)
11218c2ecf20Sopenharmony_ci			goto err;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci		insert_time2 = get_insert_time(&mm, (insert_size * 2),
11248c2ecf20Sopenharmony_ci					       nodes + insert_size * 2, mode);
11258c2ecf20Sopenharmony_ci		if (insert_time2 == 0)
11268c2ecf20Sopenharmony_ci			goto err;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci		pr_info("%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n",
11298c2ecf20Sopenharmony_ci			mode->name, insert_size, insert_size * 2,
11308c2ecf20Sopenharmony_ci			insert_time1, insert_time2);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		if (insert_time2 > (scale_factor * insert_time1)) {
11338c2ecf20Sopenharmony_ci			pr_err("%s fragmented insert took %llu nsecs more\n",
11348c2ecf20Sopenharmony_ci			       mode->name,
11358c2ecf20Sopenharmony_ci			       insert_time2 - (scale_factor * insert_time1));
11368c2ecf20Sopenharmony_ci			goto err;
11378c2ecf20Sopenharmony_ci		}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
11408c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
11418c2ecf20Sopenharmony_ci	}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	ret = 0;
11448c2ecf20Sopenharmony_cierr:
11458c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
11468c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
11478c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
11488c2ecf20Sopenharmony_ci	vfree(nodes);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	return ret;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic int igt_align(void *ignored)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
11568c2ecf20Sopenharmony_ci	const unsigned int max_count = min(8192u, max_prime);
11578c2ecf20Sopenharmony_ci	struct drm_mm mm;
11588c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
11598c2ecf20Sopenharmony_ci	unsigned int prime;
11608c2ecf20Sopenharmony_ci	int ret = -EINVAL;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/* For each of the possible insertion modes, we pick a few
11638c2ecf20Sopenharmony_ci	 * arbitrary alignments and check that the inserted node
11648c2ecf20Sopenharmony_ci	 * meets our requirements.
11658c2ecf20Sopenharmony_ci	 */
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(max_count, sizeof(*nodes)));
11688c2ecf20Sopenharmony_ci	if (!nodes)
11698c2ecf20Sopenharmony_ci		goto err;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 1, U64_MAX - 2);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	for (mode = insert_modes; mode->name; mode++) {
11748c2ecf20Sopenharmony_ci		unsigned int i = 0;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci		for_each_prime_number_from(prime, 1, max_count) {
11778c2ecf20Sopenharmony_ci			u64 size = next_prime_number(prime);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, &nodes[i],
11808c2ecf20Sopenharmony_ci					   size, prime, i,
11818c2ecf20Sopenharmony_ci					   mode)) {
11828c2ecf20Sopenharmony_ci				pr_err("%s insert failed with alignment=%d",
11838c2ecf20Sopenharmony_ci				       mode->name, prime);
11848c2ecf20Sopenharmony_ci				goto out;
11858c2ecf20Sopenharmony_ci			}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci			i++;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
11918c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
11928c2ecf20Sopenharmony_ci		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci		cond_resched();
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	ret = 0;
11988c2ecf20Sopenharmony_ciout:
11998c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
12008c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
12018c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
12028c2ecf20Sopenharmony_ci	vfree(nodes);
12038c2ecf20Sopenharmony_cierr:
12048c2ecf20Sopenharmony_ci	return ret;
12058c2ecf20Sopenharmony_ci}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_cistatic int igt_align_pot(int max)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	struct drm_mm mm;
12108c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *next;
12118c2ecf20Sopenharmony_ci	int bit;
12128c2ecf20Sopenharmony_ci	int ret = -EINVAL;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	/* Check that we can align to the full u64 address space */
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 1, U64_MAX - 2);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	for (bit = max - 1; bit; bit--) {
12198c2ecf20Sopenharmony_ci		u64 align, size;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		node = kzalloc(sizeof(*node), GFP_KERNEL);
12228c2ecf20Sopenharmony_ci		if (!node) {
12238c2ecf20Sopenharmony_ci			ret = -ENOMEM;
12248c2ecf20Sopenharmony_ci			goto out;
12258c2ecf20Sopenharmony_ci		}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci		align = BIT_ULL(bit);
12288c2ecf20Sopenharmony_ci		size = BIT_ULL(bit-1) + 1;
12298c2ecf20Sopenharmony_ci		if (!expect_insert(&mm, node,
12308c2ecf20Sopenharmony_ci				   size, align, bit,
12318c2ecf20Sopenharmony_ci				   &insert_modes[0])) {
12328c2ecf20Sopenharmony_ci			pr_err("insert failed with alignment=%llx [%d]",
12338c2ecf20Sopenharmony_ci			       align, bit);
12348c2ecf20Sopenharmony_ci			goto out;
12358c2ecf20Sopenharmony_ci		}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		cond_resched();
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	ret = 0;
12418c2ecf20Sopenharmony_ciout:
12428c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm) {
12438c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
12448c2ecf20Sopenharmony_ci		kfree(node);
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
12478c2ecf20Sopenharmony_ci	return ret;
12488c2ecf20Sopenharmony_ci}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_cistatic int igt_align32(void *ignored)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	return igt_align_pot(32);
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_cistatic int igt_align64(void *ignored)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	return igt_align_pot(64);
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic void show_scan(const struct drm_mm_scan *scan)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	pr_info("scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n",
12638c2ecf20Sopenharmony_ci		scan->hit_start, scan->hit_end,
12648c2ecf20Sopenharmony_ci		scan->size, scan->alignment, scan->color);
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic void show_holes(const struct drm_mm *mm, int count)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	u64 hole_start, hole_end;
12708c2ecf20Sopenharmony_ci	struct drm_mm_node *hole;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
12738c2ecf20Sopenharmony_ci		struct drm_mm_node *next = list_next_entry(hole, node_list);
12748c2ecf20Sopenharmony_ci		const char *node1 = NULL, *node2 = NULL;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci		if (drm_mm_node_allocated(hole))
12778c2ecf20Sopenharmony_ci			node1 = kasprintf(GFP_KERNEL,
12788c2ecf20Sopenharmony_ci					  "[%llx + %lld, color=%ld], ",
12798c2ecf20Sopenharmony_ci					  hole->start, hole->size, hole->color);
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci		if (drm_mm_node_allocated(next))
12828c2ecf20Sopenharmony_ci			node2 = kasprintf(GFP_KERNEL,
12838c2ecf20Sopenharmony_ci					  ", [%llx + %lld, color=%ld]",
12848c2ecf20Sopenharmony_ci					  next->start, next->size, next->color);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		pr_info("%sHole [%llx - %llx, size %lld]%s\n",
12878c2ecf20Sopenharmony_ci			node1,
12888c2ecf20Sopenharmony_ci			hole_start, hole_end, hole_end - hole_start,
12898c2ecf20Sopenharmony_ci			node2);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		kfree(node2);
12928c2ecf20Sopenharmony_ci		kfree(node1);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		if (!--count)
12958c2ecf20Sopenharmony_ci			break;
12968c2ecf20Sopenharmony_ci	}
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cistruct evict_node {
13008c2ecf20Sopenharmony_ci	struct drm_mm_node node;
13018c2ecf20Sopenharmony_ci	struct list_head link;
13028c2ecf20Sopenharmony_ci};
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic bool evict_nodes(struct drm_mm_scan *scan,
13058c2ecf20Sopenharmony_ci			struct evict_node *nodes,
13068c2ecf20Sopenharmony_ci			unsigned int *order,
13078c2ecf20Sopenharmony_ci			unsigned int count,
13088c2ecf20Sopenharmony_ci			bool use_color,
13098c2ecf20Sopenharmony_ci			struct list_head *evict_list)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	struct evict_node *e, *en;
13128c2ecf20Sopenharmony_ci	unsigned int i;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
13158c2ecf20Sopenharmony_ci		e = &nodes[order ? order[i] : i];
13168c2ecf20Sopenharmony_ci		list_add(&e->link, evict_list);
13178c2ecf20Sopenharmony_ci		if (drm_mm_scan_add_block(scan, &e->node))
13188c2ecf20Sopenharmony_ci			break;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci	list_for_each_entry_safe(e, en, evict_list, link) {
13218c2ecf20Sopenharmony_ci		if (!drm_mm_scan_remove_block(scan, &e->node))
13228c2ecf20Sopenharmony_ci			list_del(&e->link);
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci	if (list_empty(evict_list)) {
13258c2ecf20Sopenharmony_ci		pr_err("Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n",
13268c2ecf20Sopenharmony_ci		       scan->size, count, scan->alignment, scan->color);
13278c2ecf20Sopenharmony_ci		return false;
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	list_for_each_entry(e, evict_list, link)
13318c2ecf20Sopenharmony_ci		drm_mm_remove_node(&e->node);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (use_color) {
13348c2ecf20Sopenharmony_ci		struct drm_mm_node *node;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci		while ((node = drm_mm_scan_color_evict(scan))) {
13378c2ecf20Sopenharmony_ci			e = container_of(node, typeof(*e), node);
13388c2ecf20Sopenharmony_ci			drm_mm_remove_node(&e->node);
13398c2ecf20Sopenharmony_ci			list_add(&e->link, evict_list);
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci	} else {
13428c2ecf20Sopenharmony_ci		if (drm_mm_scan_color_evict(scan)) {
13438c2ecf20Sopenharmony_ci			pr_err("drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n");
13448c2ecf20Sopenharmony_ci			return false;
13458c2ecf20Sopenharmony_ci		}
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	return true;
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic bool evict_nothing(struct drm_mm *mm,
13528c2ecf20Sopenharmony_ci			  unsigned int total_size,
13538c2ecf20Sopenharmony_ci			  struct evict_node *nodes)
13548c2ecf20Sopenharmony_ci{
13558c2ecf20Sopenharmony_ci	struct drm_mm_scan scan;
13568c2ecf20Sopenharmony_ci	LIST_HEAD(evict_list);
13578c2ecf20Sopenharmony_ci	struct evict_node *e;
13588c2ecf20Sopenharmony_ci	struct drm_mm_node *node;
13598c2ecf20Sopenharmony_ci	unsigned int n;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	drm_mm_scan_init(&scan, mm, 1, 0, 0, 0);
13628c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
13638c2ecf20Sopenharmony_ci		e = &nodes[n];
13648c2ecf20Sopenharmony_ci		list_add(&e->link, &evict_list);
13658c2ecf20Sopenharmony_ci		drm_mm_scan_add_block(&scan, &e->node);
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link)
13688c2ecf20Sopenharmony_ci		drm_mm_scan_remove_block(&scan, &e->node);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
13718c2ecf20Sopenharmony_ci		e = &nodes[n];
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci		if (!drm_mm_node_allocated(&e->node)) {
13748c2ecf20Sopenharmony_ci			pr_err("node[%d] no longer allocated!\n", n);
13758c2ecf20Sopenharmony_ci			return false;
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		e->link.next = NULL;
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	drm_mm_for_each_node(node, mm) {
13828c2ecf20Sopenharmony_ci		e = container_of(node, typeof(*e), node);
13838c2ecf20Sopenharmony_ci		e->link.next = &e->link;
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
13878c2ecf20Sopenharmony_ci		e = &nodes[n];
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci		if (!e->link.next) {
13908c2ecf20Sopenharmony_ci			pr_err("node[%d] no longer connected!\n", n);
13918c2ecf20Sopenharmony_ci			return false;
13928c2ecf20Sopenharmony_ci		}
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	return assert_continuous(mm, nodes[0].node.size);
13968c2ecf20Sopenharmony_ci}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_cistatic bool evict_everything(struct drm_mm *mm,
13998c2ecf20Sopenharmony_ci			     unsigned int total_size,
14008c2ecf20Sopenharmony_ci			     struct evict_node *nodes)
14018c2ecf20Sopenharmony_ci{
14028c2ecf20Sopenharmony_ci	struct drm_mm_scan scan;
14038c2ecf20Sopenharmony_ci	LIST_HEAD(evict_list);
14048c2ecf20Sopenharmony_ci	struct evict_node *e;
14058c2ecf20Sopenharmony_ci	unsigned int n;
14068c2ecf20Sopenharmony_ci	int err;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0);
14098c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
14108c2ecf20Sopenharmony_ci		e = &nodes[n];
14118c2ecf20Sopenharmony_ci		list_add(&e->link, &evict_list);
14128c2ecf20Sopenharmony_ci		if (drm_mm_scan_add_block(&scan, &e->node))
14138c2ecf20Sopenharmony_ci			break;
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	err = 0;
14178c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link) {
14188c2ecf20Sopenharmony_ci		if (!drm_mm_scan_remove_block(&scan, &e->node)) {
14198c2ecf20Sopenharmony_ci			if (!err) {
14208c2ecf20Sopenharmony_ci				pr_err("Node %lld not marked for eviction!\n",
14218c2ecf20Sopenharmony_ci				       e->node.start);
14228c2ecf20Sopenharmony_ci				err = -EINVAL;
14238c2ecf20Sopenharmony_ci			}
14248c2ecf20Sopenharmony_ci		}
14258c2ecf20Sopenharmony_ci	}
14268c2ecf20Sopenharmony_ci	if (err)
14278c2ecf20Sopenharmony_ci		return false;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link)
14308c2ecf20Sopenharmony_ci		drm_mm_remove_node(&e->node);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	if (!assert_one_hole(mm, 0, total_size))
14338c2ecf20Sopenharmony_ci		return false;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link) {
14368c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(mm, &e->node);
14378c2ecf20Sopenharmony_ci		if (err) {
14388c2ecf20Sopenharmony_ci			pr_err("Failed to reinsert node after eviction: start=%llx\n",
14398c2ecf20Sopenharmony_ci			       e->node.start);
14408c2ecf20Sopenharmony_ci			return false;
14418c2ecf20Sopenharmony_ci		}
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	return assert_continuous(mm, nodes[0].node.size);
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_cistatic int evict_something(struct drm_mm *mm,
14488c2ecf20Sopenharmony_ci			   u64 range_start, u64 range_end,
14498c2ecf20Sopenharmony_ci			   struct evict_node *nodes,
14508c2ecf20Sopenharmony_ci			   unsigned int *order,
14518c2ecf20Sopenharmony_ci			   unsigned int count,
14528c2ecf20Sopenharmony_ci			   unsigned int size,
14538c2ecf20Sopenharmony_ci			   unsigned int alignment,
14548c2ecf20Sopenharmony_ci			   const struct insert_mode *mode)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	struct drm_mm_scan scan;
14578c2ecf20Sopenharmony_ci	LIST_HEAD(evict_list);
14588c2ecf20Sopenharmony_ci	struct evict_node *e;
14598c2ecf20Sopenharmony_ci	struct drm_mm_node tmp;
14608c2ecf20Sopenharmony_ci	int err;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	drm_mm_scan_init_with_range(&scan, mm,
14638c2ecf20Sopenharmony_ci				    size, alignment, 0,
14648c2ecf20Sopenharmony_ci				    range_start, range_end,
14658c2ecf20Sopenharmony_ci				    mode->mode);
14668c2ecf20Sopenharmony_ci	if (!evict_nodes(&scan,
14678c2ecf20Sopenharmony_ci			 nodes, order, count, false,
14688c2ecf20Sopenharmony_ci			 &evict_list))
14698c2ecf20Sopenharmony_ci		return -EINVAL;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	memset(&tmp, 0, sizeof(tmp));
14728c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0,
14738c2ecf20Sopenharmony_ci					 DRM_MM_INSERT_EVICT);
14748c2ecf20Sopenharmony_ci	if (err) {
14758c2ecf20Sopenharmony_ci		pr_err("Failed to insert into eviction hole: size=%d, align=%d\n",
14768c2ecf20Sopenharmony_ci		       size, alignment);
14778c2ecf20Sopenharmony_ci		show_scan(&scan);
14788c2ecf20Sopenharmony_ci		show_holes(mm, 3);
14798c2ecf20Sopenharmony_ci		return err;
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
14838c2ecf20Sopenharmony_ci		pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
14848c2ecf20Sopenharmony_ci		       tmp.start, tmp.size, range_start, range_end);
14858c2ecf20Sopenharmony_ci		err = -EINVAL;
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (!assert_node(&tmp, mm, size, alignment, 0) ||
14898c2ecf20Sopenharmony_ci	    drm_mm_hole_follows(&tmp)) {
14908c2ecf20Sopenharmony_ci		pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n",
14918c2ecf20Sopenharmony_ci		       tmp.size, size,
14928c2ecf20Sopenharmony_ci		       alignment, misalignment(&tmp, alignment),
14938c2ecf20Sopenharmony_ci		       tmp.start, drm_mm_hole_follows(&tmp));
14948c2ecf20Sopenharmony_ci		err = -EINVAL;
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	drm_mm_remove_node(&tmp);
14988c2ecf20Sopenharmony_ci	if (err)
14998c2ecf20Sopenharmony_ci		return err;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link) {
15028c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(mm, &e->node);
15038c2ecf20Sopenharmony_ci		if (err) {
15048c2ecf20Sopenharmony_ci			pr_err("Failed to reinsert node after eviction: start=%llx\n",
15058c2ecf20Sopenharmony_ci			       e->node.start);
15068c2ecf20Sopenharmony_ci			return err;
15078c2ecf20Sopenharmony_ci		}
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	if (!assert_continuous(mm, nodes[0].node.size)) {
15118c2ecf20Sopenharmony_ci		pr_err("range is no longer continuous\n");
15128c2ecf20Sopenharmony_ci		return -EINVAL;
15138c2ecf20Sopenharmony_ci	}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	return 0;
15168c2ecf20Sopenharmony_ci}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_cistatic int igt_evict(void *ignored)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
15218c2ecf20Sopenharmony_ci	const unsigned int size = 8192;
15228c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
15238c2ecf20Sopenharmony_ci	struct drm_mm mm;
15248c2ecf20Sopenharmony_ci	struct evict_node *nodes;
15258c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *next;
15268c2ecf20Sopenharmony_ci	unsigned int *order, n;
15278c2ecf20Sopenharmony_ci	int ret, err;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	/* Here we populate a full drm_mm and then try and insert a new node
15308c2ecf20Sopenharmony_ci	 * by evicting other nodes in a random order. The drm_mm_scan should
15318c2ecf20Sopenharmony_ci	 * pick the first matching hole it finds from the random list. We
15328c2ecf20Sopenharmony_ci	 * repeat that for different allocation strategies, alignments and
15338c2ecf20Sopenharmony_ci	 * sizes to try and stress the hole finder.
15348c2ecf20Sopenharmony_ci	 */
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	ret = -ENOMEM;
15378c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(size, sizeof(*nodes)));
15388c2ecf20Sopenharmony_ci	if (!nodes)
15398c2ecf20Sopenharmony_ci		goto err;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	order = drm_random_order(size, &prng);
15428c2ecf20Sopenharmony_ci	if (!order)
15438c2ecf20Sopenharmony_ci		goto err_nodes;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	ret = -EINVAL;
15468c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, size);
15478c2ecf20Sopenharmony_ci	for (n = 0; n < size; n++) {
15488c2ecf20Sopenharmony_ci		err = drm_mm_insert_node(&mm, &nodes[n].node, 1);
15498c2ecf20Sopenharmony_ci		if (err) {
15508c2ecf20Sopenharmony_ci			pr_err("insert failed, step %d\n", n);
15518c2ecf20Sopenharmony_ci			ret = err;
15528c2ecf20Sopenharmony_ci			goto out;
15538c2ecf20Sopenharmony_ci		}
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	/* First check that using the scanner doesn't break the mm */
15578c2ecf20Sopenharmony_ci	if (!evict_nothing(&mm, size, nodes)) {
15588c2ecf20Sopenharmony_ci		pr_err("evict_nothing() failed\n");
15598c2ecf20Sopenharmony_ci		goto out;
15608c2ecf20Sopenharmony_ci	}
15618c2ecf20Sopenharmony_ci	if (!evict_everything(&mm, size, nodes)) {
15628c2ecf20Sopenharmony_ci		pr_err("evict_everything() failed\n");
15638c2ecf20Sopenharmony_ci		goto out;
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	for (mode = evict_modes; mode->name; mode++) {
15678c2ecf20Sopenharmony_ci		for (n = 1; n <= size; n <<= 1) {
15688c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
15698c2ecf20Sopenharmony_ci			err = evict_something(&mm, 0, U64_MAX,
15708c2ecf20Sopenharmony_ci					      nodes, order, size,
15718c2ecf20Sopenharmony_ci					      n, 1,
15728c2ecf20Sopenharmony_ci					      mode);
15738c2ecf20Sopenharmony_ci			if (err) {
15748c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u) failed\n",
15758c2ecf20Sopenharmony_ci				       mode->name, n);
15768c2ecf20Sopenharmony_ci				ret = err;
15778c2ecf20Sopenharmony_ci				goto out;
15788c2ecf20Sopenharmony_ci			}
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		for (n = 1; n < size; n <<= 1) {
15828c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
15838c2ecf20Sopenharmony_ci			err = evict_something(&mm, 0, U64_MAX,
15848c2ecf20Sopenharmony_ci					      nodes, order, size,
15858c2ecf20Sopenharmony_ci					      size/2, n,
15868c2ecf20Sopenharmony_ci					      mode);
15878c2ecf20Sopenharmony_ci			if (err) {
15888c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
15898c2ecf20Sopenharmony_ci				       mode->name, size/2, n);
15908c2ecf20Sopenharmony_ci				ret = err;
15918c2ecf20Sopenharmony_ci				goto out;
15928c2ecf20Sopenharmony_ci			}
15938c2ecf20Sopenharmony_ci		}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(size, max_prime)) {
15968c2ecf20Sopenharmony_ci			unsigned int nsize = (size - n + 1) / 2;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(!nsize);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
16018c2ecf20Sopenharmony_ci			err = evict_something(&mm, 0, U64_MAX,
16028c2ecf20Sopenharmony_ci					      nodes, order, size,
16038c2ecf20Sopenharmony_ci					      nsize, n,
16048c2ecf20Sopenharmony_ci					      mode);
16058c2ecf20Sopenharmony_ci			if (err) {
16068c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
16078c2ecf20Sopenharmony_ci				       mode->name, nsize, n);
16088c2ecf20Sopenharmony_ci				ret = err;
16098c2ecf20Sopenharmony_ci				goto out;
16108c2ecf20Sopenharmony_ci			}
16118c2ecf20Sopenharmony_ci		}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci		cond_resched();
16148c2ecf20Sopenharmony_ci	}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	ret = 0;
16178c2ecf20Sopenharmony_ciout:
16188c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
16198c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
16208c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
16218c2ecf20Sopenharmony_ci	kfree(order);
16228c2ecf20Sopenharmony_cierr_nodes:
16238c2ecf20Sopenharmony_ci	vfree(nodes);
16248c2ecf20Sopenharmony_cierr:
16258c2ecf20Sopenharmony_ci	return ret;
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic int igt_evict_range(void *ignored)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
16318c2ecf20Sopenharmony_ci	const unsigned int size = 8192;
16328c2ecf20Sopenharmony_ci	const unsigned int range_size = size / 2;
16338c2ecf20Sopenharmony_ci	const unsigned int range_start = size / 4;
16348c2ecf20Sopenharmony_ci	const unsigned int range_end = range_start + range_size;
16358c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
16368c2ecf20Sopenharmony_ci	struct drm_mm mm;
16378c2ecf20Sopenharmony_ci	struct evict_node *nodes;
16388c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *next;
16398c2ecf20Sopenharmony_ci	unsigned int *order, n;
16408c2ecf20Sopenharmony_ci	int ret, err;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	/* Like igt_evict() but now we are limiting the search to a
16438c2ecf20Sopenharmony_ci	 * small portion of the full drm_mm.
16448c2ecf20Sopenharmony_ci	 */
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	ret = -ENOMEM;
16478c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(size, sizeof(*nodes)));
16488c2ecf20Sopenharmony_ci	if (!nodes)
16498c2ecf20Sopenharmony_ci		goto err;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	order = drm_random_order(size, &prng);
16528c2ecf20Sopenharmony_ci	if (!order)
16538c2ecf20Sopenharmony_ci		goto err_nodes;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	ret = -EINVAL;
16568c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, size);
16578c2ecf20Sopenharmony_ci	for (n = 0; n < size; n++) {
16588c2ecf20Sopenharmony_ci		err = drm_mm_insert_node(&mm, &nodes[n].node, 1);
16598c2ecf20Sopenharmony_ci		if (err) {
16608c2ecf20Sopenharmony_ci			pr_err("insert failed, step %d\n", n);
16618c2ecf20Sopenharmony_ci			ret = err;
16628c2ecf20Sopenharmony_ci			goto out;
16638c2ecf20Sopenharmony_ci		}
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	for (mode = evict_modes; mode->name; mode++) {
16678c2ecf20Sopenharmony_ci		for (n = 1; n <= range_size; n <<= 1) {
16688c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
16698c2ecf20Sopenharmony_ci			err = evict_something(&mm, range_start, range_end,
16708c2ecf20Sopenharmony_ci					      nodes, order, size,
16718c2ecf20Sopenharmony_ci					      n, 1,
16728c2ecf20Sopenharmony_ci					      mode);
16738c2ecf20Sopenharmony_ci			if (err) {
16748c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n",
16758c2ecf20Sopenharmony_ci				       mode->name, n, range_start, range_end);
16768c2ecf20Sopenharmony_ci				goto out;
16778c2ecf20Sopenharmony_ci			}
16788c2ecf20Sopenharmony_ci		}
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci		for (n = 1; n <= range_size; n <<= 1) {
16818c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
16828c2ecf20Sopenharmony_ci			err = evict_something(&mm, range_start, range_end,
16838c2ecf20Sopenharmony_ci					      nodes, order, size,
16848c2ecf20Sopenharmony_ci					      range_size/2, n,
16858c2ecf20Sopenharmony_ci					      mode);
16868c2ecf20Sopenharmony_ci			if (err) {
16878c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
16888c2ecf20Sopenharmony_ci				       mode->name, range_size/2, n, range_start, range_end);
16898c2ecf20Sopenharmony_ci				goto out;
16908c2ecf20Sopenharmony_ci			}
16918c2ecf20Sopenharmony_ci		}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
16948c2ecf20Sopenharmony_ci			unsigned int nsize = (range_size - n + 1) / 2;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(!nsize);
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci			drm_random_reorder(order, size, &prng);
16998c2ecf20Sopenharmony_ci			err = evict_something(&mm, range_start, range_end,
17008c2ecf20Sopenharmony_ci					      nodes, order, size,
17018c2ecf20Sopenharmony_ci					      nsize, n,
17028c2ecf20Sopenharmony_ci					      mode);
17038c2ecf20Sopenharmony_ci			if (err) {
17048c2ecf20Sopenharmony_ci				pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
17058c2ecf20Sopenharmony_ci				       mode->name, nsize, n, range_start, range_end);
17068c2ecf20Sopenharmony_ci				goto out;
17078c2ecf20Sopenharmony_ci			}
17088c2ecf20Sopenharmony_ci		}
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci		cond_resched();
17118c2ecf20Sopenharmony_ci	}
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	ret = 0;
17148c2ecf20Sopenharmony_ciout:
17158c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
17168c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
17178c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
17188c2ecf20Sopenharmony_ci	kfree(order);
17198c2ecf20Sopenharmony_cierr_nodes:
17208c2ecf20Sopenharmony_ci	vfree(nodes);
17218c2ecf20Sopenharmony_cierr:
17228c2ecf20Sopenharmony_ci	return ret;
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic unsigned int node_index(const struct drm_mm_node *node)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	return div64_u64(node->start, node->size);
17288c2ecf20Sopenharmony_ci}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_cistatic int igt_topdown(void *ignored)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	const struct insert_mode *topdown = &insert_modes[TOPDOWN];
17338c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
17348c2ecf20Sopenharmony_ci	const unsigned int count = 8192;
17358c2ecf20Sopenharmony_ci	unsigned int size;
17368c2ecf20Sopenharmony_ci	unsigned long *bitmap;
17378c2ecf20Sopenharmony_ci	struct drm_mm mm;
17388c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
17398c2ecf20Sopenharmony_ci	unsigned int *order, n, m, o = 0;
17408c2ecf20Sopenharmony_ci	int ret;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	/* When allocating top-down, we expect to be returned a node
17438c2ecf20Sopenharmony_ci	 * from a suitable hole at the top of the drm_mm. We check that
17448c2ecf20Sopenharmony_ci	 * the returned node does match the highest available slot.
17458c2ecf20Sopenharmony_ci	 */
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	ret = -ENOMEM;
17488c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(count, sizeof(*nodes)));
17498c2ecf20Sopenharmony_ci	if (!nodes)
17508c2ecf20Sopenharmony_ci		goto err;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	bitmap = bitmap_zalloc(count, GFP_KERNEL);
17538c2ecf20Sopenharmony_ci	if (!bitmap)
17548c2ecf20Sopenharmony_ci		goto err_nodes;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	order = drm_random_order(count, &prng);
17578c2ecf20Sopenharmony_ci	if (!order)
17588c2ecf20Sopenharmony_ci		goto err_bitmap;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	ret = -EINVAL;
17618c2ecf20Sopenharmony_ci	for (size = 1; size <= 64; size <<= 1) {
17628c2ecf20Sopenharmony_ci		drm_mm_init(&mm, 0, size*count);
17638c2ecf20Sopenharmony_ci		for (n = 0; n < count; n++) {
17648c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, &nodes[n],
17658c2ecf20Sopenharmony_ci					   size, 0, n,
17668c2ecf20Sopenharmony_ci					   topdown)) {
17678c2ecf20Sopenharmony_ci				pr_err("insert failed, size %u step %d\n", size, n);
17688c2ecf20Sopenharmony_ci				goto out;
17698c2ecf20Sopenharmony_ci			}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci			if (drm_mm_hole_follows(&nodes[n])) {
17728c2ecf20Sopenharmony_ci				pr_err("hole after topdown insert %d, start=%llx\n, size=%u",
17738c2ecf20Sopenharmony_ci				       n, nodes[n].start, size);
17748c2ecf20Sopenharmony_ci				goto out;
17758c2ecf20Sopenharmony_ci			}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci			if (!assert_one_hole(&mm, 0, size*(count - n - 1)))
17788c2ecf20Sopenharmony_ci				goto out;
17798c2ecf20Sopenharmony_ci		}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci		if (!assert_continuous(&mm, size))
17828c2ecf20Sopenharmony_ci			goto out;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci		drm_random_reorder(order, count, &prng);
17858c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(count, max_prime)) {
17868c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
17878c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
17888c2ecf20Sopenharmony_ci				drm_mm_remove_node(node);
17898c2ecf20Sopenharmony_ci				__set_bit(node_index(node), bitmap);
17908c2ecf20Sopenharmony_ci			}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
17938c2ecf20Sopenharmony_ci				unsigned int last;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
17968c2ecf20Sopenharmony_ci				if (!expect_insert(&mm, node,
17978c2ecf20Sopenharmony_ci						   size, 0, 0,
17988c2ecf20Sopenharmony_ci						   topdown)) {
17998c2ecf20Sopenharmony_ci					pr_err("insert failed, step %d/%d\n", m, n);
18008c2ecf20Sopenharmony_ci					goto out;
18018c2ecf20Sopenharmony_ci				}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci				if (drm_mm_hole_follows(node)) {
18048c2ecf20Sopenharmony_ci					pr_err("hole after topdown insert %d/%d, start=%llx\n",
18058c2ecf20Sopenharmony_ci					       m, n, node->start);
18068c2ecf20Sopenharmony_ci					goto out;
18078c2ecf20Sopenharmony_ci				}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci				last = find_last_bit(bitmap, count);
18108c2ecf20Sopenharmony_ci				if (node_index(node) != last) {
18118c2ecf20Sopenharmony_ci					pr_err("node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n",
18128c2ecf20Sopenharmony_ci					       m, n, size, last, node_index(node));
18138c2ecf20Sopenharmony_ci					goto out;
18148c2ecf20Sopenharmony_ci				}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci				__clear_bit(last, bitmap);
18178c2ecf20Sopenharmony_ci			}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci			o += n;
18228c2ecf20Sopenharmony_ci		}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
18258c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
18268c2ecf20Sopenharmony_ci		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
18278c2ecf20Sopenharmony_ci		cond_resched();
18288c2ecf20Sopenharmony_ci	}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	ret = 0;
18318c2ecf20Sopenharmony_ciout:
18328c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
18338c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
18348c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
18358c2ecf20Sopenharmony_ci	kfree(order);
18368c2ecf20Sopenharmony_cierr_bitmap:
18378c2ecf20Sopenharmony_ci	bitmap_free(bitmap);
18388c2ecf20Sopenharmony_cierr_nodes:
18398c2ecf20Sopenharmony_ci	vfree(nodes);
18408c2ecf20Sopenharmony_cierr:
18418c2ecf20Sopenharmony_ci	return ret;
18428c2ecf20Sopenharmony_ci}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_cistatic int igt_bottomup(void *ignored)
18458c2ecf20Sopenharmony_ci{
18468c2ecf20Sopenharmony_ci	const struct insert_mode *bottomup = &insert_modes[BOTTOMUP];
18478c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
18488c2ecf20Sopenharmony_ci	const unsigned int count = 8192;
18498c2ecf20Sopenharmony_ci	unsigned int size;
18508c2ecf20Sopenharmony_ci	unsigned long *bitmap;
18518c2ecf20Sopenharmony_ci	struct drm_mm mm;
18528c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes, *node, *next;
18538c2ecf20Sopenharmony_ci	unsigned int *order, n, m, o = 0;
18548c2ecf20Sopenharmony_ci	int ret;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	/* Like igt_topdown, but instead of searching for the last hole,
18578c2ecf20Sopenharmony_ci	 * we search for the first.
18588c2ecf20Sopenharmony_ci	 */
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	ret = -ENOMEM;
18618c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(count, sizeof(*nodes)));
18628c2ecf20Sopenharmony_ci	if (!nodes)
18638c2ecf20Sopenharmony_ci		goto err;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	bitmap = bitmap_zalloc(count, GFP_KERNEL);
18668c2ecf20Sopenharmony_ci	if (!bitmap)
18678c2ecf20Sopenharmony_ci		goto err_nodes;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	order = drm_random_order(count, &prng);
18708c2ecf20Sopenharmony_ci	if (!order)
18718c2ecf20Sopenharmony_ci		goto err_bitmap;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	ret = -EINVAL;
18748c2ecf20Sopenharmony_ci	for (size = 1; size <= 64; size <<= 1) {
18758c2ecf20Sopenharmony_ci		drm_mm_init(&mm, 0, size*count);
18768c2ecf20Sopenharmony_ci		for (n = 0; n < count; n++) {
18778c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, &nodes[n],
18788c2ecf20Sopenharmony_ci					   size, 0, n,
18798c2ecf20Sopenharmony_ci					   bottomup)) {
18808c2ecf20Sopenharmony_ci				pr_err("bottomup insert failed, size %u step %d\n", size, n);
18818c2ecf20Sopenharmony_ci				goto out;
18828c2ecf20Sopenharmony_ci			}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci			if (!assert_one_hole(&mm, size*(n + 1), size*count))
18858c2ecf20Sopenharmony_ci				goto out;
18868c2ecf20Sopenharmony_ci		}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci		if (!assert_continuous(&mm, size))
18898c2ecf20Sopenharmony_ci			goto out;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci		drm_random_reorder(order, count, &prng);
18928c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(count, max_prime)) {
18938c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
18948c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
18958c2ecf20Sopenharmony_ci				drm_mm_remove_node(node);
18968c2ecf20Sopenharmony_ci				__set_bit(node_index(node), bitmap);
18978c2ecf20Sopenharmony_ci			}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci			for (m = 0; m < n; m++) {
19008c2ecf20Sopenharmony_ci				unsigned int first;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci				node = &nodes[order[(o + m) % count]];
19038c2ecf20Sopenharmony_ci				if (!expect_insert(&mm, node,
19048c2ecf20Sopenharmony_ci						   size, 0, 0,
19058c2ecf20Sopenharmony_ci						   bottomup)) {
19068c2ecf20Sopenharmony_ci					pr_err("insert failed, step %d/%d\n", m, n);
19078c2ecf20Sopenharmony_ci					goto out;
19088c2ecf20Sopenharmony_ci				}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci				first = find_first_bit(bitmap, count);
19118c2ecf20Sopenharmony_ci				if (node_index(node) != first) {
19128c2ecf20Sopenharmony_ci					pr_err("node %d/%d not inserted into bottom hole, expected %d, found %d\n",
19138c2ecf20Sopenharmony_ci					       m, n, first, node_index(node));
19148c2ecf20Sopenharmony_ci					goto out;
19158c2ecf20Sopenharmony_ci				}
19168c2ecf20Sopenharmony_ci				__clear_bit(first, bitmap);
19178c2ecf20Sopenharmony_ci			}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci			o += n;
19228c2ecf20Sopenharmony_ci		}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, next, &mm)
19258c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
19268c2ecf20Sopenharmony_ci		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
19278c2ecf20Sopenharmony_ci		cond_resched();
19288c2ecf20Sopenharmony_ci	}
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	ret = 0;
19318c2ecf20Sopenharmony_ciout:
19328c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
19338c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
19348c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
19358c2ecf20Sopenharmony_ci	kfree(order);
19368c2ecf20Sopenharmony_cierr_bitmap:
19378c2ecf20Sopenharmony_ci	bitmap_free(bitmap);
19388c2ecf20Sopenharmony_cierr_nodes:
19398c2ecf20Sopenharmony_ci	vfree(nodes);
19408c2ecf20Sopenharmony_cierr:
19418c2ecf20Sopenharmony_ci	return ret;
19428c2ecf20Sopenharmony_ci}
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_cistatic int __igt_once(unsigned int mode)
19458c2ecf20Sopenharmony_ci{
19468c2ecf20Sopenharmony_ci	struct drm_mm mm;
19478c2ecf20Sopenharmony_ci	struct drm_mm_node rsvd_lo, rsvd_hi, node;
19488c2ecf20Sopenharmony_ci	int err;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, 7);
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	memset(&rsvd_lo, 0, sizeof(rsvd_lo));
19538c2ecf20Sopenharmony_ci	rsvd_lo.start = 1;
19548c2ecf20Sopenharmony_ci	rsvd_lo.size = 1;
19558c2ecf20Sopenharmony_ci	err = drm_mm_reserve_node(&mm, &rsvd_lo);
19568c2ecf20Sopenharmony_ci	if (err) {
19578c2ecf20Sopenharmony_ci		pr_err("Could not reserve low node\n");
19588c2ecf20Sopenharmony_ci		goto err;
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	memset(&rsvd_hi, 0, sizeof(rsvd_hi));
19628c2ecf20Sopenharmony_ci	rsvd_hi.start = 5;
19638c2ecf20Sopenharmony_ci	rsvd_hi.size = 1;
19648c2ecf20Sopenharmony_ci	err = drm_mm_reserve_node(&mm, &rsvd_hi);
19658c2ecf20Sopenharmony_ci	if (err) {
19668c2ecf20Sopenharmony_ci		pr_err("Could not reserve low node\n");
19678c2ecf20Sopenharmony_ci		goto err_lo;
19688c2ecf20Sopenharmony_ci	}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) {
19718c2ecf20Sopenharmony_ci		pr_err("Expected a hole after lo and high nodes!\n");
19728c2ecf20Sopenharmony_ci		err = -EINVAL;
19738c2ecf20Sopenharmony_ci		goto err_hi;
19748c2ecf20Sopenharmony_ci	}
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	memset(&node, 0, sizeof(node));
19778c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode);
19788c2ecf20Sopenharmony_ci	if (err) {
19798c2ecf20Sopenharmony_ci		pr_err("Could not insert the node into the available hole!\n");
19808c2ecf20Sopenharmony_ci		err = -EINVAL;
19818c2ecf20Sopenharmony_ci		goto err_hi;
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	drm_mm_remove_node(&node);
19858c2ecf20Sopenharmony_cierr_hi:
19868c2ecf20Sopenharmony_ci	drm_mm_remove_node(&rsvd_hi);
19878c2ecf20Sopenharmony_cierr_lo:
19888c2ecf20Sopenharmony_ci	drm_mm_remove_node(&rsvd_lo);
19898c2ecf20Sopenharmony_cierr:
19908c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
19918c2ecf20Sopenharmony_ci	return err;
19928c2ecf20Sopenharmony_ci}
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_cistatic int igt_lowest(void *ignored)
19958c2ecf20Sopenharmony_ci{
19968c2ecf20Sopenharmony_ci	return __igt_once(DRM_MM_INSERT_LOW);
19978c2ecf20Sopenharmony_ci}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_cistatic int igt_highest(void *ignored)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci	return __igt_once(DRM_MM_INSERT_HIGH);
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_cistatic void separate_adjacent_colors(const struct drm_mm_node *node,
20058c2ecf20Sopenharmony_ci				     unsigned long color,
20068c2ecf20Sopenharmony_ci				     u64 *start,
20078c2ecf20Sopenharmony_ci				     u64 *end)
20088c2ecf20Sopenharmony_ci{
20098c2ecf20Sopenharmony_ci	if (drm_mm_node_allocated(node) && node->color != color)
20108c2ecf20Sopenharmony_ci		++*start;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	node = list_next_entry(node, node_list);
20138c2ecf20Sopenharmony_ci	if (drm_mm_node_allocated(node) && node->color != color)
20148c2ecf20Sopenharmony_ci		--*end;
20158c2ecf20Sopenharmony_ci}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_cistatic bool colors_abutt(const struct drm_mm_node *node)
20188c2ecf20Sopenharmony_ci{
20198c2ecf20Sopenharmony_ci	if (!drm_mm_hole_follows(node) &&
20208c2ecf20Sopenharmony_ci	    drm_mm_node_allocated(list_next_entry(node, node_list))) {
20218c2ecf20Sopenharmony_ci		pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n",
20228c2ecf20Sopenharmony_ci		       node->color, node->start, node->size,
20238c2ecf20Sopenharmony_ci		       list_next_entry(node, node_list)->color,
20248c2ecf20Sopenharmony_ci		       list_next_entry(node, node_list)->start,
20258c2ecf20Sopenharmony_ci		       list_next_entry(node, node_list)->size);
20268c2ecf20Sopenharmony_ci		return true;
20278c2ecf20Sopenharmony_ci	}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	return false;
20308c2ecf20Sopenharmony_ci}
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_cistatic int igt_color(void *ignored)
20338c2ecf20Sopenharmony_ci{
20348c2ecf20Sopenharmony_ci	const unsigned int count = min(4096u, max_iterations);
20358c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
20368c2ecf20Sopenharmony_ci	struct drm_mm mm;
20378c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *nn;
20388c2ecf20Sopenharmony_ci	unsigned int n;
20398c2ecf20Sopenharmony_ci	int ret = -EINVAL, err;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	/* Color adjustment complicates everything. First we just check
20428c2ecf20Sopenharmony_ci	 * that when we insert a node we apply any color_adjustment callback.
20438c2ecf20Sopenharmony_ci	 * The callback we use should ensure that there is a gap between
20448c2ecf20Sopenharmony_ci	 * any two nodes, and so after each insertion we check that those
20458c2ecf20Sopenharmony_ci	 * holes are inserted and that they are preserved.
20468c2ecf20Sopenharmony_ci	 */
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, U64_MAX);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	for (n = 1; n <= count; n++) {
20518c2ecf20Sopenharmony_ci		node = kzalloc(sizeof(*node), GFP_KERNEL);
20528c2ecf20Sopenharmony_ci		if (!node) {
20538c2ecf20Sopenharmony_ci			ret = -ENOMEM;
20548c2ecf20Sopenharmony_ci			goto out;
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci		if (!expect_insert(&mm, node,
20588c2ecf20Sopenharmony_ci				   n, 0, n,
20598c2ecf20Sopenharmony_ci				   &insert_modes[0])) {
20608c2ecf20Sopenharmony_ci			pr_err("insert failed, step %d\n", n);
20618c2ecf20Sopenharmony_ci			kfree(node);
20628c2ecf20Sopenharmony_ci			goto out;
20638c2ecf20Sopenharmony_ci		}
20648c2ecf20Sopenharmony_ci	}
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, nn, &mm) {
20678c2ecf20Sopenharmony_ci		if (node->color != node->size) {
20688c2ecf20Sopenharmony_ci			pr_err("invalid color stored: expected %lld, found %ld\n",
20698c2ecf20Sopenharmony_ci			       node->size, node->color);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci			goto out;
20728c2ecf20Sopenharmony_ci		}
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
20758c2ecf20Sopenharmony_ci		kfree(node);
20768c2ecf20Sopenharmony_ci	}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	/* Now, let's start experimenting with applying a color callback */
20798c2ecf20Sopenharmony_ci	mm.color_adjust = separate_adjacent_colors;
20808c2ecf20Sopenharmony_ci	for (mode = insert_modes; mode->name; mode++) {
20818c2ecf20Sopenharmony_ci		u64 last;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci		node = kzalloc(sizeof(*node), GFP_KERNEL);
20848c2ecf20Sopenharmony_ci		if (!node) {
20858c2ecf20Sopenharmony_ci			ret = -ENOMEM;
20868c2ecf20Sopenharmony_ci			goto out;
20878c2ecf20Sopenharmony_ci		}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci		node->size = 1 + 2*count;
20908c2ecf20Sopenharmony_ci		node->color = node->size;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(&mm, node);
20938c2ecf20Sopenharmony_ci		if (err) {
20948c2ecf20Sopenharmony_ci			pr_err("initial reserve failed!\n");
20958c2ecf20Sopenharmony_ci			ret = err;
20968c2ecf20Sopenharmony_ci			goto out;
20978c2ecf20Sopenharmony_ci		}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci		last = node->start + node->size;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci		for (n = 1; n <= count; n++) {
21028c2ecf20Sopenharmony_ci			int rem;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci			node = kzalloc(sizeof(*node), GFP_KERNEL);
21058c2ecf20Sopenharmony_ci			if (!node) {
21068c2ecf20Sopenharmony_ci				ret = -ENOMEM;
21078c2ecf20Sopenharmony_ci				goto out;
21088c2ecf20Sopenharmony_ci			}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci			node->start = last;
21118c2ecf20Sopenharmony_ci			node->size = n + count;
21128c2ecf20Sopenharmony_ci			node->color = node->size;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci			err = drm_mm_reserve_node(&mm, node);
21158c2ecf20Sopenharmony_ci			if (err != -ENOSPC) {
21168c2ecf20Sopenharmony_ci				pr_err("reserve %d did not report color overlap! err=%d\n",
21178c2ecf20Sopenharmony_ci				       n, err);
21188c2ecf20Sopenharmony_ci				goto out;
21198c2ecf20Sopenharmony_ci			}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci			node->start += n + 1;
21228c2ecf20Sopenharmony_ci			rem = misalignment(node, n + count);
21238c2ecf20Sopenharmony_ci			node->start += n + count - rem;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci			err = drm_mm_reserve_node(&mm, node);
21268c2ecf20Sopenharmony_ci			if (err) {
21278c2ecf20Sopenharmony_ci				pr_err("reserve %d failed, err=%d\n", n, err);
21288c2ecf20Sopenharmony_ci				ret = err;
21298c2ecf20Sopenharmony_ci				goto out;
21308c2ecf20Sopenharmony_ci			}
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci			last = node->start + node->size;
21338c2ecf20Sopenharmony_ci		}
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci		for (n = 1; n <= count; n++) {
21368c2ecf20Sopenharmony_ci			node = kzalloc(sizeof(*node), GFP_KERNEL);
21378c2ecf20Sopenharmony_ci			if (!node) {
21388c2ecf20Sopenharmony_ci				ret = -ENOMEM;
21398c2ecf20Sopenharmony_ci				goto out;
21408c2ecf20Sopenharmony_ci			}
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci			if (!expect_insert(&mm, node,
21438c2ecf20Sopenharmony_ci					   n, n, n,
21448c2ecf20Sopenharmony_ci					   mode)) {
21458c2ecf20Sopenharmony_ci				pr_err("%s insert failed, step %d\n",
21468c2ecf20Sopenharmony_ci				       mode->name, n);
21478c2ecf20Sopenharmony_ci				kfree(node);
21488c2ecf20Sopenharmony_ci				goto out;
21498c2ecf20Sopenharmony_ci			}
21508c2ecf20Sopenharmony_ci		}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		drm_mm_for_each_node_safe(node, nn, &mm) {
21538c2ecf20Sopenharmony_ci			u64 rem;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci			if (node->color != node->size) {
21568c2ecf20Sopenharmony_ci				pr_err("%s invalid color stored: expected %lld, found %ld\n",
21578c2ecf20Sopenharmony_ci				       mode->name, node->size, node->color);
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci				goto out;
21608c2ecf20Sopenharmony_ci			}
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci			if (colors_abutt(node))
21638c2ecf20Sopenharmony_ci				goto out;
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci			div64_u64_rem(node->start, node->size, &rem);
21668c2ecf20Sopenharmony_ci			if (rem) {
21678c2ecf20Sopenharmony_ci				pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n",
21688c2ecf20Sopenharmony_ci				       mode->name, node->start, node->size, rem);
21698c2ecf20Sopenharmony_ci				goto out;
21708c2ecf20Sopenharmony_ci			}
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci			drm_mm_remove_node(node);
21738c2ecf20Sopenharmony_ci			kfree(node);
21748c2ecf20Sopenharmony_ci		}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci		cond_resched();
21778c2ecf20Sopenharmony_ci	}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	ret = 0;
21808c2ecf20Sopenharmony_ciout:
21818c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, nn, &mm) {
21828c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
21838c2ecf20Sopenharmony_ci		kfree(node);
21848c2ecf20Sopenharmony_ci	}
21858c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
21868c2ecf20Sopenharmony_ci	return ret;
21878c2ecf20Sopenharmony_ci}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_cistatic int evict_color(struct drm_mm *mm,
21908c2ecf20Sopenharmony_ci		       u64 range_start, u64 range_end,
21918c2ecf20Sopenharmony_ci		       struct evict_node *nodes,
21928c2ecf20Sopenharmony_ci		       unsigned int *order,
21938c2ecf20Sopenharmony_ci		       unsigned int count,
21948c2ecf20Sopenharmony_ci		       unsigned int size,
21958c2ecf20Sopenharmony_ci		       unsigned int alignment,
21968c2ecf20Sopenharmony_ci		       unsigned long color,
21978c2ecf20Sopenharmony_ci		       const struct insert_mode *mode)
21988c2ecf20Sopenharmony_ci{
21998c2ecf20Sopenharmony_ci	struct drm_mm_scan scan;
22008c2ecf20Sopenharmony_ci	LIST_HEAD(evict_list);
22018c2ecf20Sopenharmony_ci	struct evict_node *e;
22028c2ecf20Sopenharmony_ci	struct drm_mm_node tmp;
22038c2ecf20Sopenharmony_ci	int err;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	drm_mm_scan_init_with_range(&scan, mm,
22068c2ecf20Sopenharmony_ci				    size, alignment, color,
22078c2ecf20Sopenharmony_ci				    range_start, range_end,
22088c2ecf20Sopenharmony_ci				    mode->mode);
22098c2ecf20Sopenharmony_ci	if (!evict_nodes(&scan,
22108c2ecf20Sopenharmony_ci			 nodes, order, count, true,
22118c2ecf20Sopenharmony_ci			 &evict_list))
22128c2ecf20Sopenharmony_ci		return -EINVAL;
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	memset(&tmp, 0, sizeof(tmp));
22158c2ecf20Sopenharmony_ci	err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color,
22168c2ecf20Sopenharmony_ci					 DRM_MM_INSERT_EVICT);
22178c2ecf20Sopenharmony_ci	if (err) {
22188c2ecf20Sopenharmony_ci		pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n",
22198c2ecf20Sopenharmony_ci		       size, alignment, color, err);
22208c2ecf20Sopenharmony_ci		show_scan(&scan);
22218c2ecf20Sopenharmony_ci		show_holes(mm, 3);
22228c2ecf20Sopenharmony_ci		return err;
22238c2ecf20Sopenharmony_ci	}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
22268c2ecf20Sopenharmony_ci		pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
22278c2ecf20Sopenharmony_ci		       tmp.start, tmp.size, range_start, range_end);
22288c2ecf20Sopenharmony_ci		err = -EINVAL;
22298c2ecf20Sopenharmony_ci	}
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	if (colors_abutt(&tmp))
22328c2ecf20Sopenharmony_ci		err = -EINVAL;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (!assert_node(&tmp, mm, size, alignment, color)) {
22358c2ecf20Sopenharmony_ci		pr_err("Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n",
22368c2ecf20Sopenharmony_ci		       tmp.size, size,
22378c2ecf20Sopenharmony_ci		       alignment, misalignment(&tmp, alignment), tmp.start);
22388c2ecf20Sopenharmony_ci		err = -EINVAL;
22398c2ecf20Sopenharmony_ci	}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	drm_mm_remove_node(&tmp);
22428c2ecf20Sopenharmony_ci	if (err)
22438c2ecf20Sopenharmony_ci		return err;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	list_for_each_entry(e, &evict_list, link) {
22468c2ecf20Sopenharmony_ci		err = drm_mm_reserve_node(mm, &e->node);
22478c2ecf20Sopenharmony_ci		if (err) {
22488c2ecf20Sopenharmony_ci			pr_err("Failed to reinsert node after eviction: start=%llx\n",
22498c2ecf20Sopenharmony_ci			       e->node.start);
22508c2ecf20Sopenharmony_ci			return err;
22518c2ecf20Sopenharmony_ci		}
22528c2ecf20Sopenharmony_ci	}
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	cond_resched();
22558c2ecf20Sopenharmony_ci	return 0;
22568c2ecf20Sopenharmony_ci}
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_cistatic int igt_color_evict(void *ignored)
22598c2ecf20Sopenharmony_ci{
22608c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
22618c2ecf20Sopenharmony_ci	const unsigned int total_size = min(8192u, max_iterations);
22628c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
22638c2ecf20Sopenharmony_ci	unsigned long color = 0;
22648c2ecf20Sopenharmony_ci	struct drm_mm mm;
22658c2ecf20Sopenharmony_ci	struct evict_node *nodes;
22668c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *next;
22678c2ecf20Sopenharmony_ci	unsigned int *order, n;
22688c2ecf20Sopenharmony_ci	int ret, err;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	/* Check that the drm_mm_scan also honours color adjustment when
22718c2ecf20Sopenharmony_ci	 * choosing its victims to create a hole. Our color_adjust does not
22728c2ecf20Sopenharmony_ci	 * allow two nodes to be placed together without an intervening hole
22738c2ecf20Sopenharmony_ci	 * enlarging the set of victims that must be evicted.
22748c2ecf20Sopenharmony_ci	 */
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	ret = -ENOMEM;
22778c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(total_size, sizeof(*nodes)));
22788c2ecf20Sopenharmony_ci	if (!nodes)
22798c2ecf20Sopenharmony_ci		goto err;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	order = drm_random_order(total_size, &prng);
22828c2ecf20Sopenharmony_ci	if (!order)
22838c2ecf20Sopenharmony_ci		goto err_nodes;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	ret = -EINVAL;
22868c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, 2*total_size - 1);
22878c2ecf20Sopenharmony_ci	mm.color_adjust = separate_adjacent_colors;
22888c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
22898c2ecf20Sopenharmony_ci		if (!expect_insert(&mm, &nodes[n].node,
22908c2ecf20Sopenharmony_ci				   1, 0, color++,
22918c2ecf20Sopenharmony_ci				   &insert_modes[0])) {
22928c2ecf20Sopenharmony_ci			pr_err("insert failed, step %d\n", n);
22938c2ecf20Sopenharmony_ci			goto out;
22948c2ecf20Sopenharmony_ci		}
22958c2ecf20Sopenharmony_ci	}
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	for (mode = evict_modes; mode->name; mode++) {
22988c2ecf20Sopenharmony_ci		for (n = 1; n <= total_size; n <<= 1) {
22998c2ecf20Sopenharmony_ci			drm_random_reorder(order, total_size, &prng);
23008c2ecf20Sopenharmony_ci			err = evict_color(&mm, 0, U64_MAX,
23018c2ecf20Sopenharmony_ci					  nodes, order, total_size,
23028c2ecf20Sopenharmony_ci					  n, 1, color++,
23038c2ecf20Sopenharmony_ci					  mode);
23048c2ecf20Sopenharmony_ci			if (err) {
23058c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u) failed\n",
23068c2ecf20Sopenharmony_ci				       mode->name, n);
23078c2ecf20Sopenharmony_ci				goto out;
23088c2ecf20Sopenharmony_ci			}
23098c2ecf20Sopenharmony_ci		}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci		for (n = 1; n < total_size; n <<= 1) {
23128c2ecf20Sopenharmony_ci			drm_random_reorder(order, total_size, &prng);
23138c2ecf20Sopenharmony_ci			err = evict_color(&mm, 0, U64_MAX,
23148c2ecf20Sopenharmony_ci					  nodes, order, total_size,
23158c2ecf20Sopenharmony_ci					  total_size/2, n, color++,
23168c2ecf20Sopenharmony_ci					  mode);
23178c2ecf20Sopenharmony_ci			if (err) {
23188c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u, alignment=%u) failed\n",
23198c2ecf20Sopenharmony_ci				       mode->name, total_size/2, n);
23208c2ecf20Sopenharmony_ci				goto out;
23218c2ecf20Sopenharmony_ci			}
23228c2ecf20Sopenharmony_ci		}
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(total_size, max_prime)) {
23258c2ecf20Sopenharmony_ci			unsigned int nsize = (total_size - n + 1) / 2;
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(!nsize);
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci			drm_random_reorder(order, total_size, &prng);
23308c2ecf20Sopenharmony_ci			err = evict_color(&mm, 0, U64_MAX,
23318c2ecf20Sopenharmony_ci					  nodes, order, total_size,
23328c2ecf20Sopenharmony_ci					  nsize, n, color++,
23338c2ecf20Sopenharmony_ci					  mode);
23348c2ecf20Sopenharmony_ci			if (err) {
23358c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u, alignment=%u) failed\n",
23368c2ecf20Sopenharmony_ci				       mode->name, nsize, n);
23378c2ecf20Sopenharmony_ci				goto out;
23388c2ecf20Sopenharmony_ci			}
23398c2ecf20Sopenharmony_ci		}
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci		cond_resched();
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	ret = 0;
23458c2ecf20Sopenharmony_ciout:
23468c2ecf20Sopenharmony_ci	if (ret)
23478c2ecf20Sopenharmony_ci		show_mm(&mm);
23488c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
23498c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
23508c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
23518c2ecf20Sopenharmony_ci	kfree(order);
23528c2ecf20Sopenharmony_cierr_nodes:
23538c2ecf20Sopenharmony_ci	vfree(nodes);
23548c2ecf20Sopenharmony_cierr:
23558c2ecf20Sopenharmony_ci	return ret;
23568c2ecf20Sopenharmony_ci}
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_cistatic int igt_color_evict_range(void *ignored)
23598c2ecf20Sopenharmony_ci{
23608c2ecf20Sopenharmony_ci	DRM_RND_STATE(prng, random_seed);
23618c2ecf20Sopenharmony_ci	const unsigned int total_size = 8192;
23628c2ecf20Sopenharmony_ci	const unsigned int range_size = total_size / 2;
23638c2ecf20Sopenharmony_ci	const unsigned int range_start = total_size / 4;
23648c2ecf20Sopenharmony_ci	const unsigned int range_end = range_start + range_size;
23658c2ecf20Sopenharmony_ci	const struct insert_mode *mode;
23668c2ecf20Sopenharmony_ci	unsigned long color = 0;
23678c2ecf20Sopenharmony_ci	struct drm_mm mm;
23688c2ecf20Sopenharmony_ci	struct evict_node *nodes;
23698c2ecf20Sopenharmony_ci	struct drm_mm_node *node, *next;
23708c2ecf20Sopenharmony_ci	unsigned int *order, n;
23718c2ecf20Sopenharmony_ci	int ret, err;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	/* Like igt_color_evict(), but limited to small portion of the full
23748c2ecf20Sopenharmony_ci	 * drm_mm range.
23758c2ecf20Sopenharmony_ci	 */
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	ret = -ENOMEM;
23788c2ecf20Sopenharmony_ci	nodes = vzalloc(array_size(total_size, sizeof(*nodes)));
23798c2ecf20Sopenharmony_ci	if (!nodes)
23808c2ecf20Sopenharmony_ci		goto err;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	order = drm_random_order(total_size, &prng);
23838c2ecf20Sopenharmony_ci	if (!order)
23848c2ecf20Sopenharmony_ci		goto err_nodes;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	ret = -EINVAL;
23878c2ecf20Sopenharmony_ci	drm_mm_init(&mm, 0, 2*total_size - 1);
23888c2ecf20Sopenharmony_ci	mm.color_adjust = separate_adjacent_colors;
23898c2ecf20Sopenharmony_ci	for (n = 0; n < total_size; n++) {
23908c2ecf20Sopenharmony_ci		if (!expect_insert(&mm, &nodes[n].node,
23918c2ecf20Sopenharmony_ci				   1, 0, color++,
23928c2ecf20Sopenharmony_ci				   &insert_modes[0])) {
23938c2ecf20Sopenharmony_ci			pr_err("insert failed, step %d\n", n);
23948c2ecf20Sopenharmony_ci			goto out;
23958c2ecf20Sopenharmony_ci		}
23968c2ecf20Sopenharmony_ci	}
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	for (mode = evict_modes; mode->name; mode++) {
23998c2ecf20Sopenharmony_ci		for (n = 1; n <= range_size; n <<= 1) {
24008c2ecf20Sopenharmony_ci			drm_random_reorder(order, range_size, &prng);
24018c2ecf20Sopenharmony_ci			err = evict_color(&mm, range_start, range_end,
24028c2ecf20Sopenharmony_ci					  nodes, order, total_size,
24038c2ecf20Sopenharmony_ci					  n, 1, color++,
24048c2ecf20Sopenharmony_ci					  mode);
24058c2ecf20Sopenharmony_ci			if (err) {
24068c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u) failed for range [%x, %x]\n",
24078c2ecf20Sopenharmony_ci				       mode->name, n, range_start, range_end);
24088c2ecf20Sopenharmony_ci				goto out;
24098c2ecf20Sopenharmony_ci			}
24108c2ecf20Sopenharmony_ci		}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		for (n = 1; n < range_size; n <<= 1) {
24138c2ecf20Sopenharmony_ci			drm_random_reorder(order, total_size, &prng);
24148c2ecf20Sopenharmony_ci			err = evict_color(&mm, range_start, range_end,
24158c2ecf20Sopenharmony_ci					  nodes, order, total_size,
24168c2ecf20Sopenharmony_ci					  range_size/2, n, color++,
24178c2ecf20Sopenharmony_ci					  mode);
24188c2ecf20Sopenharmony_ci			if (err) {
24198c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n",
24208c2ecf20Sopenharmony_ci				       mode->name, total_size/2, n, range_start, range_end);
24218c2ecf20Sopenharmony_ci				goto out;
24228c2ecf20Sopenharmony_ci			}
24238c2ecf20Sopenharmony_ci		}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci		for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
24268c2ecf20Sopenharmony_ci			unsigned int nsize = (range_size - n + 1) / 2;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci			DRM_MM_BUG_ON(!nsize);
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci			drm_random_reorder(order, total_size, &prng);
24318c2ecf20Sopenharmony_ci			err = evict_color(&mm, range_start, range_end,
24328c2ecf20Sopenharmony_ci					  nodes, order, total_size,
24338c2ecf20Sopenharmony_ci					  nsize, n, color++,
24348c2ecf20Sopenharmony_ci					  mode);
24358c2ecf20Sopenharmony_ci			if (err) {
24368c2ecf20Sopenharmony_ci				pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n",
24378c2ecf20Sopenharmony_ci				       mode->name, nsize, n, range_start, range_end);
24388c2ecf20Sopenharmony_ci				goto out;
24398c2ecf20Sopenharmony_ci			}
24408c2ecf20Sopenharmony_ci		}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci		cond_resched();
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	ret = 0;
24468c2ecf20Sopenharmony_ciout:
24478c2ecf20Sopenharmony_ci	if (ret)
24488c2ecf20Sopenharmony_ci		show_mm(&mm);
24498c2ecf20Sopenharmony_ci	drm_mm_for_each_node_safe(node, next, &mm)
24508c2ecf20Sopenharmony_ci		drm_mm_remove_node(node);
24518c2ecf20Sopenharmony_ci	drm_mm_takedown(&mm);
24528c2ecf20Sopenharmony_ci	kfree(order);
24538c2ecf20Sopenharmony_cierr_nodes:
24548c2ecf20Sopenharmony_ci	vfree(nodes);
24558c2ecf20Sopenharmony_cierr:
24568c2ecf20Sopenharmony_ci	return ret;
24578c2ecf20Sopenharmony_ci}
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci#include "drm_selftest.c"
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic int __init test_drm_mm_init(void)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	int err;
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	while (!random_seed)
24668c2ecf20Sopenharmony_ci		random_seed = get_random_int();
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	pr_info("Testing DRM range manager (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n",
24698c2ecf20Sopenharmony_ci		random_seed, max_iterations, max_prime);
24708c2ecf20Sopenharmony_ci	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	return err > 0 ? 0 : err;
24738c2ecf20Sopenharmony_ci}
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_cistatic void __exit test_drm_mm_exit(void)
24768c2ecf20Sopenharmony_ci{
24778c2ecf20Sopenharmony_ci}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_cimodule_init(test_drm_mm_init);
24808c2ecf20Sopenharmony_cimodule_exit(test_drm_mm_exit);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_cimodule_param(random_seed, uint, 0400);
24838c2ecf20Sopenharmony_cimodule_param(max_iterations, uint, 0400);
24848c2ecf20Sopenharmony_cimodule_param(max_prime, uint, 0400);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation");
24878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2488