162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Test cases for the drm_mm range manager 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2022 Arthur Grillo <arthur.grillo@usp.br> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <kunit/test.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/prime_numbers.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/random.h> 1362306a36Sopenharmony_ci#include <linux/vmalloc.h> 1462306a36Sopenharmony_ci#include <linux/ktime.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <drm/drm_mm.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "../lib/drm_random.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic unsigned int random_seed; 2162306a36Sopenharmony_cistatic unsigned int max_iterations = 8192; 2262306a36Sopenharmony_cistatic unsigned int max_prime = 128; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cienum { 2562306a36Sopenharmony_ci BEST, 2662306a36Sopenharmony_ci BOTTOMUP, 2762306a36Sopenharmony_ci TOPDOWN, 2862306a36Sopenharmony_ci EVICT, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct insert_mode { 3262306a36Sopenharmony_ci const char *name; 3362306a36Sopenharmony_ci enum drm_mm_insert_mode mode; 3462306a36Sopenharmony_ci} insert_modes[] = { 3562306a36Sopenharmony_ci [BEST] = { "best", DRM_MM_INSERT_BEST }, 3662306a36Sopenharmony_ci [BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW }, 3762306a36Sopenharmony_ci [TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH }, 3862306a36Sopenharmony_ci [EVICT] = { "evict", DRM_MM_INSERT_EVICT }, 3962306a36Sopenharmony_ci {} 4062306a36Sopenharmony_ci}, evict_modes[] = { 4162306a36Sopenharmony_ci { "bottom-up", DRM_MM_INSERT_LOW }, 4262306a36Sopenharmony_ci { "top-down", DRM_MM_INSERT_HIGH }, 4362306a36Sopenharmony_ci {} 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic bool assert_no_holes(struct kunit *test, const struct drm_mm *mm) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct drm_mm_node *hole; 4962306a36Sopenharmony_ci u64 hole_start, __always_unused hole_end; 5062306a36Sopenharmony_ci unsigned long count; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci count = 0; 5362306a36Sopenharmony_ci drm_mm_for_each_hole(hole, mm, hole_start, hole_end) 5462306a36Sopenharmony_ci count++; 5562306a36Sopenharmony_ci if (count) { 5662306a36Sopenharmony_ci KUNIT_FAIL(test, 5762306a36Sopenharmony_ci "Expected to find no holes (after reserve), found %lu instead\n", count); 5862306a36Sopenharmony_ci return false; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci drm_mm_for_each_node(hole, mm) { 6262306a36Sopenharmony_ci if (drm_mm_hole_follows(hole)) { 6362306a36Sopenharmony_ci KUNIT_FAIL(test, "Hole follows node, expected none!\n"); 6462306a36Sopenharmony_ci return false; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return true; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic bool assert_one_hole(struct kunit *test, const struct drm_mm *mm, u64 start, u64 end) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct drm_mm_node *hole; 7462306a36Sopenharmony_ci u64 hole_start, hole_end; 7562306a36Sopenharmony_ci unsigned long count; 7662306a36Sopenharmony_ci bool ok = true; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (end <= start) 7962306a36Sopenharmony_ci return true; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci count = 0; 8262306a36Sopenharmony_ci drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 8362306a36Sopenharmony_ci if (start != hole_start || end != hole_end) { 8462306a36Sopenharmony_ci if (ok) 8562306a36Sopenharmony_ci KUNIT_FAIL(test, 8662306a36Sopenharmony_ci "empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", 8762306a36Sopenharmony_ci hole_start, hole_end, start, end); 8862306a36Sopenharmony_ci ok = false; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci count++; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci if (count != 1) { 9362306a36Sopenharmony_ci KUNIT_FAIL(test, "Expected to find one hole, found %lu instead\n", count); 9462306a36Sopenharmony_ci ok = false; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return ok; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic bool assert_continuous(struct kunit *test, const struct drm_mm *mm, u64 size) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct drm_mm_node *node, *check, *found; 10362306a36Sopenharmony_ci unsigned long n; 10462306a36Sopenharmony_ci u64 addr; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!assert_no_holes(test, mm)) 10762306a36Sopenharmony_ci return false; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci n = 0; 11062306a36Sopenharmony_ci addr = 0; 11162306a36Sopenharmony_ci drm_mm_for_each_node(node, mm) { 11262306a36Sopenharmony_ci if (node->start != addr) { 11362306a36Sopenharmony_ci KUNIT_FAIL(test, "node[%ld] list out of order, expected %llx found %llx\n", 11462306a36Sopenharmony_ci n, addr, node->start); 11562306a36Sopenharmony_ci return false; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (node->size != size) { 11962306a36Sopenharmony_ci KUNIT_FAIL(test, "node[%ld].size incorrect, expected %llx, found %llx\n", 12062306a36Sopenharmony_ci n, size, node->size); 12162306a36Sopenharmony_ci return false; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (drm_mm_hole_follows(node)) { 12562306a36Sopenharmony_ci KUNIT_FAIL(test, "node[%ld] is followed by a hole!\n", n); 12662306a36Sopenharmony_ci return false; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci found = NULL; 13062306a36Sopenharmony_ci drm_mm_for_each_node_in_range(check, mm, addr, addr + size) { 13162306a36Sopenharmony_ci if (node != check) { 13262306a36Sopenharmony_ci KUNIT_FAIL(test, 13362306a36Sopenharmony_ci "lookup return wrong node, expected start %llx, found %llx\n", 13462306a36Sopenharmony_ci node->start, check->start); 13562306a36Sopenharmony_ci return false; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci found = check; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci if (!found) { 14062306a36Sopenharmony_ci KUNIT_FAIL(test, "lookup failed for node %llx + %llx\n", addr, size); 14162306a36Sopenharmony_ci return false; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci addr += size; 14562306a36Sopenharmony_ci n++; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return true; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic u64 misalignment(struct drm_mm_node *node, u64 alignment) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci u64 rem; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!alignment) 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci div64_u64_rem(node->start, alignment, &rem); 15962306a36Sopenharmony_ci return rem; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic bool assert_node(struct kunit *test, struct drm_mm_node *node, struct drm_mm *mm, 16362306a36Sopenharmony_ci u64 size, u64 alignment, unsigned long color) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci bool ok = true; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!drm_mm_node_allocated(node) || node->mm != mm) { 16862306a36Sopenharmony_ci KUNIT_FAIL(test, "node not allocated\n"); 16962306a36Sopenharmony_ci ok = false; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (node->size != size) { 17362306a36Sopenharmony_ci KUNIT_FAIL(test, "node has wrong size, found %llu, expected %llu\n", 17462306a36Sopenharmony_ci node->size, size); 17562306a36Sopenharmony_ci ok = false; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (misalignment(node, alignment)) { 17962306a36Sopenharmony_ci KUNIT_FAIL(test, 18062306a36Sopenharmony_ci "node is misaligned, start %llx rem %llu, expected alignment %llu\n", 18162306a36Sopenharmony_ci node->start, misalignment(node, alignment), alignment); 18262306a36Sopenharmony_ci ok = false; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (node->color != color) { 18662306a36Sopenharmony_ci KUNIT_FAIL(test, "node has wrong color, found %lu, expected %lu\n", 18762306a36Sopenharmony_ci node->color, color); 18862306a36Sopenharmony_ci ok = false; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return ok; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void drm_test_mm_init(struct kunit *test) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci const unsigned int size = 4096; 19762306a36Sopenharmony_ci struct drm_mm mm; 19862306a36Sopenharmony_ci struct drm_mm_node tmp; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Start with some simple checks on initialising the struct drm_mm */ 20162306a36Sopenharmony_ci memset(&mm, 0, sizeof(mm)); 20262306a36Sopenharmony_ci KUNIT_ASSERT_FALSE_MSG(test, drm_mm_initialized(&mm), 20362306a36Sopenharmony_ci "zeroed mm claims to be initialized\n"); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci memset(&mm, 0xff, sizeof(mm)); 20662306a36Sopenharmony_ci drm_mm_init(&mm, 0, size); 20762306a36Sopenharmony_ci if (!drm_mm_initialized(&mm)) { 20862306a36Sopenharmony_ci KUNIT_FAIL(test, "mm claims not to be initialized\n"); 20962306a36Sopenharmony_ci goto out; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!drm_mm_clean(&mm)) { 21362306a36Sopenharmony_ci KUNIT_FAIL(test, "mm not empty on creation\n"); 21462306a36Sopenharmony_ci goto out; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* After creation, it should all be one massive hole */ 21862306a36Sopenharmony_ci if (!assert_one_hole(test, &mm, 0, size)) { 21962306a36Sopenharmony_ci KUNIT_FAIL(test, ""); 22062306a36Sopenharmony_ci goto out; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 22462306a36Sopenharmony_ci tmp.start = 0; 22562306a36Sopenharmony_ci tmp.size = size; 22662306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, &tmp)) { 22762306a36Sopenharmony_ci KUNIT_FAIL(test, "failed to reserve whole drm_mm\n"); 22862306a36Sopenharmony_ci goto out; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* After filling the range entirely, there should be no holes */ 23262306a36Sopenharmony_ci if (!assert_no_holes(test, &mm)) { 23362306a36Sopenharmony_ci KUNIT_FAIL(test, ""); 23462306a36Sopenharmony_ci goto out; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* And then after emptying it again, the massive hole should be back */ 23862306a36Sopenharmony_ci drm_mm_remove_node(&tmp); 23962306a36Sopenharmony_ci if (!assert_one_hole(test, &mm, 0, size)) { 24062306a36Sopenharmony_ci KUNIT_FAIL(test, ""); 24162306a36Sopenharmony_ci goto out; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ciout: 24562306a36Sopenharmony_ci drm_mm_takedown(&mm); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic void drm_test_mm_debug(struct kunit *test) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct drm_mm mm; 25162306a36Sopenharmony_ci struct drm_mm_node nodes[2]; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Create a small drm_mm with a couple of nodes and a few holes, and 25462306a36Sopenharmony_ci * check that the debug iterator doesn't explode over a trivial drm_mm. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci drm_mm_init(&mm, 0, 4096); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci memset(nodes, 0, sizeof(nodes)); 26062306a36Sopenharmony_ci nodes[0].start = 512; 26162306a36Sopenharmony_ci nodes[0].size = 1024; 26262306a36Sopenharmony_ci KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[0]), 26362306a36Sopenharmony_ci "failed to reserve node[0] {start=%lld, size=%lld)\n", 26462306a36Sopenharmony_ci nodes[0].start, nodes[0].size); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci nodes[1].size = 1024; 26762306a36Sopenharmony_ci nodes[1].start = 4096 - 512 - nodes[1].size; 26862306a36Sopenharmony_ci KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]), 26962306a36Sopenharmony_ci "failed to reserve node[0] {start=%lld, size=%lld)\n", 27062306a36Sopenharmony_ci nodes[0].start, nodes[0].size); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic struct drm_mm_node *set_node(struct drm_mm_node *node, 27462306a36Sopenharmony_ci u64 start, u64 size) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci node->start = start; 27762306a36Sopenharmony_ci node->size = size; 27862306a36Sopenharmony_ci return node; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic bool expect_reserve_fail(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci int err; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci err = drm_mm_reserve_node(mm, node); 28662306a36Sopenharmony_ci if (likely(err == -ENOSPC)) 28762306a36Sopenharmony_ci return true; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (!err) { 29062306a36Sopenharmony_ci KUNIT_FAIL(test, "impossible reserve succeeded, node %llu + %llu\n", 29162306a36Sopenharmony_ci node->start, node->size); 29262306a36Sopenharmony_ci drm_mm_remove_node(node); 29362306a36Sopenharmony_ci } else { 29462306a36Sopenharmony_ci KUNIT_FAIL(test, 29562306a36Sopenharmony_ci "impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", 29662306a36Sopenharmony_ci err, -ENOSPC, node->start, node->size); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci return false; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic bool noinline_for_stack check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, 30262306a36Sopenharmony_ci unsigned int count, 30362306a36Sopenharmony_ci u64 size) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci const struct boundary { 30662306a36Sopenharmony_ci u64 start, size; 30762306a36Sopenharmony_ci const char *name; 30862306a36Sopenharmony_ci } boundaries[] = { 30962306a36Sopenharmony_ci#define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" } 31062306a36Sopenharmony_ci B(0, 0), 31162306a36Sopenharmony_ci B(-size, 0), 31262306a36Sopenharmony_ci B(size, 0), 31362306a36Sopenharmony_ci B(size * count, 0), 31462306a36Sopenharmony_ci B(-size, size), 31562306a36Sopenharmony_ci B(-size, -size), 31662306a36Sopenharmony_ci B(-size, 2 * size), 31762306a36Sopenharmony_ci B(0, -size), 31862306a36Sopenharmony_ci B(size, -size), 31962306a36Sopenharmony_ci B(count * size, size), 32062306a36Sopenharmony_ci B(count * size, -size), 32162306a36Sopenharmony_ci B(count * size, count * size), 32262306a36Sopenharmony_ci B(count * size, -count * size), 32362306a36Sopenharmony_ci B(count * size, -(count + 1) * size), 32462306a36Sopenharmony_ci B((count + 1) * size, size), 32562306a36Sopenharmony_ci B((count + 1) * size, -size), 32662306a36Sopenharmony_ci B((count + 1) * size, -2 * size), 32762306a36Sopenharmony_ci#undef B 32862306a36Sopenharmony_ci }; 32962306a36Sopenharmony_ci struct drm_mm_node tmp = {}; 33062306a36Sopenharmony_ci int n; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (n = 0; n < ARRAY_SIZE(boundaries); n++) { 33362306a36Sopenharmony_ci if (!expect_reserve_fail(test, mm, set_node(&tmp, boundaries[n].start, 33462306a36Sopenharmony_ci boundaries[n].size))) { 33562306a36Sopenharmony_ci KUNIT_FAIL(test, "boundary[%d:%s] failed, count=%u, size=%lld\n", 33662306a36Sopenharmony_ci n, boundaries[n].name, count, size); 33762306a36Sopenharmony_ci return false; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return true; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int __drm_test_mm_reserve(struct kunit *test, unsigned int count, u64 size) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 34762306a36Sopenharmony_ci struct drm_mm mm; 34862306a36Sopenharmony_ci struct drm_mm_node tmp, *nodes, *node, *next; 34962306a36Sopenharmony_ci unsigned int *order, n, m, o = 0; 35062306a36Sopenharmony_ci int ret, err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* For exercising drm_mm_reserve_node(), we want to check that 35362306a36Sopenharmony_ci * reservations outside of the drm_mm range are rejected, and to 35462306a36Sopenharmony_ci * overlapping and otherwise already occupied ranges. Afterwards, 35562306a36Sopenharmony_ci * the tree and nodes should be intact. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci DRM_MM_BUG_ON(!count); 35962306a36Sopenharmony_ci DRM_MM_BUG_ON(!size); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret = -ENOMEM; 36262306a36Sopenharmony_ci order = drm_random_order(count, &prng); 36362306a36Sopenharmony_ci if (!order) 36462306a36Sopenharmony_ci goto err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci nodes = vzalloc(array_size(count, sizeof(*nodes))); 36762306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = -EINVAL; 37062306a36Sopenharmony_ci drm_mm_init(&mm, 0, count * size); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (!check_reserve_boundaries(test, &mm, count, size)) 37362306a36Sopenharmony_ci goto out; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (n = 0; n < count; n++) { 37662306a36Sopenharmony_ci nodes[n].start = order[n] * size; 37762306a36Sopenharmony_ci nodes[n].size = size; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = drm_mm_reserve_node(&mm, &nodes[n]); 38062306a36Sopenharmony_ci if (err) { 38162306a36Sopenharmony_ci KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", 38262306a36Sopenharmony_ci n, nodes[n].start); 38362306a36Sopenharmony_ci ret = err; 38462306a36Sopenharmony_ci goto out; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!drm_mm_node_allocated(&nodes[n])) { 38862306a36Sopenharmony_ci KUNIT_FAIL(test, "reserved node not allocated! step %d, start %llu\n", 38962306a36Sopenharmony_ci n, nodes[n].start); 39062306a36Sopenharmony_ci goto out; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!expect_reserve_fail(test, &mm, &nodes[n])) 39462306a36Sopenharmony_ci goto out; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* After random insertion the nodes should be in order */ 39862306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 39962306a36Sopenharmony_ci goto out; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Repeated use should then fail */ 40262306a36Sopenharmony_ci drm_random_reorder(order, count, &prng); 40362306a36Sopenharmony_ci for (n = 0; n < count; n++) { 40462306a36Sopenharmony_ci if (!expect_reserve_fail(test, &mm, set_node(&tmp, order[n] * size, 1))) 40562306a36Sopenharmony_ci goto out; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Remove and reinsert should work */ 40862306a36Sopenharmony_ci drm_mm_remove_node(&nodes[order[n]]); 40962306a36Sopenharmony_ci err = drm_mm_reserve_node(&mm, &nodes[order[n]]); 41062306a36Sopenharmony_ci if (err) { 41162306a36Sopenharmony_ci KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", 41262306a36Sopenharmony_ci n, nodes[n].start); 41362306a36Sopenharmony_ci ret = err; 41462306a36Sopenharmony_ci goto out; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 41962306a36Sopenharmony_ci goto out; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Overlapping use should then fail */ 42262306a36Sopenharmony_ci for (n = 0; n < count; n++) { 42362306a36Sopenharmony_ci if (!expect_reserve_fail(test, &mm, set_node(&tmp, 0, size * count))) 42462306a36Sopenharmony_ci goto out; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci for (n = 0; n < count; n++) { 42762306a36Sopenharmony_ci if (!expect_reserve_fail(test, &mm, set_node(&tmp, size * n, size * (count - n)))) 42862306a36Sopenharmony_ci goto out; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Remove several, reinsert, check full */ 43262306a36Sopenharmony_ci for_each_prime_number(n, min(max_prime, count)) { 43362306a36Sopenharmony_ci for (m = 0; m < n; m++) { 43462306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 43562306a36Sopenharmony_ci drm_mm_remove_node(node); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci for (m = 0; m < n; m++) { 43962306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 44062306a36Sopenharmony_ci err = drm_mm_reserve_node(&mm, node); 44162306a36Sopenharmony_ci if (err) { 44262306a36Sopenharmony_ci KUNIT_FAIL(test, "reserve failed, step %d/%d, start %llu\n", 44362306a36Sopenharmony_ci m, n, node->start); 44462306a36Sopenharmony_ci ret = err; 44562306a36Sopenharmony_ci goto out; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci o += n; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 45262306a36Sopenharmony_ci goto out; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ret = 0; 45662306a36Sopenharmony_ciout: 45762306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 45862306a36Sopenharmony_ci drm_mm_remove_node(node); 45962306a36Sopenharmony_ci drm_mm_takedown(&mm); 46062306a36Sopenharmony_ci vfree(nodes); 46162306a36Sopenharmony_ci kfree(order); 46262306a36Sopenharmony_cierr: 46362306a36Sopenharmony_ci return ret; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void drm_test_mm_reserve(struct kunit *test) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 46962306a36Sopenharmony_ci int n; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci for_each_prime_number_from(n, 1, 54) { 47262306a36Sopenharmony_ci u64 size = BIT_ULL(n); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size - 1)); 47562306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size)); 47662306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_reserve(test, count, size + 1)); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci cond_resched(); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic bool expect_insert(struct kunit *test, struct drm_mm *mm, 48362306a36Sopenharmony_ci struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, 48462306a36Sopenharmony_ci const struct insert_mode *mode) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci int err; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci err = drm_mm_insert_node_generic(mm, node, 48962306a36Sopenharmony_ci size, alignment, color, 49062306a36Sopenharmony_ci mode->mode); 49162306a36Sopenharmony_ci if (err) { 49262306a36Sopenharmony_ci KUNIT_FAIL(test, 49362306a36Sopenharmony_ci "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", 49462306a36Sopenharmony_ci size, alignment, color, mode->name, err); 49562306a36Sopenharmony_ci return false; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (!assert_node(test, node, mm, size, alignment, color)) { 49962306a36Sopenharmony_ci drm_mm_remove_node(node); 50062306a36Sopenharmony_ci return false; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return true; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic bool expect_insert_fail(struct kunit *test, struct drm_mm *mm, u64 size) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct drm_mm_node tmp = {}; 50962306a36Sopenharmony_ci int err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci err = drm_mm_insert_node(mm, &tmp, size); 51262306a36Sopenharmony_ci if (likely(err == -ENOSPC)) 51362306a36Sopenharmony_ci return true; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (!err) { 51662306a36Sopenharmony_ci KUNIT_FAIL(test, "impossible insert succeeded, node %llu + %llu\n", 51762306a36Sopenharmony_ci tmp.start, tmp.size); 51862306a36Sopenharmony_ci drm_mm_remove_node(&tmp); 51962306a36Sopenharmony_ci } else { 52062306a36Sopenharmony_ci KUNIT_FAIL(test, 52162306a36Sopenharmony_ci "impossible insert failed with wrong error %d [expected %d], size %llu\n", 52262306a36Sopenharmony_ci err, -ENOSPC, size); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci return false; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int __drm_test_mm_insert(struct kunit *test, unsigned int count, u64 size, bool replace) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 53062306a36Sopenharmony_ci const struct insert_mode *mode; 53162306a36Sopenharmony_ci struct drm_mm mm; 53262306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 53362306a36Sopenharmony_ci unsigned int *order, n, m, o = 0; 53462306a36Sopenharmony_ci int ret; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Fill a range with lots of nodes, check it doesn't fail too early */ 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci DRM_MM_BUG_ON(!count); 53962306a36Sopenharmony_ci DRM_MM_BUG_ON(!size); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci ret = -ENOMEM; 54262306a36Sopenharmony_ci nodes = vmalloc(array_size(count, sizeof(*nodes))); 54362306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci order = drm_random_order(count, &prng); 54662306a36Sopenharmony_ci if (!order) 54762306a36Sopenharmony_ci goto err_nodes; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci ret = -EINVAL; 55062306a36Sopenharmony_ci drm_mm_init(&mm, 0, count * size); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci for (mode = insert_modes; mode->name; mode++) { 55362306a36Sopenharmony_ci for (n = 0; n < count; n++) { 55462306a36Sopenharmony_ci struct drm_mm_node tmp; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci node = replace ? &tmp : &nodes[n]; 55762306a36Sopenharmony_ci memset(node, 0, sizeof(*node)); 55862306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, size, 0, n, mode)) { 55962306a36Sopenharmony_ci KUNIT_FAIL(test, "%s insert failed, size %llu step %d\n", 56062306a36Sopenharmony_ci mode->name, size, n); 56162306a36Sopenharmony_ci goto out; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (replace) { 56562306a36Sopenharmony_ci drm_mm_replace_node(&tmp, &nodes[n]); 56662306a36Sopenharmony_ci if (drm_mm_node_allocated(&tmp)) { 56762306a36Sopenharmony_ci KUNIT_FAIL(test, 56862306a36Sopenharmony_ci "replaced old-node still allocated! step %d\n", 56962306a36Sopenharmony_ci n); 57062306a36Sopenharmony_ci goto out; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!assert_node(test, &nodes[n], &mm, size, 0, n)) { 57462306a36Sopenharmony_ci KUNIT_FAIL(test, 57562306a36Sopenharmony_ci "replaced node did not inherit parameters, size %llu step %d\n", 57662306a36Sopenharmony_ci size, n); 57762306a36Sopenharmony_ci goto out; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (tmp.start != nodes[n].start) { 58162306a36Sopenharmony_ci KUNIT_FAIL(test, 58262306a36Sopenharmony_ci "replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", 58362306a36Sopenharmony_ci tmp.start, size, nodes[n].start, nodes[n].size); 58462306a36Sopenharmony_ci goto out; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* After random insertion the nodes should be in order */ 59062306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 59162306a36Sopenharmony_ci goto out; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Repeated use should then fail */ 59462306a36Sopenharmony_ci if (!expect_insert_fail(test, &mm, size)) 59562306a36Sopenharmony_ci goto out; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Remove one and reinsert, as the only hole it should refill itself */ 59862306a36Sopenharmony_ci for (n = 0; n < count; n++) { 59962306a36Sopenharmony_ci u64 addr = nodes[n].start; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci drm_mm_remove_node(&nodes[n]); 60262306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[n], size, 0, n, mode)) { 60362306a36Sopenharmony_ci KUNIT_FAIL(test, "%s reinsert failed, size %llu step %d\n", 60462306a36Sopenharmony_ci mode->name, size, n); 60562306a36Sopenharmony_ci goto out; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (nodes[n].start != addr) { 60962306a36Sopenharmony_ci KUNIT_FAIL(test, 61062306a36Sopenharmony_ci "%s reinsert node moved, step %d, expected %llx, found %llx\n", 61162306a36Sopenharmony_ci mode->name, n, addr, nodes[n].start); 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 61662306a36Sopenharmony_ci goto out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Remove several, reinsert, check full */ 62062306a36Sopenharmony_ci for_each_prime_number(n, min(max_prime, count)) { 62162306a36Sopenharmony_ci for (m = 0; m < n; m++) { 62262306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 62362306a36Sopenharmony_ci drm_mm_remove_node(node); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci for (m = 0; m < n; m++) { 62762306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 62862306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, size, 0, n, mode)) { 62962306a36Sopenharmony_ci KUNIT_FAIL(test, 63062306a36Sopenharmony_ci "%s multiple reinsert failed, size %llu step %d\n", 63162306a36Sopenharmony_ci mode->name, size, n); 63262306a36Sopenharmony_ci goto out; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci o += n; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 63962306a36Sopenharmony_ci goto out; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (!expect_insert_fail(test, &mm, size)) 64262306a36Sopenharmony_ci goto out; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 64662306a36Sopenharmony_ci drm_mm_remove_node(node); 64762306a36Sopenharmony_ci DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci cond_resched(); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci ret = 0; 65362306a36Sopenharmony_ciout: 65462306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 65562306a36Sopenharmony_ci drm_mm_remove_node(node); 65662306a36Sopenharmony_ci drm_mm_takedown(&mm); 65762306a36Sopenharmony_ci kfree(order); 65862306a36Sopenharmony_cierr_nodes: 65962306a36Sopenharmony_ci vfree(nodes); 66062306a36Sopenharmony_ci return ret; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic void drm_test_mm_insert(struct kunit *test) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 66662306a36Sopenharmony_ci unsigned int n; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for_each_prime_number_from(n, 1, 54) { 66962306a36Sopenharmony_ci u64 size = BIT_ULL(n); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, false)); 67262306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, false)); 67362306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, false)); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci cond_resched(); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void drm_test_mm_replace(struct kunit *test) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 68262306a36Sopenharmony_ci unsigned int n; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Reuse __drm_test_mm_insert to exercise replacement by inserting a dummy node, 68562306a36Sopenharmony_ci * then replacing it with the intended node. We want to check that 68662306a36Sopenharmony_ci * the tree is intact and all the information we need is carried 68762306a36Sopenharmony_ci * across to the target node. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci for_each_prime_number_from(n, 1, 54) { 69162306a36Sopenharmony_ci u64 size = BIT_ULL(n); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size - 1, true)); 69462306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size, true)); 69562306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert(test, count, size + 1, true)); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci cond_resched(); 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic bool expect_insert_in_range(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node, 70262306a36Sopenharmony_ci u64 size, u64 alignment, unsigned long color, 70362306a36Sopenharmony_ci u64 range_start, u64 range_end, const struct insert_mode *mode) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci int err; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci err = drm_mm_insert_node_in_range(mm, node, 70862306a36Sopenharmony_ci size, alignment, color, 70962306a36Sopenharmony_ci range_start, range_end, 71062306a36Sopenharmony_ci mode->mode); 71162306a36Sopenharmony_ci if (err) { 71262306a36Sopenharmony_ci KUNIT_FAIL(test, 71362306a36Sopenharmony_ci "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", 71462306a36Sopenharmony_ci size, alignment, color, mode->name, 71562306a36Sopenharmony_ci range_start, range_end, err); 71662306a36Sopenharmony_ci return false; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (!assert_node(test, node, mm, size, alignment, color)) { 72062306a36Sopenharmony_ci drm_mm_remove_node(node); 72162306a36Sopenharmony_ci return false; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return true; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic bool expect_insert_in_range_fail(struct kunit *test, struct drm_mm *mm, 72862306a36Sopenharmony_ci u64 size, u64 range_start, u64 range_end) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct drm_mm_node tmp = {}; 73162306a36Sopenharmony_ci int err; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci err = drm_mm_insert_node_in_range(mm, &tmp, size, 0, 0, range_start, range_end, 73462306a36Sopenharmony_ci 0); 73562306a36Sopenharmony_ci if (likely(err == -ENOSPC)) 73662306a36Sopenharmony_ci return true; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!err) { 73962306a36Sopenharmony_ci KUNIT_FAIL(test, 74062306a36Sopenharmony_ci "impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", 74162306a36Sopenharmony_ci tmp.start, tmp.size, range_start, range_end); 74262306a36Sopenharmony_ci drm_mm_remove_node(&tmp); 74362306a36Sopenharmony_ci } else { 74462306a36Sopenharmony_ci KUNIT_FAIL(test, 74562306a36Sopenharmony_ci "impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", 74662306a36Sopenharmony_ci err, -ENOSPC, size, range_start, range_end); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return false; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic bool assert_contiguous_in_range(struct kunit *test, struct drm_mm *mm, 75362306a36Sopenharmony_ci u64 size, u64 start, u64 end) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct drm_mm_node *node; 75662306a36Sopenharmony_ci unsigned int n; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (!expect_insert_in_range_fail(test, mm, size, start, end)) 75962306a36Sopenharmony_ci return false; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci n = div64_u64(start + size - 1, size); 76262306a36Sopenharmony_ci drm_mm_for_each_node(node, mm) { 76362306a36Sopenharmony_ci if (node->start < start || node->start + node->size > end) { 76462306a36Sopenharmony_ci KUNIT_FAIL(test, 76562306a36Sopenharmony_ci "node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", 76662306a36Sopenharmony_ci n, node->start, node->start + node->size, start, end); 76762306a36Sopenharmony_ci return false; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (node->start != n * size) { 77162306a36Sopenharmony_ci KUNIT_FAIL(test, "node %d out of order, expected start %llx, found %llx\n", 77262306a36Sopenharmony_ci n, n * size, node->start); 77362306a36Sopenharmony_ci return false; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (node->size != size) { 77762306a36Sopenharmony_ci KUNIT_FAIL(test, "node %d has wrong size, expected size %llx, found %llx\n", 77862306a36Sopenharmony_ci n, size, node->size); 77962306a36Sopenharmony_ci return false; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (drm_mm_hole_follows(node) && drm_mm_hole_node_end(node) < end) { 78362306a36Sopenharmony_ci KUNIT_FAIL(test, "node %d is followed by a hole!\n", n); 78462306a36Sopenharmony_ci return false; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci n++; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (start > 0) { 79162306a36Sopenharmony_ci node = __drm_mm_interval_first(mm, 0, start - 1); 79262306a36Sopenharmony_ci if (drm_mm_node_allocated(node)) { 79362306a36Sopenharmony_ci KUNIT_FAIL(test, "node before start: node=%llx+%llu, start=%llx\n", 79462306a36Sopenharmony_ci node->start, node->size, start); 79562306a36Sopenharmony_ci return false; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (end < U64_MAX) { 80062306a36Sopenharmony_ci node = __drm_mm_interval_first(mm, end, U64_MAX); 80162306a36Sopenharmony_ci if (drm_mm_node_allocated(node)) { 80262306a36Sopenharmony_ci KUNIT_FAIL(test, "node after end: node=%llx+%llu, end=%llx\n", 80362306a36Sopenharmony_ci node->start, node->size, end); 80462306a36Sopenharmony_ci return false; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return true; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int __drm_test_mm_insert_range(struct kunit *test, unsigned int count, u64 size, 81262306a36Sopenharmony_ci u64 start, u64 end) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci const struct insert_mode *mode; 81562306a36Sopenharmony_ci struct drm_mm mm; 81662306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 81762306a36Sopenharmony_ci unsigned int n, start_n, end_n; 81862306a36Sopenharmony_ci int ret; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci DRM_MM_BUG_ON(!count); 82162306a36Sopenharmony_ci DRM_MM_BUG_ON(!size); 82262306a36Sopenharmony_ci DRM_MM_BUG_ON(end <= start); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Very similar to __drm_test_mm_insert(), but now instead of populating the 82562306a36Sopenharmony_ci * full range of the drm_mm, we try to fill a small portion of it. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ret = -ENOMEM; 82962306a36Sopenharmony_ci nodes = vzalloc(array_size(count, sizeof(*nodes))); 83062306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ret = -EINVAL; 83362306a36Sopenharmony_ci drm_mm_init(&mm, 0, count * size); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci start_n = div64_u64(start + size - 1, size); 83662306a36Sopenharmony_ci end_n = div64_u64(end - size, size); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci for (mode = insert_modes; mode->name; mode++) { 83962306a36Sopenharmony_ci for (n = start_n; n <= end_n; n++) { 84062306a36Sopenharmony_ci if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, 84162306a36Sopenharmony_ci start, end, mode)) { 84262306a36Sopenharmony_ci KUNIT_FAIL(test, 84362306a36Sopenharmony_ci "%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", 84462306a36Sopenharmony_ci mode->name, size, n, start_n, end_n, start, end); 84562306a36Sopenharmony_ci goto out; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (!assert_contiguous_in_range(test, &mm, size, start, end)) { 85062306a36Sopenharmony_ci KUNIT_FAIL(test, 85162306a36Sopenharmony_ci "%s: range [%llx, %llx] not full after initialisation, size=%llu\n", 85262306a36Sopenharmony_ci mode->name, start, end, size); 85362306a36Sopenharmony_ci goto out; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* Remove one and reinsert, it should refill itself */ 85762306a36Sopenharmony_ci for (n = start_n; n <= end_n; n++) { 85862306a36Sopenharmony_ci u64 addr = nodes[n].start; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci drm_mm_remove_node(&nodes[n]); 86162306a36Sopenharmony_ci if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, 86262306a36Sopenharmony_ci start, end, mode)) { 86362306a36Sopenharmony_ci KUNIT_FAIL(test, "%s reinsert failed, step %d\n", mode->name, n); 86462306a36Sopenharmony_ci goto out; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (nodes[n].start != addr) { 86862306a36Sopenharmony_ci KUNIT_FAIL(test, 86962306a36Sopenharmony_ci "%s reinsert node moved, step %d, expected %llx, found %llx\n", 87062306a36Sopenharmony_ci mode->name, n, addr, nodes[n].start); 87162306a36Sopenharmony_ci goto out; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (!assert_contiguous_in_range(test, &mm, size, start, end)) { 87662306a36Sopenharmony_ci KUNIT_FAIL(test, 87762306a36Sopenharmony_ci "%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", 87862306a36Sopenharmony_ci mode->name, start, end, size); 87962306a36Sopenharmony_ci goto out; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 88362306a36Sopenharmony_ci drm_mm_remove_node(node); 88462306a36Sopenharmony_ci DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci cond_resched(); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci ret = 0; 89062306a36Sopenharmony_ciout: 89162306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 89262306a36Sopenharmony_ci drm_mm_remove_node(node); 89362306a36Sopenharmony_ci drm_mm_takedown(&mm); 89462306a36Sopenharmony_ci vfree(nodes); 89562306a36Sopenharmony_ci return ret; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int insert_outside_range(struct kunit *test) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct drm_mm mm; 90162306a36Sopenharmony_ci const unsigned int start = 1024; 90262306a36Sopenharmony_ci const unsigned int end = 2048; 90362306a36Sopenharmony_ci const unsigned int size = end - start; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci drm_mm_init(&mm, start, size); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (!expect_insert_in_range_fail(test, &mm, 1, 0, start)) 90862306a36Sopenharmony_ci return -EINVAL; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (!expect_insert_in_range_fail(test, &mm, size, 91162306a36Sopenharmony_ci start - size / 2, start + (size + 1) / 2)) 91262306a36Sopenharmony_ci return -EINVAL; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (!expect_insert_in_range_fail(test, &mm, size, 91562306a36Sopenharmony_ci end - (size + 1) / 2, end + size / 2)) 91662306a36Sopenharmony_ci return -EINVAL; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (!expect_insert_in_range_fail(test, &mm, 1, end, end + size)) 91962306a36Sopenharmony_ci return -EINVAL; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci drm_mm_takedown(&mm); 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic void drm_test_mm_insert_range(struct kunit *test) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); 92862306a36Sopenharmony_ci unsigned int n; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* Check that requests outside the bounds of drm_mm are rejected. */ 93162306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, insert_outside_range(test)); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci for_each_prime_number_from(n, 1, 50) { 93462306a36Sopenharmony_ci const u64 size = BIT_ULL(n); 93562306a36Sopenharmony_ci const u64 max = count * size; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max)); 93862306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 1, max)); 93962306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max - 1)); 94062306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max / 2)); 94162306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 94262306a36Sopenharmony_ci max / 2, max)); 94362306a36Sopenharmony_ci KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 94462306a36Sopenharmony_ci max / 4 + 1, 3 * max / 4 - 1)); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci cond_resched(); 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic int prepare_frag(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *nodes, 95162306a36Sopenharmony_ci unsigned int num_insert, const struct insert_mode *mode) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci unsigned int size = 4096; 95462306a36Sopenharmony_ci unsigned int i; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci for (i = 0; i < num_insert; i++) { 95762306a36Sopenharmony_ci if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { 95862306a36Sopenharmony_ci KUNIT_FAIL(test, "%s insert failed\n", mode->name); 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* introduce fragmentation by freeing every other node */ 96462306a36Sopenharmony_ci for (i = 0; i < num_insert; i++) { 96562306a36Sopenharmony_ci if (i % 2 == 0) 96662306a36Sopenharmony_ci drm_mm_remove_node(&nodes[i]); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic u64 get_insert_time(struct kunit *test, struct drm_mm *mm, 97362306a36Sopenharmony_ci unsigned int num_insert, struct drm_mm_node *nodes, 97462306a36Sopenharmony_ci const struct insert_mode *mode) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci unsigned int size = 8192; 97762306a36Sopenharmony_ci ktime_t start; 97862306a36Sopenharmony_ci unsigned int i; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci start = ktime_get(); 98162306a36Sopenharmony_ci for (i = 0; i < num_insert; i++) { 98262306a36Sopenharmony_ci if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { 98362306a36Sopenharmony_ci KUNIT_FAIL(test, "%s insert failed\n", mode->name); 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return ktime_to_ns(ktime_sub(ktime_get(), start)); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void drm_test_mm_frag(struct kunit *test) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct drm_mm mm; 99462306a36Sopenharmony_ci const struct insert_mode *mode; 99562306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 99662306a36Sopenharmony_ci unsigned int insert_size = 10000; 99762306a36Sopenharmony_ci unsigned int scale_factor = 4; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* We need 4 * insert_size nodes to hold intermediate allocated 100062306a36Sopenharmony_ci * drm_mm nodes. 100162306a36Sopenharmony_ci * 1 times for prepare_frag() 100262306a36Sopenharmony_ci * 1 times for get_insert_time() 100362306a36Sopenharmony_ci * 2 times for get_insert_time() 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); 100662306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* For BOTTOMUP and TOPDOWN, we first fragment the 100962306a36Sopenharmony_ci * address space using prepare_frag() and then try to verify 101062306a36Sopenharmony_ci * that insertions scale quadratically from 10k to 20k insertions 101162306a36Sopenharmony_ci */ 101262306a36Sopenharmony_ci drm_mm_init(&mm, 1, U64_MAX - 2); 101362306a36Sopenharmony_ci for (mode = insert_modes; mode->name; mode++) { 101462306a36Sopenharmony_ci u64 insert_time1, insert_time2; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (mode->mode != DRM_MM_INSERT_LOW && 101762306a36Sopenharmony_ci mode->mode != DRM_MM_INSERT_HIGH) 101862306a36Sopenharmony_ci continue; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (prepare_frag(test, &mm, nodes, insert_size, mode)) 102162306a36Sopenharmony_ci goto err; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci insert_time1 = get_insert_time(test, &mm, insert_size, 102462306a36Sopenharmony_ci nodes + insert_size, mode); 102562306a36Sopenharmony_ci if (insert_time1 == 0) 102662306a36Sopenharmony_ci goto err; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci insert_time2 = get_insert_time(test, &mm, (insert_size * 2), 102962306a36Sopenharmony_ci nodes + insert_size * 2, mode); 103062306a36Sopenharmony_ci if (insert_time2 == 0) 103162306a36Sopenharmony_ci goto err; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci kunit_info(test, "%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", 103462306a36Sopenharmony_ci mode->name, insert_size, insert_size * 2, insert_time1, insert_time2); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (insert_time2 > (scale_factor * insert_time1)) { 103762306a36Sopenharmony_ci KUNIT_FAIL(test, "%s fragmented insert took %llu nsecs more\n", 103862306a36Sopenharmony_ci mode->name, insert_time2 - (scale_factor * insert_time1)); 103962306a36Sopenharmony_ci goto err; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 104362306a36Sopenharmony_ci drm_mm_remove_node(node); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cierr: 104762306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 104862306a36Sopenharmony_ci drm_mm_remove_node(node); 104962306a36Sopenharmony_ci drm_mm_takedown(&mm); 105062306a36Sopenharmony_ci vfree(nodes); 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic void drm_test_mm_align(struct kunit *test) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci const struct insert_mode *mode; 105662306a36Sopenharmony_ci const unsigned int max_count = min(8192u, max_prime); 105762306a36Sopenharmony_ci struct drm_mm mm; 105862306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 105962306a36Sopenharmony_ci unsigned int prime; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* For each of the possible insertion modes, we pick a few 106262306a36Sopenharmony_ci * arbitrary alignments and check that the inserted node 106362306a36Sopenharmony_ci * meets our requirements. 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci nodes = vzalloc(array_size(max_count, sizeof(*nodes))); 106762306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci drm_mm_init(&mm, 1, U64_MAX - 2); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci for (mode = insert_modes; mode->name; mode++) { 107262306a36Sopenharmony_ci unsigned int i = 0; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci for_each_prime_number_from(prime, 1, max_count) { 107562306a36Sopenharmony_ci u64 size = next_prime_number(prime); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[i], size, prime, i, mode)) { 107862306a36Sopenharmony_ci KUNIT_FAIL(test, "%s insert failed with alignment=%d", 107962306a36Sopenharmony_ci mode->name, prime); 108062306a36Sopenharmony_ci goto out; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci i++; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 108762306a36Sopenharmony_ci drm_mm_remove_node(node); 108862306a36Sopenharmony_ci DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci cond_resched(); 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ciout: 109462306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 109562306a36Sopenharmony_ci drm_mm_remove_node(node); 109662306a36Sopenharmony_ci drm_mm_takedown(&mm); 109762306a36Sopenharmony_ci vfree(nodes); 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic void drm_test_mm_align_pot(struct kunit *test, int max) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci struct drm_mm mm; 110362306a36Sopenharmony_ci struct drm_mm_node *node, *next; 110462306a36Sopenharmony_ci int bit; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Check that we can align to the full u64 address space */ 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci drm_mm_init(&mm, 1, U64_MAX - 2); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci for (bit = max - 1; bit; bit--) { 111162306a36Sopenharmony_ci u64 align, size; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 111462306a36Sopenharmony_ci if (!node) { 111562306a36Sopenharmony_ci KUNIT_FAIL(test, "failed to allocate node"); 111662306a36Sopenharmony_ci goto out; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci align = BIT_ULL(bit); 112062306a36Sopenharmony_ci size = BIT_ULL(bit - 1) + 1; 112162306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, size, align, bit, &insert_modes[0])) { 112262306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed with alignment=%llx [%d]", align, bit); 112362306a36Sopenharmony_ci goto out; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci cond_resched(); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ciout: 113062306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) { 113162306a36Sopenharmony_ci drm_mm_remove_node(node); 113262306a36Sopenharmony_ci kfree(node); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci drm_mm_takedown(&mm); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic void drm_test_mm_align32(struct kunit *test) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci drm_test_mm_align_pot(test, 32); 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_cistatic void drm_test_mm_align64(struct kunit *test) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci drm_test_mm_align_pot(test, 64); 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic void show_scan(struct kunit *test, const struct drm_mm_scan *scan) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci kunit_info(test, "scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", 115062306a36Sopenharmony_ci scan->hit_start, scan->hit_end, scan->size, scan->alignment, scan->color); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void show_holes(struct kunit *test, const struct drm_mm *mm, int count) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci u64 hole_start, hole_end; 115662306a36Sopenharmony_ci struct drm_mm_node *hole; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 115962306a36Sopenharmony_ci struct drm_mm_node *next = list_next_entry(hole, node_list); 116062306a36Sopenharmony_ci const char *node1 = NULL, *node2 = NULL; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (drm_mm_node_allocated(hole)) 116362306a36Sopenharmony_ci node1 = kasprintf(GFP_KERNEL, "[%llx + %lld, color=%ld], ", 116462306a36Sopenharmony_ci hole->start, hole->size, hole->color); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (drm_mm_node_allocated(next)) 116762306a36Sopenharmony_ci node2 = kasprintf(GFP_KERNEL, ", [%llx + %lld, color=%ld]", 116862306a36Sopenharmony_ci next->start, next->size, next->color); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci kunit_info(test, "%sHole [%llx - %llx, size %lld]%s\n", node1, 117162306a36Sopenharmony_ci hole_start, hole_end, hole_end - hole_start, node2); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci kfree(node2); 117462306a36Sopenharmony_ci kfree(node1); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (!--count) 117762306a36Sopenharmony_ci break; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistruct evict_node { 118262306a36Sopenharmony_ci struct drm_mm_node node; 118362306a36Sopenharmony_ci struct list_head link; 118462306a36Sopenharmony_ci}; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic bool evict_nodes(struct kunit *test, struct drm_mm_scan *scan, 118762306a36Sopenharmony_ci struct evict_node *nodes, unsigned int *order, unsigned int count, 118862306a36Sopenharmony_ci bool use_color, struct list_head *evict_list) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci struct evict_node *e, *en; 119162306a36Sopenharmony_ci unsigned int i; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 119462306a36Sopenharmony_ci e = &nodes[order ? order[i] : i]; 119562306a36Sopenharmony_ci list_add(&e->link, evict_list); 119662306a36Sopenharmony_ci if (drm_mm_scan_add_block(scan, &e->node)) 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci list_for_each_entry_safe(e, en, evict_list, link) { 120062306a36Sopenharmony_ci if (!drm_mm_scan_remove_block(scan, &e->node)) 120162306a36Sopenharmony_ci list_del(&e->link); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci if (list_empty(evict_list)) { 120462306a36Sopenharmony_ci KUNIT_FAIL(test, 120562306a36Sopenharmony_ci "Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", 120662306a36Sopenharmony_ci scan->size, count, scan->alignment, scan->color); 120762306a36Sopenharmony_ci return false; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci list_for_each_entry(e, evict_list, link) 121162306a36Sopenharmony_ci drm_mm_remove_node(&e->node); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (use_color) { 121462306a36Sopenharmony_ci struct drm_mm_node *node; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci while ((node = drm_mm_scan_color_evict(scan))) { 121762306a36Sopenharmony_ci e = container_of(node, typeof(*e), node); 121862306a36Sopenharmony_ci drm_mm_remove_node(&e->node); 121962306a36Sopenharmony_ci list_add(&e->link, evict_list); 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci } else { 122262306a36Sopenharmony_ci if (drm_mm_scan_color_evict(scan)) { 122362306a36Sopenharmony_ci KUNIT_FAIL(test, 122462306a36Sopenharmony_ci "drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); 122562306a36Sopenharmony_ci return false; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return true; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic bool evict_nothing(struct kunit *test, struct drm_mm *mm, 123362306a36Sopenharmony_ci unsigned int total_size, struct evict_node *nodes) 123462306a36Sopenharmony_ci{ 123562306a36Sopenharmony_ci struct drm_mm_scan scan; 123662306a36Sopenharmony_ci LIST_HEAD(evict_list); 123762306a36Sopenharmony_ci struct evict_node *e; 123862306a36Sopenharmony_ci struct drm_mm_node *node; 123962306a36Sopenharmony_ci unsigned int n; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci drm_mm_scan_init(&scan, mm, 1, 0, 0, 0); 124262306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 124362306a36Sopenharmony_ci e = &nodes[n]; 124462306a36Sopenharmony_ci list_add(&e->link, &evict_list); 124562306a36Sopenharmony_ci drm_mm_scan_add_block(&scan, &e->node); 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) 124862306a36Sopenharmony_ci drm_mm_scan_remove_block(&scan, &e->node); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 125162306a36Sopenharmony_ci e = &nodes[n]; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (!drm_mm_node_allocated(&e->node)) { 125462306a36Sopenharmony_ci KUNIT_FAIL(test, "node[%d] no longer allocated!\n", n); 125562306a36Sopenharmony_ci return false; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci e->link.next = NULL; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci drm_mm_for_each_node(node, mm) { 126262306a36Sopenharmony_ci e = container_of(node, typeof(*e), node); 126362306a36Sopenharmony_ci e->link.next = &e->link; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 126762306a36Sopenharmony_ci e = &nodes[n]; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (!e->link.next) { 127062306a36Sopenharmony_ci KUNIT_FAIL(test, "node[%d] no longer connected!\n", n); 127162306a36Sopenharmony_ci return false; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci return assert_continuous(test, mm, nodes[0].node.size); 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic bool evict_everything(struct kunit *test, struct drm_mm *mm, 127962306a36Sopenharmony_ci unsigned int total_size, struct evict_node *nodes) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci struct drm_mm_scan scan; 128262306a36Sopenharmony_ci LIST_HEAD(evict_list); 128362306a36Sopenharmony_ci struct evict_node *e; 128462306a36Sopenharmony_ci unsigned int n; 128562306a36Sopenharmony_ci int err; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0); 128862306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 128962306a36Sopenharmony_ci e = &nodes[n]; 129062306a36Sopenharmony_ci list_add(&e->link, &evict_list); 129162306a36Sopenharmony_ci if (drm_mm_scan_add_block(&scan, &e->node)) 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci err = 0; 129662306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) { 129762306a36Sopenharmony_ci if (!drm_mm_scan_remove_block(&scan, &e->node)) { 129862306a36Sopenharmony_ci if (!err) { 129962306a36Sopenharmony_ci KUNIT_FAIL(test, "Node %lld not marked for eviction!\n", 130062306a36Sopenharmony_ci e->node.start); 130162306a36Sopenharmony_ci err = -EINVAL; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci if (err) 130662306a36Sopenharmony_ci return false; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) 130962306a36Sopenharmony_ci drm_mm_remove_node(&e->node); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (!assert_one_hole(test, mm, 0, total_size)) 131262306a36Sopenharmony_ci return false; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) { 131562306a36Sopenharmony_ci err = drm_mm_reserve_node(mm, &e->node); 131662306a36Sopenharmony_ci if (err) { 131762306a36Sopenharmony_ci KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", 131862306a36Sopenharmony_ci e->node.start); 131962306a36Sopenharmony_ci return false; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return assert_continuous(test, mm, nodes[0].node.size); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic int evict_something(struct kunit *test, struct drm_mm *mm, 132762306a36Sopenharmony_ci u64 range_start, u64 range_end, struct evict_node *nodes, 132862306a36Sopenharmony_ci unsigned int *order, unsigned int count, unsigned int size, 132962306a36Sopenharmony_ci unsigned int alignment, const struct insert_mode *mode) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct drm_mm_scan scan; 133262306a36Sopenharmony_ci LIST_HEAD(evict_list); 133362306a36Sopenharmony_ci struct evict_node *e; 133462306a36Sopenharmony_ci struct drm_mm_node tmp; 133562306a36Sopenharmony_ci int err; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci drm_mm_scan_init_with_range(&scan, mm, size, alignment, 0, range_start, 133862306a36Sopenharmony_ci range_end, mode->mode); 133962306a36Sopenharmony_ci if (!evict_nodes(test, &scan, nodes, order, count, false, &evict_list)) 134062306a36Sopenharmony_ci return -EINVAL; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 134362306a36Sopenharmony_ci err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, 134462306a36Sopenharmony_ci DRM_MM_INSERT_EVICT); 134562306a36Sopenharmony_ci if (err) { 134662306a36Sopenharmony_ci KUNIT_FAIL(test, "Failed to insert into eviction hole: size=%d, align=%d\n", 134762306a36Sopenharmony_ci size, alignment); 134862306a36Sopenharmony_ci show_scan(test, &scan); 134962306a36Sopenharmony_ci show_holes(test, mm, 3); 135062306a36Sopenharmony_ci return err; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 135462306a36Sopenharmony_ci KUNIT_FAIL(test, 135562306a36Sopenharmony_ci "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 135662306a36Sopenharmony_ci tmp.start, tmp.size, range_start, range_end); 135762306a36Sopenharmony_ci err = -EINVAL; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (!assert_node(test, &tmp, mm, size, alignment, 0) || 136162306a36Sopenharmony_ci drm_mm_hole_follows(&tmp)) { 136262306a36Sopenharmony_ci KUNIT_FAIL(test, 136362306a36Sopenharmony_ci "Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", 136462306a36Sopenharmony_ci tmp.size, size, alignment, misalignment(&tmp, alignment), 136562306a36Sopenharmony_ci tmp.start, drm_mm_hole_follows(&tmp)); 136662306a36Sopenharmony_ci err = -EINVAL; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci drm_mm_remove_node(&tmp); 137062306a36Sopenharmony_ci if (err) 137162306a36Sopenharmony_ci return err; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) { 137462306a36Sopenharmony_ci err = drm_mm_reserve_node(mm, &e->node); 137562306a36Sopenharmony_ci if (err) { 137662306a36Sopenharmony_ci KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", 137762306a36Sopenharmony_ci e->node.start); 137862306a36Sopenharmony_ci return err; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (!assert_continuous(test, mm, nodes[0].node.size)) { 138362306a36Sopenharmony_ci KUNIT_FAIL(test, "range is no longer continuous\n"); 138462306a36Sopenharmony_ci return -EINVAL; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci return 0; 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic void drm_test_mm_evict(struct kunit *test) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 139362306a36Sopenharmony_ci const unsigned int size = 8192; 139462306a36Sopenharmony_ci const struct insert_mode *mode; 139562306a36Sopenharmony_ci struct drm_mm mm; 139662306a36Sopenharmony_ci struct evict_node *nodes; 139762306a36Sopenharmony_ci struct drm_mm_node *node, *next; 139862306a36Sopenharmony_ci unsigned int *order, n; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* Here we populate a full drm_mm and then try and insert a new node 140162306a36Sopenharmony_ci * by evicting other nodes in a random order. The drm_mm_scan should 140262306a36Sopenharmony_ci * pick the first matching hole it finds from the random list. We 140362306a36Sopenharmony_ci * repeat that for different allocation strategies, alignments and 140462306a36Sopenharmony_ci * sizes to try and stress the hole finder. 140562306a36Sopenharmony_ci */ 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci nodes = vzalloc(array_size(size, sizeof(*nodes))); 140862306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci order = drm_random_order(size, &prng); 141162306a36Sopenharmony_ci if (!order) 141262306a36Sopenharmony_ci goto err_nodes; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci drm_mm_init(&mm, 0, size); 141562306a36Sopenharmony_ci for (n = 0; n < size; n++) { 141662306a36Sopenharmony_ci if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { 141762306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d\n", n); 141862306a36Sopenharmony_ci goto out; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* First check that using the scanner doesn't break the mm */ 142362306a36Sopenharmony_ci if (!evict_nothing(test, &mm, size, nodes)) { 142462306a36Sopenharmony_ci KUNIT_FAIL(test, "evict_nothing() failed\n"); 142562306a36Sopenharmony_ci goto out; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci if (!evict_everything(test, &mm, size, nodes)) { 142862306a36Sopenharmony_ci KUNIT_FAIL(test, "evict_everything() failed\n"); 142962306a36Sopenharmony_ci goto out; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci for (mode = evict_modes; mode->name; mode++) { 143362306a36Sopenharmony_ci for (n = 1; n <= size; n <<= 1) { 143462306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 143562306a36Sopenharmony_ci if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, n, 1, 143662306a36Sopenharmony_ci mode)) { 143762306a36Sopenharmony_ci KUNIT_FAIL(test, "%s evict_something(size=%u) failed\n", 143862306a36Sopenharmony_ci mode->name, n); 143962306a36Sopenharmony_ci goto out; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci for (n = 1; n < size; n <<= 1) { 144462306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 144562306a36Sopenharmony_ci if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, 144662306a36Sopenharmony_ci size / 2, n, mode)) { 144762306a36Sopenharmony_ci KUNIT_FAIL(test, 144862306a36Sopenharmony_ci "%s evict_something(size=%u, alignment=%u) failed\n", 144962306a36Sopenharmony_ci mode->name, size / 2, n); 145062306a36Sopenharmony_ci goto out; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(size, max_prime)) { 145562306a36Sopenharmony_ci unsigned int nsize = (size - n + 1) / 2; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci DRM_MM_BUG_ON(!nsize); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 146062306a36Sopenharmony_ci if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, 146162306a36Sopenharmony_ci nsize, n, mode)) { 146262306a36Sopenharmony_ci KUNIT_FAIL(test, 146362306a36Sopenharmony_ci "%s evict_something(size=%u, alignment=%u) failed\n", 146462306a36Sopenharmony_ci mode->name, nsize, n); 146562306a36Sopenharmony_ci goto out; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci cond_resched(); 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ciout: 147362306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 147462306a36Sopenharmony_ci drm_mm_remove_node(node); 147562306a36Sopenharmony_ci drm_mm_takedown(&mm); 147662306a36Sopenharmony_ci kfree(order); 147762306a36Sopenharmony_cierr_nodes: 147862306a36Sopenharmony_ci vfree(nodes); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic void drm_test_mm_evict_range(struct kunit *test) 148262306a36Sopenharmony_ci{ 148362306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 148462306a36Sopenharmony_ci const unsigned int size = 8192; 148562306a36Sopenharmony_ci const unsigned int range_size = size / 2; 148662306a36Sopenharmony_ci const unsigned int range_start = size / 4; 148762306a36Sopenharmony_ci const unsigned int range_end = range_start + range_size; 148862306a36Sopenharmony_ci const struct insert_mode *mode; 148962306a36Sopenharmony_ci struct drm_mm mm; 149062306a36Sopenharmony_ci struct evict_node *nodes; 149162306a36Sopenharmony_ci struct drm_mm_node *node, *next; 149262306a36Sopenharmony_ci unsigned int *order, n; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* Like drm_test_mm_evict() but now we are limiting the search to a 149562306a36Sopenharmony_ci * small portion of the full drm_mm. 149662306a36Sopenharmony_ci */ 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci nodes = vzalloc(array_size(size, sizeof(*nodes))); 149962306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci order = drm_random_order(size, &prng); 150262306a36Sopenharmony_ci if (!order) 150362306a36Sopenharmony_ci goto err_nodes; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci drm_mm_init(&mm, 0, size); 150662306a36Sopenharmony_ci for (n = 0; n < size; n++) { 150762306a36Sopenharmony_ci if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { 150862306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d\n", n); 150962306a36Sopenharmony_ci goto out; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci for (mode = evict_modes; mode->name; mode++) { 151462306a36Sopenharmony_ci for (n = 1; n <= range_size; n <<= 1) { 151562306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 151662306a36Sopenharmony_ci if (evict_something(test, &mm, range_start, range_end, nodes, 151762306a36Sopenharmony_ci order, size, n, 1, mode)) { 151862306a36Sopenharmony_ci KUNIT_FAIL(test, 151962306a36Sopenharmony_ci "%s evict_something(size=%u) failed with range [%u, %u]\n", 152062306a36Sopenharmony_ci mode->name, n, range_start, range_end); 152162306a36Sopenharmony_ci goto out; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci for (n = 1; n <= range_size; n <<= 1) { 152662306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 152762306a36Sopenharmony_ci if (evict_something(test, &mm, range_start, range_end, nodes, 152862306a36Sopenharmony_ci order, size, range_size / 2, n, mode)) { 152962306a36Sopenharmony_ci KUNIT_FAIL(test, 153062306a36Sopenharmony_ci "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 153162306a36Sopenharmony_ci mode->name, range_size / 2, n, range_start, range_end); 153262306a36Sopenharmony_ci goto out; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 153762306a36Sopenharmony_ci unsigned int nsize = (range_size - n + 1) / 2; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci DRM_MM_BUG_ON(!nsize); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci drm_random_reorder(order, size, &prng); 154262306a36Sopenharmony_ci if (evict_something(test, &mm, range_start, range_end, nodes, 154362306a36Sopenharmony_ci order, size, nsize, n, mode)) { 154462306a36Sopenharmony_ci KUNIT_FAIL(test, 154562306a36Sopenharmony_ci "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 154662306a36Sopenharmony_ci mode->name, nsize, n, range_start, range_end); 154762306a36Sopenharmony_ci goto out; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci cond_resched(); 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ciout: 155562306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 155662306a36Sopenharmony_ci drm_mm_remove_node(node); 155762306a36Sopenharmony_ci drm_mm_takedown(&mm); 155862306a36Sopenharmony_ci kfree(order); 155962306a36Sopenharmony_cierr_nodes: 156062306a36Sopenharmony_ci vfree(nodes); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic unsigned int node_index(const struct drm_mm_node *node) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci return div64_u64(node->start, node->size); 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic void drm_test_mm_topdown(struct kunit *test) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci const struct insert_mode *topdown = &insert_modes[TOPDOWN]; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 157362306a36Sopenharmony_ci const unsigned int count = 8192; 157462306a36Sopenharmony_ci unsigned int size; 157562306a36Sopenharmony_ci unsigned long *bitmap; 157662306a36Sopenharmony_ci struct drm_mm mm; 157762306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 157862306a36Sopenharmony_ci unsigned int *order, n, m, o = 0; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* When allocating top-down, we expect to be returned a node 158162306a36Sopenharmony_ci * from a suitable hole at the top of the drm_mm. We check that 158262306a36Sopenharmony_ci * the returned node does match the highest available slot. 158362306a36Sopenharmony_ci */ 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci nodes = vzalloc(array_size(count, sizeof(*nodes))); 158662306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci bitmap = bitmap_zalloc(count, GFP_KERNEL); 158962306a36Sopenharmony_ci if (!bitmap) 159062306a36Sopenharmony_ci goto err_nodes; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci order = drm_random_order(count, &prng); 159362306a36Sopenharmony_ci if (!order) 159462306a36Sopenharmony_ci goto err_bitmap; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci for (size = 1; size <= 64; size <<= 1) { 159762306a36Sopenharmony_ci drm_mm_init(&mm, 0, size * count); 159862306a36Sopenharmony_ci for (n = 0; n < count; n++) { 159962306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[n], size, 0, n, topdown)) { 160062306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, size %u step %d\n", size, n); 160162306a36Sopenharmony_ci goto out; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (drm_mm_hole_follows(&nodes[n])) { 160562306a36Sopenharmony_ci KUNIT_FAIL(test, 160662306a36Sopenharmony_ci "hole after topdown insert %d, start=%llx\n, size=%u", 160762306a36Sopenharmony_ci n, nodes[n].start, size); 160862306a36Sopenharmony_ci goto out; 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (!assert_one_hole(test, &mm, 0, size * (count - n - 1))) 161262306a36Sopenharmony_ci goto out; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 161662306a36Sopenharmony_ci goto out; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci drm_random_reorder(order, count, &prng); 161962306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(count, max_prime)) { 162062306a36Sopenharmony_ci for (m = 0; m < n; m++) { 162162306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 162262306a36Sopenharmony_ci drm_mm_remove_node(node); 162362306a36Sopenharmony_ci __set_bit(node_index(node), bitmap); 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci for (m = 0; m < n; m++) { 162762306a36Sopenharmony_ci unsigned int last; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 163062306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, size, 0, 0, topdown)) { 163162306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); 163262306a36Sopenharmony_ci goto out; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (drm_mm_hole_follows(node)) { 163662306a36Sopenharmony_ci KUNIT_FAIL(test, 163762306a36Sopenharmony_ci "hole after topdown insert %d/%d, start=%llx\n", 163862306a36Sopenharmony_ci m, n, node->start); 163962306a36Sopenharmony_ci goto out; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci last = find_last_bit(bitmap, count); 164362306a36Sopenharmony_ci if (node_index(node) != last) { 164462306a36Sopenharmony_ci KUNIT_FAIL(test, 164562306a36Sopenharmony_ci "node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", 164662306a36Sopenharmony_ci m, n, size, last, node_index(node)); 164762306a36Sopenharmony_ci goto out; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci __clear_bit(last, bitmap); 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci o += n; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 165962306a36Sopenharmony_ci drm_mm_remove_node(node); 166062306a36Sopenharmony_ci DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 166162306a36Sopenharmony_ci cond_resched(); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ciout: 166562306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 166662306a36Sopenharmony_ci drm_mm_remove_node(node); 166762306a36Sopenharmony_ci drm_mm_takedown(&mm); 166862306a36Sopenharmony_ci kfree(order); 166962306a36Sopenharmony_cierr_bitmap: 167062306a36Sopenharmony_ci bitmap_free(bitmap); 167162306a36Sopenharmony_cierr_nodes: 167262306a36Sopenharmony_ci vfree(nodes); 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic void drm_test_mm_bottomup(struct kunit *test) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 168062306a36Sopenharmony_ci const unsigned int count = 8192; 168162306a36Sopenharmony_ci unsigned int size; 168262306a36Sopenharmony_ci unsigned long *bitmap; 168362306a36Sopenharmony_ci struct drm_mm mm; 168462306a36Sopenharmony_ci struct drm_mm_node *nodes, *node, *next; 168562306a36Sopenharmony_ci unsigned int *order, n, m, o = 0; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci /* Like drm_test_mm_topdown, but instead of searching for the last hole, 168862306a36Sopenharmony_ci * we search for the first. 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci nodes = vzalloc(array_size(count, sizeof(*nodes))); 169262306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci bitmap = bitmap_zalloc(count, GFP_KERNEL); 169562306a36Sopenharmony_ci if (!bitmap) 169662306a36Sopenharmony_ci goto err_nodes; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci order = drm_random_order(count, &prng); 169962306a36Sopenharmony_ci if (!order) 170062306a36Sopenharmony_ci goto err_bitmap; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci for (size = 1; size <= 64; size <<= 1) { 170362306a36Sopenharmony_ci drm_mm_init(&mm, 0, size * count); 170462306a36Sopenharmony_ci for (n = 0; n < count; n++) { 170562306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[n], size, 0, n, bottomup)) { 170662306a36Sopenharmony_ci KUNIT_FAIL(test, 170762306a36Sopenharmony_ci "bottomup insert failed, size %u step %d\n", size, n); 170862306a36Sopenharmony_ci goto out; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci if (!assert_one_hole(test, &mm, size * (n + 1), size * count)) 171262306a36Sopenharmony_ci goto out; 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci if (!assert_continuous(test, &mm, size)) 171662306a36Sopenharmony_ci goto out; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci drm_random_reorder(order, count, &prng); 171962306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(count, max_prime)) { 172062306a36Sopenharmony_ci for (m = 0; m < n; m++) { 172162306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 172262306a36Sopenharmony_ci drm_mm_remove_node(node); 172362306a36Sopenharmony_ci __set_bit(node_index(node), bitmap); 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci for (m = 0; m < n; m++) { 172762306a36Sopenharmony_ci unsigned int first; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci node = &nodes[order[(o + m) % count]]; 173062306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, size, 0, 0, bottomup)) { 173162306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); 173262306a36Sopenharmony_ci goto out; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci first = find_first_bit(bitmap, count); 173662306a36Sopenharmony_ci if (node_index(node) != first) { 173762306a36Sopenharmony_ci KUNIT_FAIL(test, 173862306a36Sopenharmony_ci "node %d/%d not inserted into bottom hole, expected %d, found %d\n", 173962306a36Sopenharmony_ci m, n, first, node_index(node)); 174062306a36Sopenharmony_ci goto out; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci __clear_bit(first, bitmap); 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci o += n; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 175162306a36Sopenharmony_ci drm_mm_remove_node(node); 175262306a36Sopenharmony_ci DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 175362306a36Sopenharmony_ci cond_resched(); 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ciout: 175762306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 175862306a36Sopenharmony_ci drm_mm_remove_node(node); 175962306a36Sopenharmony_ci drm_mm_takedown(&mm); 176062306a36Sopenharmony_ci kfree(order); 176162306a36Sopenharmony_cierr_bitmap: 176262306a36Sopenharmony_ci bitmap_free(bitmap); 176362306a36Sopenharmony_cierr_nodes: 176462306a36Sopenharmony_ci vfree(nodes); 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic void drm_test_mm_once(struct kunit *test, unsigned int mode) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct drm_mm mm; 177062306a36Sopenharmony_ci struct drm_mm_node rsvd_lo, rsvd_hi, node; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci drm_mm_init(&mm, 0, 7); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci memset(&rsvd_lo, 0, sizeof(rsvd_lo)); 177562306a36Sopenharmony_ci rsvd_lo.start = 1; 177662306a36Sopenharmony_ci rsvd_lo.size = 1; 177762306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, &rsvd_lo)) { 177862306a36Sopenharmony_ci KUNIT_FAIL(test, "Could not reserve low node\n"); 177962306a36Sopenharmony_ci goto err; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci memset(&rsvd_hi, 0, sizeof(rsvd_hi)); 178362306a36Sopenharmony_ci rsvd_hi.start = 5; 178462306a36Sopenharmony_ci rsvd_hi.size = 1; 178562306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, &rsvd_hi)) { 178662306a36Sopenharmony_ci KUNIT_FAIL(test, "Could not reserve low node\n"); 178762306a36Sopenharmony_ci goto err_lo; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) { 179162306a36Sopenharmony_ci KUNIT_FAIL(test, "Expected a hole after lo and high nodes!\n"); 179262306a36Sopenharmony_ci goto err_hi; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci memset(&node, 0, sizeof(node)); 179662306a36Sopenharmony_ci if (drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode)) { 179762306a36Sopenharmony_ci KUNIT_FAIL(test, "Could not insert the node into the available hole!\n"); 179862306a36Sopenharmony_ci goto err_hi; 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci drm_mm_remove_node(&node); 180262306a36Sopenharmony_cierr_hi: 180362306a36Sopenharmony_ci drm_mm_remove_node(&rsvd_hi); 180462306a36Sopenharmony_cierr_lo: 180562306a36Sopenharmony_ci drm_mm_remove_node(&rsvd_lo); 180662306a36Sopenharmony_cierr: 180762306a36Sopenharmony_ci drm_mm_takedown(&mm); 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic void drm_test_mm_lowest(struct kunit *test) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci drm_test_mm_once(test, DRM_MM_INSERT_LOW); 181362306a36Sopenharmony_ci} 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_cistatic void drm_test_mm_highest(struct kunit *test) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci drm_test_mm_once(test, DRM_MM_INSERT_HIGH); 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic void separate_adjacent_colors(const struct drm_mm_node *node, 182162306a36Sopenharmony_ci unsigned long color, u64 *start, u64 *end) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci if (drm_mm_node_allocated(node) && node->color != color) 182462306a36Sopenharmony_ci ++*start; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci node = list_next_entry(node, node_list); 182762306a36Sopenharmony_ci if (drm_mm_node_allocated(node) && node->color != color) 182862306a36Sopenharmony_ci --*end; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic bool colors_abutt(struct kunit *test, const struct drm_mm_node *node) 183262306a36Sopenharmony_ci{ 183362306a36Sopenharmony_ci if (!drm_mm_hole_follows(node) && 183462306a36Sopenharmony_ci drm_mm_node_allocated(list_next_entry(node, node_list))) { 183562306a36Sopenharmony_ci KUNIT_FAIL(test, "colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", 183662306a36Sopenharmony_ci node->color, node->start, node->size, 183762306a36Sopenharmony_ci list_next_entry(node, node_list)->color, 183862306a36Sopenharmony_ci list_next_entry(node, node_list)->start, 183962306a36Sopenharmony_ci list_next_entry(node, node_list)->size); 184062306a36Sopenharmony_ci return true; 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci return false; 184462306a36Sopenharmony_ci} 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_cistatic void drm_test_mm_color(struct kunit *test) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci const unsigned int count = min(4096u, max_iterations); 184962306a36Sopenharmony_ci const struct insert_mode *mode; 185062306a36Sopenharmony_ci struct drm_mm mm; 185162306a36Sopenharmony_ci struct drm_mm_node *node, *nn; 185262306a36Sopenharmony_ci unsigned int n; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci /* Color adjustment complicates everything. First we just check 185562306a36Sopenharmony_ci * that when we insert a node we apply any color_adjustment callback. 185662306a36Sopenharmony_ci * The callback we use should ensure that there is a gap between 185762306a36Sopenharmony_ci * any two nodes, and so after each insertion we check that those 185862306a36Sopenharmony_ci * holes are inserted and that they are preserved. 185962306a36Sopenharmony_ci */ 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci drm_mm_init(&mm, 0, U64_MAX); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci for (n = 1; n <= count; n++) { 186462306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 186562306a36Sopenharmony_ci if (!node) 186662306a36Sopenharmony_ci goto out; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, n, 0, n, &insert_modes[0])) { 186962306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d\n", n); 187062306a36Sopenharmony_ci kfree(node); 187162306a36Sopenharmony_ci goto out; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, nn, &mm) { 187662306a36Sopenharmony_ci if (node->color != node->size) { 187762306a36Sopenharmony_ci KUNIT_FAIL(test, "invalid color stored: expected %lld, found %ld\n", 187862306a36Sopenharmony_ci node->size, node->color); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci goto out; 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci drm_mm_remove_node(node); 188462306a36Sopenharmony_ci kfree(node); 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* Now, let's start experimenting with applying a color callback */ 188862306a36Sopenharmony_ci mm.color_adjust = separate_adjacent_colors; 188962306a36Sopenharmony_ci for (mode = insert_modes; mode->name; mode++) { 189062306a36Sopenharmony_ci u64 last; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 189362306a36Sopenharmony_ci if (!node) 189462306a36Sopenharmony_ci goto out; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci node->size = 1 + 2 * count; 189762306a36Sopenharmony_ci node->color = node->size; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, node)) { 190062306a36Sopenharmony_ci KUNIT_FAIL(test, "initial reserve failed!\n"); 190162306a36Sopenharmony_ci goto out; 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci last = node->start + node->size; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci for (n = 1; n <= count; n++) { 190762306a36Sopenharmony_ci int rem; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 191062306a36Sopenharmony_ci if (!node) 191162306a36Sopenharmony_ci goto out; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci node->start = last; 191462306a36Sopenharmony_ci node->size = n + count; 191562306a36Sopenharmony_ci node->color = node->size; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, node) != -ENOSPC) { 191862306a36Sopenharmony_ci KUNIT_FAIL(test, "reserve %d did not report color overlap!", n); 191962306a36Sopenharmony_ci goto out; 192062306a36Sopenharmony_ci } 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci node->start += n + 1; 192362306a36Sopenharmony_ci rem = misalignment(node, n + count); 192462306a36Sopenharmony_ci node->start += n + count - rem; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (drm_mm_reserve_node(&mm, node)) { 192762306a36Sopenharmony_ci KUNIT_FAIL(test, "reserve %d failed", n); 192862306a36Sopenharmony_ci goto out; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci last = node->start + node->size; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci for (n = 1; n <= count; n++) { 193562306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 193662306a36Sopenharmony_ci if (!node) 193762306a36Sopenharmony_ci goto out; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci if (!expect_insert(test, &mm, node, n, n, n, mode)) { 194062306a36Sopenharmony_ci KUNIT_FAIL(test, "%s insert failed, step %d\n", mode->name, n); 194162306a36Sopenharmony_ci kfree(node); 194262306a36Sopenharmony_ci goto out; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, nn, &mm) { 194762306a36Sopenharmony_ci u64 rem; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (node->color != node->size) { 195062306a36Sopenharmony_ci KUNIT_FAIL(test, 195162306a36Sopenharmony_ci "%s invalid color stored: expected %lld, found %ld\n", 195262306a36Sopenharmony_ci mode->name, node->size, node->color); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci goto out; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci if (colors_abutt(test, node)) 195862306a36Sopenharmony_ci goto out; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci div64_u64_rem(node->start, node->size, &rem); 196162306a36Sopenharmony_ci if (rem) { 196262306a36Sopenharmony_ci KUNIT_FAIL(test, 196362306a36Sopenharmony_ci "%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", 196462306a36Sopenharmony_ci mode->name, node->start, node->size, rem); 196562306a36Sopenharmony_ci goto out; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci drm_mm_remove_node(node); 196962306a36Sopenharmony_ci kfree(node); 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci cond_resched(); 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ciout: 197662306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, nn, &mm) { 197762306a36Sopenharmony_ci drm_mm_remove_node(node); 197862306a36Sopenharmony_ci kfree(node); 197962306a36Sopenharmony_ci } 198062306a36Sopenharmony_ci drm_mm_takedown(&mm); 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic int evict_color(struct kunit *test, struct drm_mm *mm, u64 range_start, 198462306a36Sopenharmony_ci u64 range_end, struct evict_node *nodes, unsigned int *order, 198562306a36Sopenharmony_ci unsigned int count, unsigned int size, unsigned int alignment, 198662306a36Sopenharmony_ci unsigned long color, const struct insert_mode *mode) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci struct drm_mm_scan scan; 198962306a36Sopenharmony_ci LIST_HEAD(evict_list); 199062306a36Sopenharmony_ci struct evict_node *e; 199162306a36Sopenharmony_ci struct drm_mm_node tmp; 199262306a36Sopenharmony_ci int err; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci drm_mm_scan_init_with_range(&scan, mm, size, alignment, color, range_start, 199562306a36Sopenharmony_ci range_end, mode->mode); 199662306a36Sopenharmony_ci if (!evict_nodes(test, &scan, nodes, order, count, true, &evict_list)) 199762306a36Sopenharmony_ci return -EINVAL; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 200062306a36Sopenharmony_ci err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, 200162306a36Sopenharmony_ci DRM_MM_INSERT_EVICT); 200262306a36Sopenharmony_ci if (err) { 200362306a36Sopenharmony_ci KUNIT_FAIL(test, 200462306a36Sopenharmony_ci "Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", 200562306a36Sopenharmony_ci size, alignment, color, err); 200662306a36Sopenharmony_ci show_scan(test, &scan); 200762306a36Sopenharmony_ci show_holes(test, mm, 3); 200862306a36Sopenharmony_ci return err; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 201262306a36Sopenharmony_ci KUNIT_FAIL(test, 201362306a36Sopenharmony_ci "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 201462306a36Sopenharmony_ci tmp.start, tmp.size, range_start, range_end); 201562306a36Sopenharmony_ci err = -EINVAL; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci if (colors_abutt(test, &tmp)) 201962306a36Sopenharmony_ci err = -EINVAL; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci if (!assert_node(test, &tmp, mm, size, alignment, color)) { 202262306a36Sopenharmony_ci KUNIT_FAIL(test, 202362306a36Sopenharmony_ci "Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", 202462306a36Sopenharmony_ci tmp.size, size, alignment, misalignment(&tmp, alignment), tmp.start); 202562306a36Sopenharmony_ci err = -EINVAL; 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci drm_mm_remove_node(&tmp); 202962306a36Sopenharmony_ci if (err) 203062306a36Sopenharmony_ci return err; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci list_for_each_entry(e, &evict_list, link) { 203362306a36Sopenharmony_ci err = drm_mm_reserve_node(mm, &e->node); 203462306a36Sopenharmony_ci if (err) { 203562306a36Sopenharmony_ci KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", 203662306a36Sopenharmony_ci e->node.start); 203762306a36Sopenharmony_ci return err; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci } 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci cond_resched(); 204262306a36Sopenharmony_ci return 0; 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic void drm_test_mm_color_evict(struct kunit *test) 204662306a36Sopenharmony_ci{ 204762306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 204862306a36Sopenharmony_ci const unsigned int total_size = min(8192u, max_iterations); 204962306a36Sopenharmony_ci const struct insert_mode *mode; 205062306a36Sopenharmony_ci unsigned long color = 0; 205162306a36Sopenharmony_ci struct drm_mm mm; 205262306a36Sopenharmony_ci struct evict_node *nodes; 205362306a36Sopenharmony_ci struct drm_mm_node *node, *next; 205462306a36Sopenharmony_ci unsigned int *order, n; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci /* Check that the drm_mm_scan also honours color adjustment when 205762306a36Sopenharmony_ci * choosing its victims to create a hole. Our color_adjust does not 205862306a36Sopenharmony_ci * allow two nodes to be placed together without an intervening hole 205962306a36Sopenharmony_ci * enlarging the set of victims that must be evicted. 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 206362306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci order = drm_random_order(total_size, &prng); 206662306a36Sopenharmony_ci if (!order) 206762306a36Sopenharmony_ci goto err_nodes; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci drm_mm_init(&mm, 0, 2 * total_size - 1); 207062306a36Sopenharmony_ci mm.color_adjust = separate_adjacent_colors; 207162306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 207262306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[n].node, 207362306a36Sopenharmony_ci 1, 0, color++, 207462306a36Sopenharmony_ci &insert_modes[0])) { 207562306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d\n", n); 207662306a36Sopenharmony_ci goto out; 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci for (mode = evict_modes; mode->name; mode++) { 208162306a36Sopenharmony_ci for (n = 1; n <= total_size; n <<= 1) { 208262306a36Sopenharmony_ci drm_random_reorder(order, total_size, &prng); 208362306a36Sopenharmony_ci if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, 208462306a36Sopenharmony_ci n, 1, color++, mode)) { 208562306a36Sopenharmony_ci KUNIT_FAIL(test, "%s evict_color(size=%u) failed\n", mode->name, n); 208662306a36Sopenharmony_ci goto out; 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci for (n = 1; n < total_size; n <<= 1) { 209162306a36Sopenharmony_ci drm_random_reorder(order, total_size, &prng); 209262306a36Sopenharmony_ci if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, 209362306a36Sopenharmony_ci total_size / 2, n, color++, mode)) { 209462306a36Sopenharmony_ci KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", 209562306a36Sopenharmony_ci mode->name, total_size / 2, n); 209662306a36Sopenharmony_ci goto out; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(total_size, max_prime)) { 210162306a36Sopenharmony_ci unsigned int nsize = (total_size - n + 1) / 2; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci DRM_MM_BUG_ON(!nsize); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci drm_random_reorder(order, total_size, &prng); 210662306a36Sopenharmony_ci if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, 210762306a36Sopenharmony_ci nsize, n, color++, mode)) { 210862306a36Sopenharmony_ci KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", 210962306a36Sopenharmony_ci mode->name, nsize, n); 211062306a36Sopenharmony_ci goto out; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci cond_resched(); 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ciout: 211862306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 211962306a36Sopenharmony_ci drm_mm_remove_node(node); 212062306a36Sopenharmony_ci drm_mm_takedown(&mm); 212162306a36Sopenharmony_ci kfree(order); 212262306a36Sopenharmony_cierr_nodes: 212362306a36Sopenharmony_ci vfree(nodes); 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic void drm_test_mm_color_evict_range(struct kunit *test) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci DRM_RND_STATE(prng, random_seed); 212962306a36Sopenharmony_ci const unsigned int total_size = 8192; 213062306a36Sopenharmony_ci const unsigned int range_size = total_size / 2; 213162306a36Sopenharmony_ci const unsigned int range_start = total_size / 4; 213262306a36Sopenharmony_ci const unsigned int range_end = range_start + range_size; 213362306a36Sopenharmony_ci const struct insert_mode *mode; 213462306a36Sopenharmony_ci unsigned long color = 0; 213562306a36Sopenharmony_ci struct drm_mm mm; 213662306a36Sopenharmony_ci struct evict_node *nodes; 213762306a36Sopenharmony_ci struct drm_mm_node *node, *next; 213862306a36Sopenharmony_ci unsigned int *order, n; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci /* Like drm_test_mm_color_evict(), but limited to small portion of the full 214162306a36Sopenharmony_ci * drm_mm range. 214262306a36Sopenharmony_ci */ 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 214562306a36Sopenharmony_ci KUNIT_ASSERT_TRUE(test, nodes); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci order = drm_random_order(total_size, &prng); 214862306a36Sopenharmony_ci if (!order) 214962306a36Sopenharmony_ci goto err_nodes; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci drm_mm_init(&mm, 0, 2 * total_size - 1); 215262306a36Sopenharmony_ci mm.color_adjust = separate_adjacent_colors; 215362306a36Sopenharmony_ci for (n = 0; n < total_size; n++) { 215462306a36Sopenharmony_ci if (!expect_insert(test, &mm, &nodes[n].node, 215562306a36Sopenharmony_ci 1, 0, color++, 215662306a36Sopenharmony_ci &insert_modes[0])) { 215762306a36Sopenharmony_ci KUNIT_FAIL(test, "insert failed, step %d\n", n); 215862306a36Sopenharmony_ci goto out; 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci for (mode = evict_modes; mode->name; mode++) { 216362306a36Sopenharmony_ci for (n = 1; n <= range_size; n <<= 1) { 216462306a36Sopenharmony_ci drm_random_reorder(order, range_size, &prng); 216562306a36Sopenharmony_ci if (evict_color(test, &mm, range_start, range_end, nodes, order, 216662306a36Sopenharmony_ci total_size, n, 1, color++, mode)) { 216762306a36Sopenharmony_ci KUNIT_FAIL(test, 216862306a36Sopenharmony_ci "%s evict_color(size=%u) failed for range [%x, %x]\n", 216962306a36Sopenharmony_ci mode->name, n, range_start, range_end); 217062306a36Sopenharmony_ci goto out; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci for (n = 1; n < range_size; n <<= 1) { 217562306a36Sopenharmony_ci drm_random_reorder(order, total_size, &prng); 217662306a36Sopenharmony_ci if (evict_color(test, &mm, range_start, range_end, nodes, order, 217762306a36Sopenharmony_ci total_size, range_size / 2, n, color++, mode)) { 217862306a36Sopenharmony_ci KUNIT_FAIL(test, 217962306a36Sopenharmony_ci "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 218062306a36Sopenharmony_ci mode->name, total_size / 2, n, range_start, range_end); 218162306a36Sopenharmony_ci goto out; 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 218662306a36Sopenharmony_ci unsigned int nsize = (range_size - n + 1) / 2; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci DRM_MM_BUG_ON(!nsize); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci drm_random_reorder(order, total_size, &prng); 219162306a36Sopenharmony_ci if (evict_color(test, &mm, range_start, range_end, nodes, order, 219262306a36Sopenharmony_ci total_size, nsize, n, color++, mode)) { 219362306a36Sopenharmony_ci KUNIT_FAIL(test, 219462306a36Sopenharmony_ci "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 219562306a36Sopenharmony_ci mode->name, nsize, n, range_start, range_end); 219662306a36Sopenharmony_ci goto out; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci cond_resched(); 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ciout: 220462306a36Sopenharmony_ci drm_mm_for_each_node_safe(node, next, &mm) 220562306a36Sopenharmony_ci drm_mm_remove_node(node); 220662306a36Sopenharmony_ci drm_mm_takedown(&mm); 220762306a36Sopenharmony_ci kfree(order); 220862306a36Sopenharmony_cierr_nodes: 220962306a36Sopenharmony_ci vfree(nodes); 221062306a36Sopenharmony_ci} 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_cistatic int drm_mm_suite_init(struct kunit_suite *suite) 221362306a36Sopenharmony_ci{ 221462306a36Sopenharmony_ci while (!random_seed) 221562306a36Sopenharmony_ci random_seed = get_random_u32(); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci kunit_info(suite, 221862306a36Sopenharmony_ci "Testing DRM range manager, with random_seed=0x%x max_iterations=%u max_prime=%u\n", 221962306a36Sopenharmony_ci random_seed, max_iterations, max_prime); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci return 0; 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cimodule_param(random_seed, uint, 0400); 222562306a36Sopenharmony_cimodule_param(max_iterations, uint, 0400); 222662306a36Sopenharmony_cimodule_param(max_prime, uint, 0400); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_cistatic struct kunit_case drm_mm_tests[] = { 222962306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_init), 223062306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_debug), 223162306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_reserve), 223262306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_insert), 223362306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_replace), 223462306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_insert_range), 223562306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_frag), 223662306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_align), 223762306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_align32), 223862306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_align64), 223962306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_evict), 224062306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_evict_range), 224162306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_topdown), 224262306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_bottomup), 224362306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_lowest), 224462306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_highest), 224562306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_color), 224662306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_color_evict), 224762306a36Sopenharmony_ci KUNIT_CASE(drm_test_mm_color_evict_range), 224862306a36Sopenharmony_ci {} 224962306a36Sopenharmony_ci}; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_cistatic struct kunit_suite drm_mm_test_suite = { 225262306a36Sopenharmony_ci .name = "drm_mm", 225362306a36Sopenharmony_ci .suite_init = drm_mm_suite_init, 225462306a36Sopenharmony_ci .test_cases = drm_mm_tests, 225562306a36Sopenharmony_ci}; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_cikunit_test_suite(drm_mm_test_suite); 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 226062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2261