1 1.1 riastrad /* $NetBSD: test-drm_mm.c,v 1.2 2021/12/18 23:45:44 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad // SPDX-License-Identifier: GPL-2.0-only 4 1.1 riastrad /* 5 1.1 riastrad * Test cases for the drm_mm range manager 6 1.1 riastrad */ 7 1.1 riastrad 8 1.1 riastrad #include <sys/cdefs.h> 9 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: test-drm_mm.c,v 1.2 2021/12/18 23:45:44 riastradh Exp $"); 10 1.1 riastrad 11 1.1 riastrad #define pr_fmt(fmt) "drm_mm: " fmt 12 1.1 riastrad 13 1.1 riastrad #include <linux/module.h> 14 1.1 riastrad #include <linux/prime_numbers.h> 15 1.1 riastrad #include <linux/slab.h> 16 1.1 riastrad #include <linux/random.h> 17 1.1 riastrad #include <linux/vmalloc.h> 18 1.1 riastrad 19 1.1 riastrad #include <drm/drm_mm.h> 20 1.1 riastrad 21 1.1 riastrad #include "../lib/drm_random.h" 22 1.1 riastrad 23 1.1 riastrad #define TESTS "drm_mm_selftests.h" 24 1.1 riastrad #include "drm_selftest.h" 25 1.1 riastrad 26 1.1 riastrad static unsigned int random_seed; 27 1.1 riastrad static unsigned int max_iterations = 8192; 28 1.1 riastrad static unsigned int max_prime = 128; 29 1.1 riastrad 30 1.1 riastrad enum { 31 1.1 riastrad BEST, 32 1.1 riastrad BOTTOMUP, 33 1.1 riastrad TOPDOWN, 34 1.1 riastrad EVICT, 35 1.1 riastrad }; 36 1.1 riastrad 37 1.1 riastrad static const struct insert_mode { 38 1.1 riastrad const char *name; 39 1.1 riastrad enum drm_mm_insert_mode mode; 40 1.1 riastrad } insert_modes[] = { 41 1.1 riastrad [BEST] = { "best", DRM_MM_INSERT_BEST }, 42 1.1 riastrad [BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW }, 43 1.1 riastrad [TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH }, 44 1.1 riastrad [EVICT] = { "evict", DRM_MM_INSERT_EVICT }, 45 1.1 riastrad {} 46 1.1 riastrad }, evict_modes[] = { 47 1.1 riastrad { "bottom-up", DRM_MM_INSERT_LOW }, 48 1.1 riastrad { "top-down", DRM_MM_INSERT_HIGH }, 49 1.1 riastrad {} 50 1.1 riastrad }; 51 1.1 riastrad 52 1.1 riastrad static int igt_sanitycheck(void *ignored) 53 1.1 riastrad { 54 1.1 riastrad pr_info("%s - ok!\n", __func__); 55 1.1 riastrad return 0; 56 1.1 riastrad } 57 1.1 riastrad 58 1.1 riastrad static bool assert_no_holes(const struct drm_mm *mm) 59 1.1 riastrad { 60 1.1 riastrad struct drm_mm_node *hole; 61 1.1 riastrad u64 hole_start, hole_end; 62 1.1 riastrad unsigned long count; 63 1.1 riastrad 64 1.1 riastrad count = 0; 65 1.1 riastrad drm_mm_for_each_hole(hole, mm, hole_start, hole_end) 66 1.1 riastrad count++; 67 1.1 riastrad if (count) { 68 1.1 riastrad pr_err("Expected to find no holes (after reserve), found %lu instead\n", count); 69 1.1 riastrad return false; 70 1.1 riastrad } 71 1.1 riastrad 72 1.1 riastrad drm_mm_for_each_node(hole, mm) { 73 1.1 riastrad if (drm_mm_hole_follows(hole)) { 74 1.1 riastrad pr_err("Hole follows node, expected none!\n"); 75 1.1 riastrad return false; 76 1.1 riastrad } 77 1.1 riastrad } 78 1.1 riastrad 79 1.1 riastrad return true; 80 1.1 riastrad } 81 1.1 riastrad 82 1.1 riastrad static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end) 83 1.1 riastrad { 84 1.1 riastrad struct drm_mm_node *hole; 85 1.1 riastrad u64 hole_start, hole_end; 86 1.1 riastrad unsigned long count; 87 1.1 riastrad bool ok = true; 88 1.1 riastrad 89 1.1 riastrad if (end <= start) 90 1.1 riastrad return true; 91 1.1 riastrad 92 1.1 riastrad count = 0; 93 1.1 riastrad drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 94 1.1 riastrad if (start != hole_start || end != hole_end) { 95 1.1 riastrad if (ok) 96 1.1 riastrad pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", 97 1.1 riastrad hole_start, hole_end, 98 1.1 riastrad start, end); 99 1.1 riastrad ok = false; 100 1.1 riastrad } 101 1.1 riastrad count++; 102 1.1 riastrad } 103 1.1 riastrad if (count != 1) { 104 1.1 riastrad pr_err("Expected to find one hole, found %lu instead\n", count); 105 1.1 riastrad ok = false; 106 1.1 riastrad } 107 1.1 riastrad 108 1.1 riastrad return ok; 109 1.1 riastrad } 110 1.1 riastrad 111 1.1 riastrad static bool assert_continuous(const struct drm_mm *mm, u64 size) 112 1.1 riastrad { 113 1.1 riastrad struct drm_mm_node *node, *check, *found; 114 1.1 riastrad unsigned long n; 115 1.1 riastrad u64 addr; 116 1.1 riastrad 117 1.1 riastrad if (!assert_no_holes(mm)) 118 1.1 riastrad return false; 119 1.1 riastrad 120 1.1 riastrad n = 0; 121 1.1 riastrad addr = 0; 122 1.1 riastrad drm_mm_for_each_node(node, mm) { 123 1.1 riastrad if (node->start != addr) { 124 1.1 riastrad pr_err("node[%ld] list out of order, expected %llx found %llx\n", 125 1.1 riastrad n, addr, node->start); 126 1.1 riastrad return false; 127 1.1 riastrad } 128 1.1 riastrad 129 1.1 riastrad if (node->size != size) { 130 1.1 riastrad pr_err("node[%ld].size incorrect, expected %llx, found %llx\n", 131 1.1 riastrad n, size, node->size); 132 1.1 riastrad return false; 133 1.1 riastrad } 134 1.1 riastrad 135 1.1 riastrad if (drm_mm_hole_follows(node)) { 136 1.1 riastrad pr_err("node[%ld] is followed by a hole!\n", n); 137 1.1 riastrad return false; 138 1.1 riastrad } 139 1.1 riastrad 140 1.1 riastrad found = NULL; 141 1.1 riastrad drm_mm_for_each_node_in_range(check, mm, addr, addr + size) { 142 1.1 riastrad if (node != check) { 143 1.1 riastrad pr_err("lookup return wrong node, expected start %llx, found %llx\n", 144 1.1 riastrad node->start, check->start); 145 1.1 riastrad return false; 146 1.1 riastrad } 147 1.1 riastrad found = check; 148 1.1 riastrad } 149 1.1 riastrad if (!found) { 150 1.1 riastrad pr_err("lookup failed for node %llx + %llx\n", 151 1.1 riastrad addr, size); 152 1.1 riastrad return false; 153 1.1 riastrad } 154 1.1 riastrad 155 1.1 riastrad addr += size; 156 1.1 riastrad n++; 157 1.1 riastrad } 158 1.1 riastrad 159 1.1 riastrad return true; 160 1.1 riastrad } 161 1.1 riastrad 162 1.1 riastrad static u64 misalignment(struct drm_mm_node *node, u64 alignment) 163 1.1 riastrad { 164 1.1 riastrad u64 rem; 165 1.1 riastrad 166 1.1 riastrad if (!alignment) 167 1.1 riastrad return 0; 168 1.1 riastrad 169 1.1 riastrad div64_u64_rem(node->start, alignment, &rem); 170 1.1 riastrad return rem; 171 1.1 riastrad } 172 1.1 riastrad 173 1.1 riastrad static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm, 174 1.1 riastrad u64 size, u64 alignment, unsigned long color) 175 1.1 riastrad { 176 1.1 riastrad bool ok = true; 177 1.1 riastrad 178 1.1 riastrad if (!drm_mm_node_allocated(node) || node->mm != mm) { 179 1.1 riastrad pr_err("node not allocated\n"); 180 1.1 riastrad ok = false; 181 1.1 riastrad } 182 1.1 riastrad 183 1.1 riastrad if (node->size != size) { 184 1.1 riastrad pr_err("node has wrong size, found %llu, expected %llu\n", 185 1.1 riastrad node->size, size); 186 1.1 riastrad ok = false; 187 1.1 riastrad } 188 1.1 riastrad 189 1.1 riastrad if (misalignment(node, alignment)) { 190 1.1 riastrad pr_err("node is misaligned, start %llx rem %llu, expected alignment %llu\n", 191 1.1 riastrad node->start, misalignment(node, alignment), alignment); 192 1.1 riastrad ok = false; 193 1.1 riastrad } 194 1.1 riastrad 195 1.1 riastrad if (node->color != color) { 196 1.1 riastrad pr_err("node has wrong color, found %lu, expected %lu\n", 197 1.1 riastrad node->color, color); 198 1.1 riastrad ok = false; 199 1.1 riastrad } 200 1.1 riastrad 201 1.1 riastrad return ok; 202 1.1 riastrad } 203 1.1 riastrad 204 1.1 riastrad #define show_mm(mm) do { \ 205 1.1 riastrad struct drm_printer __p = drm_debug_printer(__func__); \ 206 1.1 riastrad drm_mm_print((mm), &__p); } while (0) 207 1.1 riastrad 208 1.1 riastrad static int igt_init(void *ignored) 209 1.1 riastrad { 210 1.1 riastrad const unsigned int size = 4096; 211 1.1 riastrad struct drm_mm mm; 212 1.1 riastrad struct drm_mm_node tmp; 213 1.1 riastrad int ret = -EINVAL; 214 1.1 riastrad 215 1.1 riastrad /* Start with some simple checks on initialising the struct drm_mm */ 216 1.1 riastrad memset(&mm, 0, sizeof(mm)); 217 1.1 riastrad if (drm_mm_initialized(&mm)) { 218 1.1 riastrad pr_err("zeroed mm claims to be initialized\n"); 219 1.1 riastrad return ret; 220 1.1 riastrad } 221 1.1 riastrad 222 1.1 riastrad memset(&mm, 0xff, sizeof(mm)); 223 1.1 riastrad drm_mm_init(&mm, 0, size); 224 1.1 riastrad if (!drm_mm_initialized(&mm)) { 225 1.1 riastrad pr_err("mm claims not to be initialized\n"); 226 1.1 riastrad goto out; 227 1.1 riastrad } 228 1.1 riastrad 229 1.1 riastrad if (!drm_mm_clean(&mm)) { 230 1.1 riastrad pr_err("mm not empty on creation\n"); 231 1.1 riastrad goto out; 232 1.1 riastrad } 233 1.1 riastrad 234 1.1 riastrad /* After creation, it should all be one massive hole */ 235 1.1 riastrad if (!assert_one_hole(&mm, 0, size)) { 236 1.1 riastrad ret = -EINVAL; 237 1.1 riastrad goto out; 238 1.1 riastrad } 239 1.1 riastrad 240 1.1 riastrad memset(&tmp, 0, sizeof(tmp)); 241 1.1 riastrad tmp.start = 0; 242 1.1 riastrad tmp.size = size; 243 1.1 riastrad ret = drm_mm_reserve_node(&mm, &tmp); 244 1.1 riastrad if (ret) { 245 1.1 riastrad pr_err("failed to reserve whole drm_mm\n"); 246 1.1 riastrad goto out; 247 1.1 riastrad } 248 1.1 riastrad 249 1.1 riastrad /* After filling the range entirely, there should be no holes */ 250 1.1 riastrad if (!assert_no_holes(&mm)) { 251 1.1 riastrad ret = -EINVAL; 252 1.1 riastrad goto out; 253 1.1 riastrad } 254 1.1 riastrad 255 1.1 riastrad /* And then after emptying it again, the massive hole should be back */ 256 1.1 riastrad drm_mm_remove_node(&tmp); 257 1.1 riastrad if (!assert_one_hole(&mm, 0, size)) { 258 1.1 riastrad ret = -EINVAL; 259 1.1 riastrad goto out; 260 1.1 riastrad } 261 1.1 riastrad 262 1.1 riastrad out: 263 1.1 riastrad if (ret) 264 1.1 riastrad show_mm(&mm); 265 1.1 riastrad drm_mm_takedown(&mm); 266 1.1 riastrad return ret; 267 1.1 riastrad } 268 1.1 riastrad 269 1.1 riastrad static int igt_debug(void *ignored) 270 1.1 riastrad { 271 1.1 riastrad struct drm_mm mm; 272 1.1 riastrad struct drm_mm_node nodes[2]; 273 1.1 riastrad int ret; 274 1.1 riastrad 275 1.1 riastrad /* Create a small drm_mm with a couple of nodes and a few holes, and 276 1.1 riastrad * check that the debug iterator doesn't explode over a trivial drm_mm. 277 1.1 riastrad */ 278 1.1 riastrad 279 1.1 riastrad drm_mm_init(&mm, 0, 4096); 280 1.1 riastrad 281 1.1 riastrad memset(nodes, 0, sizeof(nodes)); 282 1.1 riastrad nodes[0].start = 512; 283 1.1 riastrad nodes[0].size = 1024; 284 1.1 riastrad ret = drm_mm_reserve_node(&mm, &nodes[0]); 285 1.1 riastrad if (ret) { 286 1.1 riastrad pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n", 287 1.1 riastrad nodes[0].start, nodes[0].size); 288 1.1 riastrad return ret; 289 1.1 riastrad } 290 1.1 riastrad 291 1.1 riastrad nodes[1].size = 1024; 292 1.1 riastrad nodes[1].start = 4096 - 512 - nodes[1].size; 293 1.1 riastrad ret = drm_mm_reserve_node(&mm, &nodes[1]); 294 1.1 riastrad if (ret) { 295 1.1 riastrad pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n", 296 1.1 riastrad nodes[1].start, nodes[1].size); 297 1.1 riastrad return ret; 298 1.1 riastrad } 299 1.1 riastrad 300 1.1 riastrad show_mm(&mm); 301 1.1 riastrad return 0; 302 1.1 riastrad } 303 1.1 riastrad 304 1.1 riastrad static struct drm_mm_node *set_node(struct drm_mm_node *node, 305 1.1 riastrad u64 start, u64 size) 306 1.1 riastrad { 307 1.1 riastrad node->start = start; 308 1.1 riastrad node->size = size; 309 1.1 riastrad return node; 310 1.1 riastrad } 311 1.1 riastrad 312 1.1 riastrad static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node) 313 1.1 riastrad { 314 1.1 riastrad int err; 315 1.1 riastrad 316 1.1 riastrad err = drm_mm_reserve_node(mm, node); 317 1.1 riastrad if (likely(err == -ENOSPC)) 318 1.1 riastrad return true; 319 1.1 riastrad 320 1.1 riastrad if (!err) { 321 1.1 riastrad pr_err("impossible reserve succeeded, node %llu + %llu\n", 322 1.1 riastrad node->start, node->size); 323 1.1 riastrad drm_mm_remove_node(node); 324 1.1 riastrad } else { 325 1.1 riastrad pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", 326 1.1 riastrad err, -ENOSPC, node->start, node->size); 327 1.1 riastrad } 328 1.1 riastrad return false; 329 1.1 riastrad } 330 1.1 riastrad 331 1.1 riastrad static bool check_reserve_boundaries(struct drm_mm *mm, 332 1.1 riastrad unsigned int count, 333 1.1 riastrad u64 size) 334 1.1 riastrad { 335 1.1 riastrad const struct boundary { 336 1.1 riastrad u64 start, size; 337 1.1 riastrad const char *name; 338 1.1 riastrad } boundaries[] = { 339 1.1 riastrad #define B(st, sz) { (st), (sz), "{ " #st ", " #sz "}" } 340 1.1 riastrad B(0, 0), 341 1.1 riastrad B(-size, 0), 342 1.1 riastrad B(size, 0), 343 1.1 riastrad B(size * count, 0), 344 1.1 riastrad B(-size, size), 345 1.1 riastrad B(-size, -size), 346 1.1 riastrad B(-size, 2*size), 347 1.1 riastrad B(0, -size), 348 1.1 riastrad B(size, -size), 349 1.1 riastrad B(count*size, size), 350 1.1 riastrad B(count*size, -size), 351 1.1 riastrad B(count*size, count*size), 352 1.1 riastrad B(count*size, -count*size), 353 1.1 riastrad B(count*size, -(count+1)*size), 354 1.1 riastrad B((count+1)*size, size), 355 1.1 riastrad B((count+1)*size, -size), 356 1.1 riastrad B((count+1)*size, -2*size), 357 1.1 riastrad #undef B 358 1.1 riastrad }; 359 1.1 riastrad struct drm_mm_node tmp = {}; 360 1.1 riastrad int n; 361 1.1 riastrad 362 1.1 riastrad for (n = 0; n < ARRAY_SIZE(boundaries); n++) { 363 1.1 riastrad if (!expect_reserve_fail(mm, 364 1.1 riastrad set_node(&tmp, 365 1.1 riastrad boundaries[n].start, 366 1.1 riastrad boundaries[n].size))) { 367 1.1 riastrad pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n", 368 1.1 riastrad n, boundaries[n].name, count, size); 369 1.1 riastrad return false; 370 1.1 riastrad } 371 1.1 riastrad } 372 1.1 riastrad 373 1.1 riastrad return true; 374 1.1 riastrad } 375 1.1 riastrad 376 1.1 riastrad static int __igt_reserve(unsigned int count, u64 size) 377 1.1 riastrad { 378 1.1 riastrad DRM_RND_STATE(prng, random_seed); 379 1.1 riastrad struct drm_mm mm; 380 1.1 riastrad struct drm_mm_node tmp, *nodes, *node, *next; 381 1.1 riastrad unsigned int *order, n, m, o = 0; 382 1.1 riastrad int ret, err; 383 1.1 riastrad 384 1.1 riastrad /* For exercising drm_mm_reserve_node(), we want to check that 385 1.1 riastrad * reservations outside of the drm_mm range are rejected, and to 386 1.1 riastrad * overlapping and otherwise already occupied ranges. Afterwards, 387 1.1 riastrad * the tree and nodes should be intact. 388 1.1 riastrad */ 389 1.1 riastrad 390 1.1 riastrad DRM_MM_BUG_ON(!count); 391 1.1 riastrad DRM_MM_BUG_ON(!size); 392 1.1 riastrad 393 1.1 riastrad ret = -ENOMEM; 394 1.1 riastrad order = drm_random_order(count, &prng); 395 1.1 riastrad if (!order) 396 1.1 riastrad goto err; 397 1.1 riastrad 398 1.1 riastrad nodes = vzalloc(array_size(count, sizeof(*nodes))); 399 1.1 riastrad if (!nodes) 400 1.1 riastrad goto err_order; 401 1.1 riastrad 402 1.1 riastrad ret = -EINVAL; 403 1.1 riastrad drm_mm_init(&mm, 0, count * size); 404 1.1 riastrad 405 1.1 riastrad if (!check_reserve_boundaries(&mm, count, size)) 406 1.1 riastrad goto out; 407 1.1 riastrad 408 1.1 riastrad for (n = 0; n < count; n++) { 409 1.1 riastrad nodes[n].start = order[n] * size; 410 1.1 riastrad nodes[n].size = size; 411 1.1 riastrad 412 1.1 riastrad err = drm_mm_reserve_node(&mm, &nodes[n]); 413 1.1 riastrad if (err) { 414 1.1 riastrad pr_err("reserve failed, step %d, start %llu\n", 415 1.1 riastrad n, nodes[n].start); 416 1.1 riastrad ret = err; 417 1.1 riastrad goto out; 418 1.1 riastrad } 419 1.1 riastrad 420 1.1 riastrad if (!drm_mm_node_allocated(&nodes[n])) { 421 1.1 riastrad pr_err("reserved node not allocated! step %d, start %llu\n", 422 1.1 riastrad n, nodes[n].start); 423 1.1 riastrad goto out; 424 1.1 riastrad } 425 1.1 riastrad 426 1.1 riastrad if (!expect_reserve_fail(&mm, &nodes[n])) 427 1.1 riastrad goto out; 428 1.1 riastrad } 429 1.1 riastrad 430 1.1 riastrad /* After random insertion the nodes should be in order */ 431 1.1 riastrad if (!assert_continuous(&mm, size)) 432 1.1 riastrad goto out; 433 1.1 riastrad 434 1.1 riastrad /* Repeated use should then fail */ 435 1.1 riastrad drm_random_reorder(order, count, &prng); 436 1.1 riastrad for (n = 0; n < count; n++) { 437 1.1 riastrad if (!expect_reserve_fail(&mm, 438 1.1 riastrad set_node(&tmp, order[n] * size, 1))) 439 1.1 riastrad goto out; 440 1.1 riastrad 441 1.1 riastrad /* Remove and reinsert should work */ 442 1.1 riastrad drm_mm_remove_node(&nodes[order[n]]); 443 1.1 riastrad err = drm_mm_reserve_node(&mm, &nodes[order[n]]); 444 1.1 riastrad if (err) { 445 1.1 riastrad pr_err("reserve failed, step %d, start %llu\n", 446 1.1 riastrad n, nodes[n].start); 447 1.1 riastrad ret = err; 448 1.1 riastrad goto out; 449 1.1 riastrad } 450 1.1 riastrad } 451 1.1 riastrad 452 1.1 riastrad if (!assert_continuous(&mm, size)) 453 1.1 riastrad goto out; 454 1.1 riastrad 455 1.1 riastrad /* Overlapping use should then fail */ 456 1.1 riastrad for (n = 0; n < count; n++) { 457 1.1 riastrad if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count))) 458 1.1 riastrad goto out; 459 1.1 riastrad } 460 1.1 riastrad for (n = 0; n < count; n++) { 461 1.1 riastrad if (!expect_reserve_fail(&mm, 462 1.1 riastrad set_node(&tmp, 463 1.1 riastrad size * n, 464 1.1 riastrad size * (count - n)))) 465 1.1 riastrad goto out; 466 1.1 riastrad } 467 1.1 riastrad 468 1.1 riastrad /* Remove several, reinsert, check full */ 469 1.1 riastrad for_each_prime_number(n, min(max_prime, count)) { 470 1.1 riastrad for (m = 0; m < n; m++) { 471 1.1 riastrad node = &nodes[order[(o + m) % count]]; 472 1.1 riastrad drm_mm_remove_node(node); 473 1.1 riastrad } 474 1.1 riastrad 475 1.1 riastrad for (m = 0; m < n; m++) { 476 1.1 riastrad node = &nodes[order[(o + m) % count]]; 477 1.1 riastrad err = drm_mm_reserve_node(&mm, node); 478 1.1 riastrad if (err) { 479 1.1 riastrad pr_err("reserve failed, step %d/%d, start %llu\n", 480 1.1 riastrad m, n, node->start); 481 1.1 riastrad ret = err; 482 1.1 riastrad goto out; 483 1.1 riastrad } 484 1.1 riastrad } 485 1.1 riastrad 486 1.1 riastrad o += n; 487 1.1 riastrad 488 1.1 riastrad if (!assert_continuous(&mm, size)) 489 1.1 riastrad goto out; 490 1.1 riastrad } 491 1.1 riastrad 492 1.1 riastrad ret = 0; 493 1.1 riastrad out: 494 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 495 1.1 riastrad drm_mm_remove_node(node); 496 1.1 riastrad drm_mm_takedown(&mm); 497 1.1 riastrad vfree(nodes); 498 1.1 riastrad err_order: 499 1.1 riastrad kfree(order); 500 1.1 riastrad err: 501 1.1 riastrad return ret; 502 1.1 riastrad } 503 1.1 riastrad 504 1.1 riastrad static int igt_reserve(void *ignored) 505 1.1 riastrad { 506 1.1 riastrad const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 507 1.1 riastrad int n, ret; 508 1.1 riastrad 509 1.1 riastrad for_each_prime_number_from(n, 1, 54) { 510 1.1 riastrad u64 size = BIT_ULL(n); 511 1.1 riastrad 512 1.1 riastrad ret = __igt_reserve(count, size - 1); 513 1.1 riastrad if (ret) 514 1.1 riastrad return ret; 515 1.1 riastrad 516 1.1 riastrad ret = __igt_reserve(count, size); 517 1.1 riastrad if (ret) 518 1.1 riastrad return ret; 519 1.1 riastrad 520 1.1 riastrad ret = __igt_reserve(count, size + 1); 521 1.1 riastrad if (ret) 522 1.1 riastrad return ret; 523 1.1 riastrad 524 1.1 riastrad cond_resched(); 525 1.1 riastrad } 526 1.1 riastrad 527 1.1 riastrad return 0; 528 1.1 riastrad } 529 1.1 riastrad 530 1.1 riastrad static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node, 531 1.1 riastrad u64 size, u64 alignment, unsigned long color, 532 1.1 riastrad const struct insert_mode *mode) 533 1.1 riastrad { 534 1.1 riastrad int err; 535 1.1 riastrad 536 1.1 riastrad err = drm_mm_insert_node_generic(mm, node, 537 1.1 riastrad size, alignment, color, 538 1.1 riastrad mode->mode); 539 1.1 riastrad if (err) { 540 1.1 riastrad pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", 541 1.1 riastrad size, alignment, color, mode->name, err); 542 1.1 riastrad return false; 543 1.1 riastrad } 544 1.1 riastrad 545 1.1 riastrad if (!assert_node(node, mm, size, alignment, color)) { 546 1.1 riastrad drm_mm_remove_node(node); 547 1.1 riastrad return false; 548 1.1 riastrad } 549 1.1 riastrad 550 1.1 riastrad return true; 551 1.1 riastrad } 552 1.1 riastrad 553 1.1 riastrad static bool expect_insert_fail(struct drm_mm *mm, u64 size) 554 1.1 riastrad { 555 1.1 riastrad struct drm_mm_node tmp = {}; 556 1.1 riastrad int err; 557 1.1 riastrad 558 1.1 riastrad err = drm_mm_insert_node(mm, &tmp, size); 559 1.1 riastrad if (likely(err == -ENOSPC)) 560 1.1 riastrad return true; 561 1.1 riastrad 562 1.1 riastrad if (!err) { 563 1.1 riastrad pr_err("impossible insert succeeded, node %llu + %llu\n", 564 1.1 riastrad tmp.start, tmp.size); 565 1.1 riastrad drm_mm_remove_node(&tmp); 566 1.1 riastrad } else { 567 1.1 riastrad pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n", 568 1.1 riastrad err, -ENOSPC, size); 569 1.1 riastrad } 570 1.1 riastrad return false; 571 1.1 riastrad } 572 1.1 riastrad 573 1.1 riastrad static int __igt_insert(unsigned int count, u64 size, bool replace) 574 1.1 riastrad { 575 1.1 riastrad DRM_RND_STATE(prng, random_seed); 576 1.1 riastrad const struct insert_mode *mode; 577 1.1 riastrad struct drm_mm mm; 578 1.1 riastrad struct drm_mm_node *nodes, *node, *next; 579 1.1 riastrad unsigned int *order, n, m, o = 0; 580 1.1 riastrad int ret; 581 1.1 riastrad 582 1.1 riastrad /* Fill a range with lots of nodes, check it doesn't fail too early */ 583 1.1 riastrad 584 1.1 riastrad DRM_MM_BUG_ON(!count); 585 1.1 riastrad DRM_MM_BUG_ON(!size); 586 1.1 riastrad 587 1.1 riastrad ret = -ENOMEM; 588 1.1 riastrad nodes = vmalloc(array_size(count, sizeof(*nodes))); 589 1.1 riastrad if (!nodes) 590 1.1 riastrad goto err; 591 1.1 riastrad 592 1.1 riastrad order = drm_random_order(count, &prng); 593 1.1 riastrad if (!order) 594 1.1 riastrad goto err_nodes; 595 1.1 riastrad 596 1.1 riastrad ret = -EINVAL; 597 1.1 riastrad drm_mm_init(&mm, 0, count * size); 598 1.1 riastrad 599 1.1 riastrad for (mode = insert_modes; mode->name; mode++) { 600 1.1 riastrad for (n = 0; n < count; n++) { 601 1.1 riastrad struct drm_mm_node tmp; 602 1.1 riastrad 603 1.1 riastrad node = replace ? &tmp : &nodes[n]; 604 1.1 riastrad memset(node, 0, sizeof(*node)); 605 1.1 riastrad if (!expect_insert(&mm, node, size, 0, n, mode)) { 606 1.1 riastrad pr_err("%s insert failed, size %llu step %d\n", 607 1.1 riastrad mode->name, size, n); 608 1.1 riastrad goto out; 609 1.1 riastrad } 610 1.1 riastrad 611 1.1 riastrad if (replace) { 612 1.1 riastrad drm_mm_replace_node(&tmp, &nodes[n]); 613 1.1 riastrad if (drm_mm_node_allocated(&tmp)) { 614 1.1 riastrad pr_err("replaced old-node still allocated! step %d\n", 615 1.1 riastrad n); 616 1.1 riastrad goto out; 617 1.1 riastrad } 618 1.1 riastrad 619 1.1 riastrad if (!assert_node(&nodes[n], &mm, size, 0, n)) { 620 1.1 riastrad pr_err("replaced node did not inherit parameters, size %llu step %d\n", 621 1.1 riastrad size, n); 622 1.1 riastrad goto out; 623 1.1 riastrad } 624 1.1 riastrad 625 1.1 riastrad if (tmp.start != nodes[n].start) { 626 1.1 riastrad pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", 627 1.1 riastrad tmp.start, size, 628 1.1 riastrad nodes[n].start, nodes[n].size); 629 1.1 riastrad goto out; 630 1.1 riastrad } 631 1.1 riastrad } 632 1.1 riastrad } 633 1.1 riastrad 634 1.1 riastrad /* After random insertion the nodes should be in order */ 635 1.1 riastrad if (!assert_continuous(&mm, size)) 636 1.1 riastrad goto out; 637 1.1 riastrad 638 1.1 riastrad /* Repeated use should then fail */ 639 1.1 riastrad if (!expect_insert_fail(&mm, size)) 640 1.1 riastrad goto out; 641 1.1 riastrad 642 1.1 riastrad /* Remove one and reinsert, as the only hole it should refill itself */ 643 1.1 riastrad for (n = 0; n < count; n++) { 644 1.1 riastrad u64 addr = nodes[n].start; 645 1.1 riastrad 646 1.1 riastrad drm_mm_remove_node(&nodes[n]); 647 1.1 riastrad if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) { 648 1.1 riastrad pr_err("%s reinsert failed, size %llu step %d\n", 649 1.1 riastrad mode->name, size, n); 650 1.1 riastrad goto out; 651 1.1 riastrad } 652 1.1 riastrad 653 1.1 riastrad if (nodes[n].start != addr) { 654 1.1 riastrad pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", 655 1.1 riastrad mode->name, n, addr, nodes[n].start); 656 1.1 riastrad goto out; 657 1.1 riastrad } 658 1.1 riastrad 659 1.1 riastrad if (!assert_continuous(&mm, size)) 660 1.1 riastrad goto out; 661 1.1 riastrad } 662 1.1 riastrad 663 1.1 riastrad /* Remove several, reinsert, check full */ 664 1.1 riastrad for_each_prime_number(n, min(max_prime, count)) { 665 1.1 riastrad for (m = 0; m < n; m++) { 666 1.1 riastrad node = &nodes[order[(o + m) % count]]; 667 1.1 riastrad drm_mm_remove_node(node); 668 1.1 riastrad } 669 1.1 riastrad 670 1.1 riastrad for (m = 0; m < n; m++) { 671 1.1 riastrad node = &nodes[order[(o + m) % count]]; 672 1.1 riastrad if (!expect_insert(&mm, node, size, 0, n, mode)) { 673 1.1 riastrad pr_err("%s multiple reinsert failed, size %llu step %d\n", 674 1.1 riastrad mode->name, size, n); 675 1.1 riastrad goto out; 676 1.1 riastrad } 677 1.1 riastrad } 678 1.1 riastrad 679 1.1 riastrad o += n; 680 1.1 riastrad 681 1.1 riastrad if (!assert_continuous(&mm, size)) 682 1.1 riastrad goto out; 683 1.1 riastrad 684 1.1 riastrad if (!expect_insert_fail(&mm, size)) 685 1.1 riastrad goto out; 686 1.1 riastrad } 687 1.1 riastrad 688 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 689 1.1 riastrad drm_mm_remove_node(node); 690 1.1 riastrad DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 691 1.1 riastrad 692 1.1 riastrad cond_resched(); 693 1.1 riastrad } 694 1.1 riastrad 695 1.1 riastrad ret = 0; 696 1.1 riastrad out: 697 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 698 1.1 riastrad drm_mm_remove_node(node); 699 1.1 riastrad drm_mm_takedown(&mm); 700 1.1 riastrad kfree(order); 701 1.1 riastrad err_nodes: 702 1.1 riastrad vfree(nodes); 703 1.1 riastrad err: 704 1.1 riastrad return ret; 705 1.1 riastrad } 706 1.1 riastrad 707 1.1 riastrad static int igt_insert(void *ignored) 708 1.1 riastrad { 709 1.1 riastrad const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 710 1.1 riastrad unsigned int n; 711 1.1 riastrad int ret; 712 1.1 riastrad 713 1.1 riastrad for_each_prime_number_from(n, 1, 54) { 714 1.1 riastrad u64 size = BIT_ULL(n); 715 1.1 riastrad 716 1.1 riastrad ret = __igt_insert(count, size - 1, false); 717 1.1 riastrad if (ret) 718 1.1 riastrad return ret; 719 1.1 riastrad 720 1.1 riastrad ret = __igt_insert(count, size, false); 721 1.1 riastrad if (ret) 722 1.1 riastrad return ret; 723 1.1 riastrad 724 1.1 riastrad ret = __igt_insert(count, size + 1, false); 725 1.1 riastrad if (ret) 726 1.1 riastrad return ret; 727 1.1 riastrad 728 1.1 riastrad cond_resched(); 729 1.1 riastrad } 730 1.1 riastrad 731 1.1 riastrad return 0; 732 1.1 riastrad } 733 1.1 riastrad 734 1.1 riastrad static int igt_replace(void *ignored) 735 1.1 riastrad { 736 1.1 riastrad const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); 737 1.1 riastrad unsigned int n; 738 1.1 riastrad int ret; 739 1.1 riastrad 740 1.1 riastrad /* Reuse igt_insert to exercise replacement by inserting a dummy node, 741 1.1 riastrad * then replacing it with the intended node. We want to check that 742 1.1 riastrad * the tree is intact and all the information we need is carried 743 1.1 riastrad * across to the target node. 744 1.1 riastrad */ 745 1.1 riastrad 746 1.1 riastrad for_each_prime_number_from(n, 1, 54) { 747 1.1 riastrad u64 size = BIT_ULL(n); 748 1.1 riastrad 749 1.1 riastrad ret = __igt_insert(count, size - 1, true); 750 1.1 riastrad if (ret) 751 1.1 riastrad return ret; 752 1.1 riastrad 753 1.1 riastrad ret = __igt_insert(count, size, true); 754 1.1 riastrad if (ret) 755 1.1 riastrad return ret; 756 1.1 riastrad 757 1.1 riastrad ret = __igt_insert(count, size + 1, true); 758 1.1 riastrad if (ret) 759 1.1 riastrad return ret; 760 1.1 riastrad 761 1.1 riastrad cond_resched(); 762 1.1 riastrad } 763 1.1 riastrad 764 1.1 riastrad return 0; 765 1.1 riastrad } 766 1.1 riastrad 767 1.1 riastrad static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node, 768 1.1 riastrad u64 size, u64 alignment, unsigned long color, 769 1.1 riastrad u64 range_start, u64 range_end, 770 1.1 riastrad const struct insert_mode *mode) 771 1.1 riastrad { 772 1.1 riastrad int err; 773 1.1 riastrad 774 1.1 riastrad err = drm_mm_insert_node_in_range(mm, node, 775 1.1 riastrad size, alignment, color, 776 1.1 riastrad range_start, range_end, 777 1.1 riastrad mode->mode); 778 1.1 riastrad if (err) { 779 1.1 riastrad pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", 780 1.1 riastrad size, alignment, color, mode->name, 781 1.1 riastrad range_start, range_end, err); 782 1.1 riastrad return false; 783 1.1 riastrad } 784 1.1 riastrad 785 1.1 riastrad if (!assert_node(node, mm, size, alignment, color)) { 786 1.1 riastrad drm_mm_remove_node(node); 787 1.1 riastrad return false; 788 1.1 riastrad } 789 1.1 riastrad 790 1.1 riastrad return true; 791 1.1 riastrad } 792 1.1 riastrad 793 1.1 riastrad static bool expect_insert_in_range_fail(struct drm_mm *mm, 794 1.1 riastrad u64 size, 795 1.1 riastrad u64 range_start, 796 1.1 riastrad u64 range_end) 797 1.1 riastrad { 798 1.1 riastrad struct drm_mm_node tmp = {}; 799 1.1 riastrad int err; 800 1.1 riastrad 801 1.1 riastrad err = drm_mm_insert_node_in_range(mm, &tmp, 802 1.1 riastrad size, 0, 0, 803 1.1 riastrad range_start, range_end, 804 1.1 riastrad 0); 805 1.1 riastrad if (likely(err == -ENOSPC)) 806 1.1 riastrad return true; 807 1.1 riastrad 808 1.1 riastrad if (!err) { 809 1.1 riastrad pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", 810 1.1 riastrad tmp.start, tmp.size, range_start, range_end); 811 1.1 riastrad drm_mm_remove_node(&tmp); 812 1.1 riastrad } else { 813 1.1 riastrad pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", 814 1.1 riastrad err, -ENOSPC, size, range_start, range_end); 815 1.1 riastrad } 816 1.1 riastrad 817 1.1 riastrad return false; 818 1.1 riastrad } 819 1.1 riastrad 820 1.1 riastrad static bool assert_contiguous_in_range(struct drm_mm *mm, 821 1.1 riastrad u64 size, 822 1.1 riastrad u64 start, 823 1.1 riastrad u64 end) 824 1.1 riastrad { 825 1.1 riastrad struct drm_mm_node *node; 826 1.1 riastrad unsigned int n; 827 1.1 riastrad 828 1.1 riastrad if (!expect_insert_in_range_fail(mm, size, start, end)) 829 1.1 riastrad return false; 830 1.1 riastrad 831 1.1 riastrad n = div64_u64(start + size - 1, size); 832 1.1 riastrad drm_mm_for_each_node(node, mm) { 833 1.1 riastrad if (node->start < start || node->start + node->size > end) { 834 1.1 riastrad pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", 835 1.1 riastrad n, node->start, node->start + node->size, start, end); 836 1.1 riastrad return false; 837 1.1 riastrad } 838 1.1 riastrad 839 1.1 riastrad if (node->start != n * size) { 840 1.1 riastrad pr_err("node %d out of order, expected start %llx, found %llx\n", 841 1.1 riastrad n, n * size, node->start); 842 1.1 riastrad return false; 843 1.1 riastrad } 844 1.1 riastrad 845 1.1 riastrad if (node->size != size) { 846 1.1 riastrad pr_err("node %d has wrong size, expected size %llx, found %llx\n", 847 1.1 riastrad n, size, node->size); 848 1.1 riastrad return false; 849 1.1 riastrad } 850 1.1 riastrad 851 1.1 riastrad if (drm_mm_hole_follows(node) && 852 1.1 riastrad drm_mm_hole_node_end(node) < end) { 853 1.1 riastrad pr_err("node %d is followed by a hole!\n", n); 854 1.1 riastrad return false; 855 1.1 riastrad } 856 1.1 riastrad 857 1.1 riastrad n++; 858 1.1 riastrad } 859 1.1 riastrad 860 1.1 riastrad if (start > 0) { 861 1.1 riastrad node = __drm_mm_interval_first(mm, 0, start - 1); 862 1.1 riastrad if (drm_mm_node_allocated(node)) { 863 1.1 riastrad pr_err("node before start: node=%llx+%llu, start=%llx\n", 864 1.1 riastrad node->start, node->size, start); 865 1.1 riastrad return false; 866 1.1 riastrad } 867 1.1 riastrad } 868 1.1 riastrad 869 1.1 riastrad if (end < U64_MAX) { 870 1.1 riastrad node = __drm_mm_interval_first(mm, end, U64_MAX); 871 1.1 riastrad if (drm_mm_node_allocated(node)) { 872 1.1 riastrad pr_err("node after end: node=%llx+%llu, end=%llx\n", 873 1.1 riastrad node->start, node->size, end); 874 1.1 riastrad return false; 875 1.1 riastrad } 876 1.1 riastrad } 877 1.1 riastrad 878 1.1 riastrad return true; 879 1.1 riastrad } 880 1.1 riastrad 881 1.1 riastrad static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) 882 1.1 riastrad { 883 1.1 riastrad const struct insert_mode *mode; 884 1.1 riastrad struct drm_mm mm; 885 1.1 riastrad struct drm_mm_node *nodes, *node, *next; 886 1.1 riastrad unsigned int n, start_n, end_n; 887 1.1 riastrad int ret; 888 1.1 riastrad 889 1.1 riastrad DRM_MM_BUG_ON(!count); 890 1.1 riastrad DRM_MM_BUG_ON(!size); 891 1.1 riastrad DRM_MM_BUG_ON(end <= start); 892 1.1 riastrad 893 1.1 riastrad /* Very similar to __igt_insert(), but now instead of populating the 894 1.1 riastrad * full range of the drm_mm, we try to fill a small portion of it. 895 1.1 riastrad */ 896 1.1 riastrad 897 1.1 riastrad ret = -ENOMEM; 898 1.1 riastrad nodes = vzalloc(array_size(count, sizeof(*nodes))); 899 1.1 riastrad if (!nodes) 900 1.1 riastrad goto err; 901 1.1 riastrad 902 1.1 riastrad ret = -EINVAL; 903 1.1 riastrad drm_mm_init(&mm, 0, count * size); 904 1.1 riastrad 905 1.1 riastrad start_n = div64_u64(start + size - 1, size); 906 1.1 riastrad end_n = div64_u64(end - size, size); 907 1.1 riastrad 908 1.1 riastrad for (mode = insert_modes; mode->name; mode++) { 909 1.1 riastrad for (n = start_n; n <= end_n; n++) { 910 1.1 riastrad if (!expect_insert_in_range(&mm, &nodes[n], 911 1.1 riastrad size, size, n, 912 1.1 riastrad start, end, mode)) { 913 1.1 riastrad pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", 914 1.1 riastrad mode->name, size, n, 915 1.1 riastrad start_n, end_n, 916 1.1 riastrad start, end); 917 1.1 riastrad goto out; 918 1.1 riastrad } 919 1.1 riastrad } 920 1.1 riastrad 921 1.1 riastrad if (!assert_contiguous_in_range(&mm, size, start, end)) { 922 1.1 riastrad pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n", 923 1.1 riastrad mode->name, start, end, size); 924 1.1 riastrad goto out; 925 1.1 riastrad } 926 1.1 riastrad 927 1.1 riastrad /* Remove one and reinsert, it should refill itself */ 928 1.1 riastrad for (n = start_n; n <= end_n; n++) { 929 1.1 riastrad u64 addr = nodes[n].start; 930 1.1 riastrad 931 1.1 riastrad drm_mm_remove_node(&nodes[n]); 932 1.1 riastrad if (!expect_insert_in_range(&mm, &nodes[n], 933 1.1 riastrad size, size, n, 934 1.1 riastrad start, end, mode)) { 935 1.1 riastrad pr_err("%s reinsert failed, step %d\n", mode->name, n); 936 1.1 riastrad goto out; 937 1.1 riastrad } 938 1.1 riastrad 939 1.1 riastrad if (nodes[n].start != addr) { 940 1.1 riastrad pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", 941 1.1 riastrad mode->name, n, addr, nodes[n].start); 942 1.1 riastrad goto out; 943 1.1 riastrad } 944 1.1 riastrad } 945 1.1 riastrad 946 1.1 riastrad if (!assert_contiguous_in_range(&mm, size, start, end)) { 947 1.1 riastrad pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", 948 1.1 riastrad mode->name, start, end, size); 949 1.1 riastrad goto out; 950 1.1 riastrad } 951 1.1 riastrad 952 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 953 1.1 riastrad drm_mm_remove_node(node); 954 1.1 riastrad DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 955 1.1 riastrad 956 1.1 riastrad cond_resched(); 957 1.1 riastrad } 958 1.1 riastrad 959 1.1 riastrad ret = 0; 960 1.1 riastrad out: 961 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 962 1.1 riastrad drm_mm_remove_node(node); 963 1.1 riastrad drm_mm_takedown(&mm); 964 1.1 riastrad vfree(nodes); 965 1.1 riastrad err: 966 1.1 riastrad return ret; 967 1.1 riastrad } 968 1.1 riastrad 969 1.1 riastrad static int insert_outside_range(void) 970 1.1 riastrad { 971 1.1 riastrad struct drm_mm mm; 972 1.1 riastrad const unsigned int start = 1024; 973 1.1 riastrad const unsigned int end = 2048; 974 1.1 riastrad const unsigned int size = end - start; 975 1.1 riastrad 976 1.1 riastrad drm_mm_init(&mm, start, size); 977 1.1 riastrad 978 1.1 riastrad if (!expect_insert_in_range_fail(&mm, 1, 0, start)) 979 1.1 riastrad return -EINVAL; 980 1.1 riastrad 981 1.1 riastrad if (!expect_insert_in_range_fail(&mm, size, 982 1.1 riastrad start - size/2, start + (size+1)/2)) 983 1.1 riastrad return -EINVAL; 984 1.1 riastrad 985 1.1 riastrad if (!expect_insert_in_range_fail(&mm, size, 986 1.1 riastrad end - (size+1)/2, end + size/2)) 987 1.1 riastrad return -EINVAL; 988 1.1 riastrad 989 1.1 riastrad if (!expect_insert_in_range_fail(&mm, 1, end, end + size)) 990 1.1 riastrad return -EINVAL; 991 1.1 riastrad 992 1.1 riastrad drm_mm_takedown(&mm); 993 1.1 riastrad return 0; 994 1.1 riastrad } 995 1.1 riastrad 996 1.1 riastrad static int igt_insert_range(void *ignored) 997 1.1 riastrad { 998 1.1 riastrad const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); 999 1.1 riastrad unsigned int n; 1000 1.1 riastrad int ret; 1001 1.1 riastrad 1002 1.1 riastrad /* Check that requests outside the bounds of drm_mm are rejected. */ 1003 1.1 riastrad ret = insert_outside_range(); 1004 1.1 riastrad if (ret) 1005 1.1 riastrad return ret; 1006 1.1 riastrad 1007 1.1 riastrad for_each_prime_number_from(n, 1, 50) { 1008 1.1 riastrad const u64 size = BIT_ULL(n); 1009 1.1 riastrad const u64 max = count * size; 1010 1.1 riastrad 1011 1.1 riastrad ret = __igt_insert_range(count, size, 0, max); 1012 1.1 riastrad if (ret) 1013 1.1 riastrad return ret; 1014 1.1 riastrad 1015 1.1 riastrad ret = __igt_insert_range(count, size, 1, max); 1016 1.1 riastrad if (ret) 1017 1.1 riastrad return ret; 1018 1.1 riastrad 1019 1.1 riastrad ret = __igt_insert_range(count, size, 0, max - 1); 1020 1.1 riastrad if (ret) 1021 1.1 riastrad return ret; 1022 1.1 riastrad 1023 1.1 riastrad ret = __igt_insert_range(count, size, 0, max/2); 1024 1.1 riastrad if (ret) 1025 1.1 riastrad return ret; 1026 1.1 riastrad 1027 1.1 riastrad ret = __igt_insert_range(count, size, max/2, max); 1028 1.1 riastrad if (ret) 1029 1.1 riastrad return ret; 1030 1.1 riastrad 1031 1.1 riastrad ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); 1032 1.1 riastrad if (ret) 1033 1.1 riastrad return ret; 1034 1.1 riastrad 1035 1.1 riastrad cond_resched(); 1036 1.1 riastrad } 1037 1.1 riastrad 1038 1.1 riastrad return 0; 1039 1.1 riastrad } 1040 1.1 riastrad 1041 1.1 riastrad static int igt_align(void *ignored) 1042 1.1 riastrad { 1043 1.1 riastrad const struct insert_mode *mode; 1044 1.1 riastrad const unsigned int max_count = min(8192u, max_prime); 1045 1.1 riastrad struct drm_mm mm; 1046 1.1 riastrad struct drm_mm_node *nodes, *node, *next; 1047 1.1 riastrad unsigned int prime; 1048 1.1 riastrad int ret = -EINVAL; 1049 1.1 riastrad 1050 1.1 riastrad /* For each of the possible insertion modes, we pick a few 1051 1.1 riastrad * arbitrary alignments and check that the inserted node 1052 1.1 riastrad * meets our requirements. 1053 1.1 riastrad */ 1054 1.1 riastrad 1055 1.1 riastrad nodes = vzalloc(array_size(max_count, sizeof(*nodes))); 1056 1.1 riastrad if (!nodes) 1057 1.1 riastrad goto err; 1058 1.1 riastrad 1059 1.1 riastrad drm_mm_init(&mm, 1, U64_MAX - 2); 1060 1.1 riastrad 1061 1.1 riastrad for (mode = insert_modes; mode->name; mode++) { 1062 1.1 riastrad unsigned int i = 0; 1063 1.1 riastrad 1064 1.1 riastrad for_each_prime_number_from(prime, 1, max_count) { 1065 1.1 riastrad u64 size = next_prime_number(prime); 1066 1.1 riastrad 1067 1.1 riastrad if (!expect_insert(&mm, &nodes[i], 1068 1.1 riastrad size, prime, i, 1069 1.1 riastrad mode)) { 1070 1.1 riastrad pr_err("%s insert failed with alignment=%d", 1071 1.1 riastrad mode->name, prime); 1072 1.1 riastrad goto out; 1073 1.1 riastrad } 1074 1.1 riastrad 1075 1.1 riastrad i++; 1076 1.1 riastrad } 1077 1.1 riastrad 1078 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1079 1.1 riastrad drm_mm_remove_node(node); 1080 1.1 riastrad DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1081 1.1 riastrad 1082 1.1 riastrad cond_resched(); 1083 1.1 riastrad } 1084 1.1 riastrad 1085 1.1 riastrad ret = 0; 1086 1.1 riastrad out: 1087 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1088 1.1 riastrad drm_mm_remove_node(node); 1089 1.1 riastrad drm_mm_takedown(&mm); 1090 1.1 riastrad vfree(nodes); 1091 1.1 riastrad err: 1092 1.1 riastrad return ret; 1093 1.1 riastrad } 1094 1.1 riastrad 1095 1.1 riastrad static int igt_align_pot(int max) 1096 1.1 riastrad { 1097 1.1 riastrad struct drm_mm mm; 1098 1.1 riastrad struct drm_mm_node *node, *next; 1099 1.1 riastrad int bit; 1100 1.1 riastrad int ret = -EINVAL; 1101 1.1 riastrad 1102 1.1 riastrad /* Check that we can align to the full u64 address space */ 1103 1.1 riastrad 1104 1.1 riastrad drm_mm_init(&mm, 1, U64_MAX - 2); 1105 1.1 riastrad 1106 1.1 riastrad for (bit = max - 1; bit; bit--) { 1107 1.1 riastrad u64 align, size; 1108 1.1 riastrad 1109 1.1 riastrad node = kzalloc(sizeof(*node), GFP_KERNEL); 1110 1.1 riastrad if (!node) { 1111 1.1 riastrad ret = -ENOMEM; 1112 1.1 riastrad goto out; 1113 1.1 riastrad } 1114 1.1 riastrad 1115 1.1 riastrad align = BIT_ULL(bit); 1116 1.1 riastrad size = BIT_ULL(bit-1) + 1; 1117 1.1 riastrad if (!expect_insert(&mm, node, 1118 1.1 riastrad size, align, bit, 1119 1.1 riastrad &insert_modes[0])) { 1120 1.1 riastrad pr_err("insert failed with alignment=%llx [%d]", 1121 1.1 riastrad align, bit); 1122 1.1 riastrad goto out; 1123 1.1 riastrad } 1124 1.1 riastrad 1125 1.1 riastrad cond_resched(); 1126 1.1 riastrad } 1127 1.1 riastrad 1128 1.1 riastrad ret = 0; 1129 1.1 riastrad out: 1130 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) { 1131 1.1 riastrad drm_mm_remove_node(node); 1132 1.1 riastrad kfree(node); 1133 1.1 riastrad } 1134 1.1 riastrad drm_mm_takedown(&mm); 1135 1.1 riastrad return ret; 1136 1.1 riastrad } 1137 1.1 riastrad 1138 1.1 riastrad static int igt_align32(void *ignored) 1139 1.1 riastrad { 1140 1.1 riastrad return igt_align_pot(32); 1141 1.1 riastrad } 1142 1.1 riastrad 1143 1.1 riastrad static int igt_align64(void *ignored) 1144 1.1 riastrad { 1145 1.1 riastrad return igt_align_pot(64); 1146 1.1 riastrad } 1147 1.1 riastrad 1148 1.1 riastrad static void show_scan(const struct drm_mm_scan *scan) 1149 1.1 riastrad { 1150 1.1 riastrad pr_info("scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", 1151 1.1 riastrad scan->hit_start, scan->hit_end, 1152 1.1 riastrad scan->size, scan->alignment, scan->color); 1153 1.1 riastrad } 1154 1.1 riastrad 1155 1.1 riastrad static void show_holes(const struct drm_mm *mm, int count) 1156 1.1 riastrad { 1157 1.1 riastrad u64 hole_start, hole_end; 1158 1.1 riastrad struct drm_mm_node *hole; 1159 1.1 riastrad 1160 1.1 riastrad drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { 1161 1.1 riastrad struct drm_mm_node *next = list_next_entry(hole, node_list); 1162 1.1 riastrad const char *node1 = NULL, *node2 = NULL; 1163 1.1 riastrad 1164 1.1 riastrad if (drm_mm_node_allocated(hole)) 1165 1.1 riastrad node1 = kasprintf(GFP_KERNEL, 1166 1.1 riastrad "[%llx + %lld, color=%ld], ", 1167 1.1 riastrad hole->start, hole->size, hole->color); 1168 1.1 riastrad 1169 1.1 riastrad if (drm_mm_node_allocated(next)) 1170 1.1 riastrad node2 = kasprintf(GFP_KERNEL, 1171 1.1 riastrad ", [%llx + %lld, color=%ld]", 1172 1.1 riastrad next->start, next->size, next->color); 1173 1.1 riastrad 1174 1.1 riastrad pr_info("%sHole [%llx - %llx, size %lld]%s\n", 1175 1.1 riastrad node1, 1176 1.1 riastrad hole_start, hole_end, hole_end - hole_start, 1177 1.1 riastrad node2); 1178 1.1 riastrad 1179 1.1 riastrad kfree(node2); 1180 1.1 riastrad kfree(node1); 1181 1.1 riastrad 1182 1.1 riastrad if (!--count) 1183 1.1 riastrad break; 1184 1.1 riastrad } 1185 1.1 riastrad } 1186 1.1 riastrad 1187 1.1 riastrad struct evict_node { 1188 1.1 riastrad struct drm_mm_node node; 1189 1.1 riastrad struct list_head link; 1190 1.1 riastrad }; 1191 1.1 riastrad 1192 1.1 riastrad static bool evict_nodes(struct drm_mm_scan *scan, 1193 1.1 riastrad struct evict_node *nodes, 1194 1.1 riastrad unsigned int *order, 1195 1.1 riastrad unsigned int count, 1196 1.1 riastrad bool use_color, 1197 1.1 riastrad struct list_head *evict_list) 1198 1.1 riastrad { 1199 1.1 riastrad struct evict_node *e, *en; 1200 1.1 riastrad unsigned int i; 1201 1.1 riastrad 1202 1.1 riastrad for (i = 0; i < count; i++) { 1203 1.1 riastrad e = &nodes[order ? order[i] : i]; 1204 1.1 riastrad list_add(&e->link, evict_list); 1205 1.1 riastrad if (drm_mm_scan_add_block(scan, &e->node)) 1206 1.1 riastrad break; 1207 1.1 riastrad } 1208 1.1 riastrad list_for_each_entry_safe(e, en, evict_list, link) { 1209 1.1 riastrad if (!drm_mm_scan_remove_block(scan, &e->node)) 1210 1.1 riastrad list_del(&e->link); 1211 1.1 riastrad } 1212 1.1 riastrad if (list_empty(evict_list)) { 1213 1.1 riastrad pr_err("Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", 1214 1.1 riastrad scan->size, count, scan->alignment, scan->color); 1215 1.1 riastrad return false; 1216 1.1 riastrad } 1217 1.1 riastrad 1218 1.1 riastrad list_for_each_entry(e, evict_list, link) 1219 1.1 riastrad drm_mm_remove_node(&e->node); 1220 1.1 riastrad 1221 1.1 riastrad if (use_color) { 1222 1.1 riastrad struct drm_mm_node *node; 1223 1.1 riastrad 1224 1.1 riastrad while ((node = drm_mm_scan_color_evict(scan))) { 1225 1.1 riastrad e = container_of(node, typeof(*e), node); 1226 1.1 riastrad drm_mm_remove_node(&e->node); 1227 1.1 riastrad list_add(&e->link, evict_list); 1228 1.1 riastrad } 1229 1.1 riastrad } else { 1230 1.1 riastrad if (drm_mm_scan_color_evict(scan)) { 1231 1.1 riastrad pr_err("drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); 1232 1.1 riastrad return false; 1233 1.1 riastrad } 1234 1.1 riastrad } 1235 1.1 riastrad 1236 1.1 riastrad return true; 1237 1.1 riastrad } 1238 1.1 riastrad 1239 1.1 riastrad static bool evict_nothing(struct drm_mm *mm, 1240 1.1 riastrad unsigned int total_size, 1241 1.1 riastrad struct evict_node *nodes) 1242 1.1 riastrad { 1243 1.1 riastrad struct drm_mm_scan scan; 1244 1.1 riastrad LIST_HEAD(evict_list); 1245 1.1 riastrad struct evict_node *e; 1246 1.1 riastrad struct drm_mm_node *node; 1247 1.1 riastrad unsigned int n; 1248 1.1 riastrad 1249 1.1 riastrad drm_mm_scan_init(&scan, mm, 1, 0, 0, 0); 1250 1.1 riastrad for (n = 0; n < total_size; n++) { 1251 1.1 riastrad e = &nodes[n]; 1252 1.1 riastrad list_add(&e->link, &evict_list); 1253 1.1 riastrad drm_mm_scan_add_block(&scan, &e->node); 1254 1.1 riastrad } 1255 1.1 riastrad list_for_each_entry(e, &evict_list, link) 1256 1.1 riastrad drm_mm_scan_remove_block(&scan, &e->node); 1257 1.1 riastrad 1258 1.1 riastrad for (n = 0; n < total_size; n++) { 1259 1.1 riastrad e = &nodes[n]; 1260 1.1 riastrad 1261 1.1 riastrad if (!drm_mm_node_allocated(&e->node)) { 1262 1.1 riastrad pr_err("node[%d] no longer allocated!\n", n); 1263 1.1 riastrad return false; 1264 1.1 riastrad } 1265 1.1 riastrad 1266 1.1 riastrad e->link.next = NULL; 1267 1.1 riastrad } 1268 1.1 riastrad 1269 1.1 riastrad drm_mm_for_each_node(node, mm) { 1270 1.1 riastrad e = container_of(node, typeof(*e), node); 1271 1.1 riastrad e->link.next = &e->link; 1272 1.1 riastrad } 1273 1.1 riastrad 1274 1.1 riastrad for (n = 0; n < total_size; n++) { 1275 1.1 riastrad e = &nodes[n]; 1276 1.1 riastrad 1277 1.1 riastrad if (!e->link.next) { 1278 1.1 riastrad pr_err("node[%d] no longer connected!\n", n); 1279 1.1 riastrad return false; 1280 1.1 riastrad } 1281 1.1 riastrad } 1282 1.1 riastrad 1283 1.1 riastrad return assert_continuous(mm, nodes[0].node.size); 1284 1.1 riastrad } 1285 1.1 riastrad 1286 1.1 riastrad static bool evict_everything(struct drm_mm *mm, 1287 1.1 riastrad unsigned int total_size, 1288 1.1 riastrad struct evict_node *nodes) 1289 1.1 riastrad { 1290 1.1 riastrad struct drm_mm_scan scan; 1291 1.1 riastrad LIST_HEAD(evict_list); 1292 1.1 riastrad struct evict_node *e; 1293 1.1 riastrad unsigned int n; 1294 1.1 riastrad int err; 1295 1.1 riastrad 1296 1.1 riastrad drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0); 1297 1.1 riastrad for (n = 0; n < total_size; n++) { 1298 1.1 riastrad e = &nodes[n]; 1299 1.1 riastrad list_add(&e->link, &evict_list); 1300 1.1 riastrad if (drm_mm_scan_add_block(&scan, &e->node)) 1301 1.1 riastrad break; 1302 1.1 riastrad } 1303 1.1 riastrad 1304 1.1 riastrad err = 0; 1305 1.1 riastrad list_for_each_entry(e, &evict_list, link) { 1306 1.1 riastrad if (!drm_mm_scan_remove_block(&scan, &e->node)) { 1307 1.1 riastrad if (!err) { 1308 1.1 riastrad pr_err("Node %lld not marked for eviction!\n", 1309 1.1 riastrad e->node.start); 1310 1.1 riastrad err = -EINVAL; 1311 1.1 riastrad } 1312 1.1 riastrad } 1313 1.1 riastrad } 1314 1.1 riastrad if (err) 1315 1.1 riastrad return false; 1316 1.1 riastrad 1317 1.1 riastrad list_for_each_entry(e, &evict_list, link) 1318 1.1 riastrad drm_mm_remove_node(&e->node); 1319 1.1 riastrad 1320 1.1 riastrad if (!assert_one_hole(mm, 0, total_size)) 1321 1.1 riastrad return false; 1322 1.1 riastrad 1323 1.1 riastrad list_for_each_entry(e, &evict_list, link) { 1324 1.1 riastrad err = drm_mm_reserve_node(mm, &e->node); 1325 1.1 riastrad if (err) { 1326 1.1 riastrad pr_err("Failed to reinsert node after eviction: start=%llx\n", 1327 1.1 riastrad e->node.start); 1328 1.1 riastrad return false; 1329 1.1 riastrad } 1330 1.1 riastrad } 1331 1.1 riastrad 1332 1.1 riastrad return assert_continuous(mm, nodes[0].node.size); 1333 1.1 riastrad } 1334 1.1 riastrad 1335 1.1 riastrad static int evict_something(struct drm_mm *mm, 1336 1.1 riastrad u64 range_start, u64 range_end, 1337 1.1 riastrad struct evict_node *nodes, 1338 1.1 riastrad unsigned int *order, 1339 1.1 riastrad unsigned int count, 1340 1.1 riastrad unsigned int size, 1341 1.1 riastrad unsigned int alignment, 1342 1.1 riastrad const struct insert_mode *mode) 1343 1.1 riastrad { 1344 1.1 riastrad struct drm_mm_scan scan; 1345 1.1 riastrad LIST_HEAD(evict_list); 1346 1.1 riastrad struct evict_node *e; 1347 1.1 riastrad struct drm_mm_node tmp; 1348 1.1 riastrad int err; 1349 1.1 riastrad 1350 1.1 riastrad drm_mm_scan_init_with_range(&scan, mm, 1351 1.1 riastrad size, alignment, 0, 1352 1.1 riastrad range_start, range_end, 1353 1.1 riastrad mode->mode); 1354 1.1 riastrad if (!evict_nodes(&scan, 1355 1.1 riastrad nodes, order, count, false, 1356 1.1 riastrad &evict_list)) 1357 1.1 riastrad return -EINVAL; 1358 1.1 riastrad 1359 1.1 riastrad memset(&tmp, 0, sizeof(tmp)); 1360 1.1 riastrad err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, 1361 1.1 riastrad DRM_MM_INSERT_EVICT); 1362 1.1 riastrad if (err) { 1363 1.1 riastrad pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", 1364 1.1 riastrad size, alignment); 1365 1.1 riastrad show_scan(&scan); 1366 1.1 riastrad show_holes(mm, 3); 1367 1.1 riastrad return err; 1368 1.1 riastrad } 1369 1.1 riastrad 1370 1.1 riastrad if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 1371 1.1 riastrad pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 1372 1.1 riastrad tmp.start, tmp.size, range_start, range_end); 1373 1.1 riastrad err = -EINVAL; 1374 1.1 riastrad } 1375 1.1 riastrad 1376 1.1 riastrad if (!assert_node(&tmp, mm, size, alignment, 0) || 1377 1.1 riastrad drm_mm_hole_follows(&tmp)) { 1378 1.1 riastrad pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", 1379 1.1 riastrad tmp.size, size, 1380 1.1 riastrad alignment, misalignment(&tmp, alignment), 1381 1.1 riastrad tmp.start, drm_mm_hole_follows(&tmp)); 1382 1.1 riastrad err = -EINVAL; 1383 1.1 riastrad } 1384 1.1 riastrad 1385 1.1 riastrad drm_mm_remove_node(&tmp); 1386 1.1 riastrad if (err) 1387 1.1 riastrad return err; 1388 1.1 riastrad 1389 1.1 riastrad list_for_each_entry(e, &evict_list, link) { 1390 1.1 riastrad err = drm_mm_reserve_node(mm, &e->node); 1391 1.1 riastrad if (err) { 1392 1.1 riastrad pr_err("Failed to reinsert node after eviction: start=%llx\n", 1393 1.1 riastrad e->node.start); 1394 1.1 riastrad return err; 1395 1.1 riastrad } 1396 1.1 riastrad } 1397 1.1 riastrad 1398 1.1 riastrad if (!assert_continuous(mm, nodes[0].node.size)) { 1399 1.1 riastrad pr_err("range is no longer continuous\n"); 1400 1.1 riastrad return -EINVAL; 1401 1.1 riastrad } 1402 1.1 riastrad 1403 1.1 riastrad return 0; 1404 1.1 riastrad } 1405 1.1 riastrad 1406 1.1 riastrad static int igt_evict(void *ignored) 1407 1.1 riastrad { 1408 1.1 riastrad DRM_RND_STATE(prng, random_seed); 1409 1.1 riastrad const unsigned int size = 8192; 1410 1.1 riastrad const struct insert_mode *mode; 1411 1.1 riastrad struct drm_mm mm; 1412 1.1 riastrad struct evict_node *nodes; 1413 1.1 riastrad struct drm_mm_node *node, *next; 1414 1.1 riastrad unsigned int *order, n; 1415 1.1 riastrad int ret, err; 1416 1.1 riastrad 1417 1.1 riastrad /* Here we populate a full drm_mm and then try and insert a new node 1418 1.1 riastrad * by evicting other nodes in a random order. The drm_mm_scan should 1419 1.1 riastrad * pick the first matching hole it finds from the random list. We 1420 1.1 riastrad * repeat that for different allocation strategies, alignments and 1421 1.1 riastrad * sizes to try and stress the hole finder. 1422 1.1 riastrad */ 1423 1.1 riastrad 1424 1.1 riastrad ret = -ENOMEM; 1425 1.1 riastrad nodes = vzalloc(array_size(size, sizeof(*nodes))); 1426 1.1 riastrad if (!nodes) 1427 1.1 riastrad goto err; 1428 1.1 riastrad 1429 1.1 riastrad order = drm_random_order(size, &prng); 1430 1.1 riastrad if (!order) 1431 1.1 riastrad goto err_nodes; 1432 1.1 riastrad 1433 1.1 riastrad ret = -EINVAL; 1434 1.1 riastrad drm_mm_init(&mm, 0, size); 1435 1.1 riastrad for (n = 0; n < size; n++) { 1436 1.1 riastrad err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1437 1.1 riastrad if (err) { 1438 1.1 riastrad pr_err("insert failed, step %d\n", n); 1439 1.1 riastrad ret = err; 1440 1.1 riastrad goto out; 1441 1.1 riastrad } 1442 1.1 riastrad } 1443 1.1 riastrad 1444 1.1 riastrad /* First check that using the scanner doesn't break the mm */ 1445 1.1 riastrad if (!evict_nothing(&mm, size, nodes)) { 1446 1.1 riastrad pr_err("evict_nothing() failed\n"); 1447 1.1 riastrad goto out; 1448 1.1 riastrad } 1449 1.1 riastrad if (!evict_everything(&mm, size, nodes)) { 1450 1.1 riastrad pr_err("evict_everything() failed\n"); 1451 1.1 riastrad goto out; 1452 1.1 riastrad } 1453 1.1 riastrad 1454 1.1 riastrad for (mode = evict_modes; mode->name; mode++) { 1455 1.1 riastrad for (n = 1; n <= size; n <<= 1) { 1456 1.1 riastrad drm_random_reorder(order, size, &prng); 1457 1.1 riastrad err = evict_something(&mm, 0, U64_MAX, 1458 1.1 riastrad nodes, order, size, 1459 1.1 riastrad n, 1, 1460 1.1 riastrad mode); 1461 1.1 riastrad if (err) { 1462 1.1 riastrad pr_err("%s evict_something(size=%u) failed\n", 1463 1.1 riastrad mode->name, n); 1464 1.1 riastrad ret = err; 1465 1.1 riastrad goto out; 1466 1.1 riastrad } 1467 1.1 riastrad } 1468 1.1 riastrad 1469 1.1 riastrad for (n = 1; n < size; n <<= 1) { 1470 1.1 riastrad drm_random_reorder(order, size, &prng); 1471 1.1 riastrad err = evict_something(&mm, 0, U64_MAX, 1472 1.1 riastrad nodes, order, size, 1473 1.1 riastrad size/2, n, 1474 1.1 riastrad mode); 1475 1.1 riastrad if (err) { 1476 1.1 riastrad pr_err("%s evict_something(size=%u, alignment=%u) failed\n", 1477 1.1 riastrad mode->name, size/2, n); 1478 1.1 riastrad ret = err; 1479 1.1 riastrad goto out; 1480 1.1 riastrad } 1481 1.1 riastrad } 1482 1.1 riastrad 1483 1.1 riastrad for_each_prime_number_from(n, 1, min(size, max_prime)) { 1484 1.1 riastrad unsigned int nsize = (size - n + 1) / 2; 1485 1.1 riastrad 1486 1.1 riastrad DRM_MM_BUG_ON(!nsize); 1487 1.1 riastrad 1488 1.1 riastrad drm_random_reorder(order, size, &prng); 1489 1.1 riastrad err = evict_something(&mm, 0, U64_MAX, 1490 1.1 riastrad nodes, order, size, 1491 1.1 riastrad nsize, n, 1492 1.1 riastrad mode); 1493 1.1 riastrad if (err) { 1494 1.1 riastrad pr_err("%s evict_something(size=%u, alignment=%u) failed\n", 1495 1.1 riastrad mode->name, nsize, n); 1496 1.1 riastrad ret = err; 1497 1.1 riastrad goto out; 1498 1.1 riastrad } 1499 1.1 riastrad } 1500 1.1 riastrad 1501 1.1 riastrad cond_resched(); 1502 1.1 riastrad } 1503 1.1 riastrad 1504 1.1 riastrad ret = 0; 1505 1.1 riastrad out: 1506 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1507 1.1 riastrad drm_mm_remove_node(node); 1508 1.1 riastrad drm_mm_takedown(&mm); 1509 1.1 riastrad kfree(order); 1510 1.1 riastrad err_nodes: 1511 1.1 riastrad vfree(nodes); 1512 1.1 riastrad err: 1513 1.1 riastrad return ret; 1514 1.1 riastrad } 1515 1.1 riastrad 1516 1.1 riastrad static int igt_evict_range(void *ignored) 1517 1.1 riastrad { 1518 1.1 riastrad DRM_RND_STATE(prng, random_seed); 1519 1.1 riastrad const unsigned int size = 8192; 1520 1.1 riastrad const unsigned int range_size = size / 2; 1521 1.1 riastrad const unsigned int range_start = size / 4; 1522 1.1 riastrad const unsigned int range_end = range_start + range_size; 1523 1.1 riastrad const struct insert_mode *mode; 1524 1.1 riastrad struct drm_mm mm; 1525 1.1 riastrad struct evict_node *nodes; 1526 1.1 riastrad struct drm_mm_node *node, *next; 1527 1.1 riastrad unsigned int *order, n; 1528 1.1 riastrad int ret, err; 1529 1.1 riastrad 1530 1.1 riastrad /* Like igt_evict() but now we are limiting the search to a 1531 1.1 riastrad * small portion of the full drm_mm. 1532 1.1 riastrad */ 1533 1.1 riastrad 1534 1.1 riastrad ret = -ENOMEM; 1535 1.1 riastrad nodes = vzalloc(array_size(size, sizeof(*nodes))); 1536 1.1 riastrad if (!nodes) 1537 1.1 riastrad goto err; 1538 1.1 riastrad 1539 1.1 riastrad order = drm_random_order(size, &prng); 1540 1.1 riastrad if (!order) 1541 1.1 riastrad goto err_nodes; 1542 1.1 riastrad 1543 1.1 riastrad ret = -EINVAL; 1544 1.1 riastrad drm_mm_init(&mm, 0, size); 1545 1.1 riastrad for (n = 0; n < size; n++) { 1546 1.1 riastrad err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1547 1.1 riastrad if (err) { 1548 1.1 riastrad pr_err("insert failed, step %d\n", n); 1549 1.1 riastrad ret = err; 1550 1.1 riastrad goto out; 1551 1.1 riastrad } 1552 1.1 riastrad } 1553 1.1 riastrad 1554 1.1 riastrad for (mode = evict_modes; mode->name; mode++) { 1555 1.1 riastrad for (n = 1; n <= range_size; n <<= 1) { 1556 1.1 riastrad drm_random_reorder(order, size, &prng); 1557 1.1 riastrad err = evict_something(&mm, range_start, range_end, 1558 1.1 riastrad nodes, order, size, 1559 1.1 riastrad n, 1, 1560 1.1 riastrad mode); 1561 1.1 riastrad if (err) { 1562 1.1 riastrad pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n", 1563 1.1 riastrad mode->name, n, range_start, range_end); 1564 1.1 riastrad goto out; 1565 1.1 riastrad } 1566 1.1 riastrad } 1567 1.1 riastrad 1568 1.1 riastrad for (n = 1; n <= range_size; n <<= 1) { 1569 1.1 riastrad drm_random_reorder(order, size, &prng); 1570 1.1 riastrad err = evict_something(&mm, range_start, range_end, 1571 1.1 riastrad nodes, order, size, 1572 1.1 riastrad range_size/2, n, 1573 1.1 riastrad mode); 1574 1.1 riastrad if (err) { 1575 1.1 riastrad pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 1576 1.1 riastrad mode->name, range_size/2, n, range_start, range_end); 1577 1.1 riastrad goto out; 1578 1.1 riastrad } 1579 1.1 riastrad } 1580 1.1 riastrad 1581 1.1 riastrad for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 1582 1.1 riastrad unsigned int nsize = (range_size - n + 1) / 2; 1583 1.1 riastrad 1584 1.1 riastrad DRM_MM_BUG_ON(!nsize); 1585 1.1 riastrad 1586 1.1 riastrad drm_random_reorder(order, size, &prng); 1587 1.1 riastrad err = evict_something(&mm, range_start, range_end, 1588 1.1 riastrad nodes, order, size, 1589 1.1 riastrad nsize, n, 1590 1.1 riastrad mode); 1591 1.1 riastrad if (err) { 1592 1.1 riastrad pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", 1593 1.1 riastrad mode->name, nsize, n, range_start, range_end); 1594 1.1 riastrad goto out; 1595 1.1 riastrad } 1596 1.1 riastrad } 1597 1.1 riastrad 1598 1.1 riastrad cond_resched(); 1599 1.1 riastrad } 1600 1.1 riastrad 1601 1.1 riastrad ret = 0; 1602 1.1 riastrad out: 1603 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1604 1.1 riastrad drm_mm_remove_node(node); 1605 1.1 riastrad drm_mm_takedown(&mm); 1606 1.1 riastrad kfree(order); 1607 1.1 riastrad err_nodes: 1608 1.1 riastrad vfree(nodes); 1609 1.1 riastrad err: 1610 1.1 riastrad return ret; 1611 1.1 riastrad } 1612 1.1 riastrad 1613 1.1 riastrad static unsigned int node_index(const struct drm_mm_node *node) 1614 1.1 riastrad { 1615 1.1 riastrad return div64_u64(node->start, node->size); 1616 1.1 riastrad } 1617 1.1 riastrad 1618 1.1 riastrad static int igt_topdown(void *ignored) 1619 1.1 riastrad { 1620 1.1 riastrad const struct insert_mode *topdown = &insert_modes[TOPDOWN]; 1621 1.1 riastrad DRM_RND_STATE(prng, random_seed); 1622 1.1 riastrad const unsigned int count = 8192; 1623 1.1 riastrad unsigned int size; 1624 1.1 riastrad unsigned long *bitmap; 1625 1.1 riastrad struct drm_mm mm; 1626 1.1 riastrad struct drm_mm_node *nodes, *node, *next; 1627 1.1 riastrad unsigned int *order, n, m, o = 0; 1628 1.1 riastrad int ret; 1629 1.1 riastrad 1630 1.1 riastrad /* When allocating top-down, we expect to be returned a node 1631 1.1 riastrad * from a suitable hole at the top of the drm_mm. We check that 1632 1.1 riastrad * the returned node does match the highest available slot. 1633 1.1 riastrad */ 1634 1.1 riastrad 1635 1.1 riastrad ret = -ENOMEM; 1636 1.1 riastrad nodes = vzalloc(array_size(count, sizeof(*nodes))); 1637 1.1 riastrad if (!nodes) 1638 1.1 riastrad goto err; 1639 1.1 riastrad 1640 1.1 riastrad bitmap = bitmap_zalloc(count, GFP_KERNEL); 1641 1.1 riastrad if (!bitmap) 1642 1.1 riastrad goto err_nodes; 1643 1.1 riastrad 1644 1.1 riastrad order = drm_random_order(count, &prng); 1645 1.1 riastrad if (!order) 1646 1.1 riastrad goto err_bitmap; 1647 1.1 riastrad 1648 1.1 riastrad ret = -EINVAL; 1649 1.1 riastrad for (size = 1; size <= 64; size <<= 1) { 1650 1.1 riastrad drm_mm_init(&mm, 0, size*count); 1651 1.1 riastrad for (n = 0; n < count; n++) { 1652 1.1 riastrad if (!expect_insert(&mm, &nodes[n], 1653 1.1 riastrad size, 0, n, 1654 1.1 riastrad topdown)) { 1655 1.1 riastrad pr_err("insert failed, size %u step %d\n", size, n); 1656 1.1 riastrad goto out; 1657 1.1 riastrad } 1658 1.1 riastrad 1659 1.1 riastrad if (drm_mm_hole_follows(&nodes[n])) { 1660 1.1 riastrad pr_err("hole after topdown insert %d, start=%llx\n, size=%u", 1661 1.1 riastrad n, nodes[n].start, size); 1662 1.1 riastrad goto out; 1663 1.1 riastrad } 1664 1.1 riastrad 1665 1.1 riastrad if (!assert_one_hole(&mm, 0, size*(count - n - 1))) 1666 1.1 riastrad goto out; 1667 1.1 riastrad } 1668 1.1 riastrad 1669 1.1 riastrad if (!assert_continuous(&mm, size)) 1670 1.1 riastrad goto out; 1671 1.1 riastrad 1672 1.1 riastrad drm_random_reorder(order, count, &prng); 1673 1.1 riastrad for_each_prime_number_from(n, 1, min(count, max_prime)) { 1674 1.1 riastrad for (m = 0; m < n; m++) { 1675 1.1 riastrad node = &nodes[order[(o + m) % count]]; 1676 1.1 riastrad drm_mm_remove_node(node); 1677 1.1 riastrad __set_bit(node_index(node), bitmap); 1678 1.1 riastrad } 1679 1.1 riastrad 1680 1.1 riastrad for (m = 0; m < n; m++) { 1681 1.1 riastrad unsigned int last; 1682 1.1 riastrad 1683 1.1 riastrad node = &nodes[order[(o + m) % count]]; 1684 1.1 riastrad if (!expect_insert(&mm, node, 1685 1.1 riastrad size, 0, 0, 1686 1.1 riastrad topdown)) { 1687 1.1 riastrad pr_err("insert failed, step %d/%d\n", m, n); 1688 1.1 riastrad goto out; 1689 1.1 riastrad } 1690 1.1 riastrad 1691 1.1 riastrad if (drm_mm_hole_follows(node)) { 1692 1.1 riastrad pr_err("hole after topdown insert %d/%d, start=%llx\n", 1693 1.1 riastrad m, n, node->start); 1694 1.1 riastrad goto out; 1695 1.1 riastrad } 1696 1.1 riastrad 1697 1.1 riastrad last = find_last_bit(bitmap, count); 1698 1.1 riastrad if (node_index(node) != last) { 1699 1.1 riastrad pr_err("node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", 1700 1.1 riastrad m, n, size, last, node_index(node)); 1701 1.1 riastrad goto out; 1702 1.1 riastrad } 1703 1.1 riastrad 1704 1.1 riastrad __clear_bit(last, bitmap); 1705 1.1 riastrad } 1706 1.1 riastrad 1707 1.1 riastrad DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 1708 1.1 riastrad 1709 1.1 riastrad o += n; 1710 1.1 riastrad } 1711 1.1 riastrad 1712 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1713 1.1 riastrad drm_mm_remove_node(node); 1714 1.1 riastrad DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1715 1.1 riastrad cond_resched(); 1716 1.1 riastrad } 1717 1.1 riastrad 1718 1.1 riastrad ret = 0; 1719 1.1 riastrad out: 1720 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1721 1.1 riastrad drm_mm_remove_node(node); 1722 1.1 riastrad drm_mm_takedown(&mm); 1723 1.1 riastrad kfree(order); 1724 1.1 riastrad err_bitmap: 1725 1.1 riastrad bitmap_free(bitmap); 1726 1.1 riastrad err_nodes: 1727 1.1 riastrad vfree(nodes); 1728 1.1 riastrad err: 1729 1.1 riastrad return ret; 1730 1.1 riastrad } 1731 1.1 riastrad 1732 1.1 riastrad static int igt_bottomup(void *ignored) 1733 1.1 riastrad { 1734 1.1 riastrad const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; 1735 1.1 riastrad DRM_RND_STATE(prng, random_seed); 1736 1.1 riastrad const unsigned int count = 8192; 1737 1.1 riastrad unsigned int size; 1738 1.1 riastrad unsigned long *bitmap; 1739 1.1 riastrad struct drm_mm mm; 1740 1.1 riastrad struct drm_mm_node *nodes, *node, *next; 1741 1.1 riastrad unsigned int *order, n, m, o = 0; 1742 1.1 riastrad int ret; 1743 1.1 riastrad 1744 1.1 riastrad /* Like igt_topdown, but instead of searching for the last hole, 1745 1.1 riastrad * we search for the first. 1746 1.1 riastrad */ 1747 1.1 riastrad 1748 1.1 riastrad ret = -ENOMEM; 1749 1.1 riastrad nodes = vzalloc(array_size(count, sizeof(*nodes))); 1750 1.1 riastrad if (!nodes) 1751 1.1 riastrad goto err; 1752 1.1 riastrad 1753 1.1 riastrad bitmap = bitmap_zalloc(count, GFP_KERNEL); 1754 1.1 riastrad if (!bitmap) 1755 1.1 riastrad goto err_nodes; 1756 1.1 riastrad 1757 1.1 riastrad order = drm_random_order(count, &prng); 1758 1.1 riastrad if (!order) 1759 1.1 riastrad goto err_bitmap; 1760 1.1 riastrad 1761 1.1 riastrad ret = -EINVAL; 1762 1.1 riastrad for (size = 1; size <= 64; size <<= 1) { 1763 1.1 riastrad drm_mm_init(&mm, 0, size*count); 1764 1.1 riastrad for (n = 0; n < count; n++) { 1765 1.1 riastrad if (!expect_insert(&mm, &nodes[n], 1766 1.1 riastrad size, 0, n, 1767 1.1 riastrad bottomup)) { 1768 1.1 riastrad pr_err("bottomup insert failed, size %u step %d\n", size, n); 1769 1.1 riastrad goto out; 1770 1.1 riastrad } 1771 1.1 riastrad 1772 1.1 riastrad if (!assert_one_hole(&mm, size*(n + 1), size*count)) 1773 1.1 riastrad goto out; 1774 1.1 riastrad } 1775 1.1 riastrad 1776 1.1 riastrad if (!assert_continuous(&mm, size)) 1777 1.1 riastrad goto out; 1778 1.1 riastrad 1779 1.1 riastrad drm_random_reorder(order, count, &prng); 1780 1.1 riastrad for_each_prime_number_from(n, 1, min(count, max_prime)) { 1781 1.1 riastrad for (m = 0; m < n; m++) { 1782 1.1 riastrad node = &nodes[order[(o + m) % count]]; 1783 1.1 riastrad drm_mm_remove_node(node); 1784 1.1 riastrad __set_bit(node_index(node), bitmap); 1785 1.1 riastrad } 1786 1.1 riastrad 1787 1.1 riastrad for (m = 0; m < n; m++) { 1788 1.1 riastrad unsigned int first; 1789 1.1 riastrad 1790 1.1 riastrad node = &nodes[order[(o + m) % count]]; 1791 1.1 riastrad if (!expect_insert(&mm, node, 1792 1.1 riastrad size, 0, 0, 1793 1.1 riastrad bottomup)) { 1794 1.1 riastrad pr_err("insert failed, step %d/%d\n", m, n); 1795 1.1 riastrad goto out; 1796 1.1 riastrad } 1797 1.1 riastrad 1798 1.1 riastrad first = find_first_bit(bitmap, count); 1799 1.1 riastrad if (node_index(node) != first) { 1800 1.1 riastrad pr_err("node %d/%d not inserted into bottom hole, expected %d, found %d\n", 1801 1.1 riastrad m, n, first, node_index(node)); 1802 1.1 riastrad goto out; 1803 1.1 riastrad } 1804 1.1 riastrad __clear_bit(first, bitmap); 1805 1.1 riastrad } 1806 1.1 riastrad 1807 1.1 riastrad DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count); 1808 1.1 riastrad 1809 1.1 riastrad o += n; 1810 1.1 riastrad } 1811 1.1 riastrad 1812 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1813 1.1 riastrad drm_mm_remove_node(node); 1814 1.1 riastrad DRM_MM_BUG_ON(!drm_mm_clean(&mm)); 1815 1.1 riastrad cond_resched(); 1816 1.1 riastrad } 1817 1.1 riastrad 1818 1.1 riastrad ret = 0; 1819 1.1 riastrad out: 1820 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 1821 1.1 riastrad drm_mm_remove_node(node); 1822 1.1 riastrad drm_mm_takedown(&mm); 1823 1.1 riastrad kfree(order); 1824 1.1 riastrad err_bitmap: 1825 1.1 riastrad bitmap_free(bitmap); 1826 1.1 riastrad err_nodes: 1827 1.1 riastrad vfree(nodes); 1828 1.1 riastrad err: 1829 1.1 riastrad return ret; 1830 1.1 riastrad } 1831 1.1 riastrad 1832 1.1 riastrad static int __igt_once(unsigned int mode) 1833 1.1 riastrad { 1834 1.1 riastrad struct drm_mm mm; 1835 1.1 riastrad struct drm_mm_node rsvd_lo, rsvd_hi, node; 1836 1.1 riastrad int err; 1837 1.1 riastrad 1838 1.1 riastrad drm_mm_init(&mm, 0, 7); 1839 1.1 riastrad 1840 1.1 riastrad memset(&rsvd_lo, 0, sizeof(rsvd_lo)); 1841 1.1 riastrad rsvd_lo.start = 1; 1842 1.1 riastrad rsvd_lo.size = 1; 1843 1.1 riastrad err = drm_mm_reserve_node(&mm, &rsvd_lo); 1844 1.1 riastrad if (err) { 1845 1.1 riastrad pr_err("Could not reserve low node\n"); 1846 1.1 riastrad goto err; 1847 1.1 riastrad } 1848 1.1 riastrad 1849 1.1 riastrad memset(&rsvd_hi, 0, sizeof(rsvd_hi)); 1850 1.1 riastrad rsvd_hi.start = 5; 1851 1.1 riastrad rsvd_hi.size = 1; 1852 1.1 riastrad err = drm_mm_reserve_node(&mm, &rsvd_hi); 1853 1.1 riastrad if (err) { 1854 1.1 riastrad pr_err("Could not reserve low node\n"); 1855 1.1 riastrad goto err_lo; 1856 1.1 riastrad } 1857 1.1 riastrad 1858 1.1 riastrad if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) { 1859 1.1 riastrad pr_err("Expected a hole after lo and high nodes!\n"); 1860 1.1 riastrad err = -EINVAL; 1861 1.1 riastrad goto err_hi; 1862 1.1 riastrad } 1863 1.1 riastrad 1864 1.1 riastrad memset(&node, 0, sizeof(node)); 1865 1.1 riastrad err = drm_mm_insert_node_generic(&mm, &node, 1866 1.1 riastrad 2, 0, 0, 1867 1.1 riastrad mode | DRM_MM_INSERT_ONCE); 1868 1.1 riastrad if (!err) { 1869 1.1 riastrad pr_err("Unexpectedly inserted the node into the wrong hole: node.start=%llx\n", 1870 1.1 riastrad node.start); 1871 1.1 riastrad err = -EINVAL; 1872 1.1 riastrad goto err_node; 1873 1.1 riastrad } 1874 1.1 riastrad 1875 1.1 riastrad err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode); 1876 1.1 riastrad if (err) { 1877 1.1 riastrad pr_err("Could not insert the node into the available hole!\n"); 1878 1.1 riastrad err = -EINVAL; 1879 1.1 riastrad goto err_hi; 1880 1.1 riastrad } 1881 1.1 riastrad 1882 1.1 riastrad err_node: 1883 1.1 riastrad drm_mm_remove_node(&node); 1884 1.1 riastrad err_hi: 1885 1.1 riastrad drm_mm_remove_node(&rsvd_hi); 1886 1.1 riastrad err_lo: 1887 1.1 riastrad drm_mm_remove_node(&rsvd_lo); 1888 1.1 riastrad err: 1889 1.1 riastrad drm_mm_takedown(&mm); 1890 1.1 riastrad return err; 1891 1.1 riastrad } 1892 1.1 riastrad 1893 1.1 riastrad static int igt_lowest(void *ignored) 1894 1.1 riastrad { 1895 1.1 riastrad return __igt_once(DRM_MM_INSERT_LOW); 1896 1.1 riastrad } 1897 1.1 riastrad 1898 1.1 riastrad static int igt_highest(void *ignored) 1899 1.1 riastrad { 1900 1.1 riastrad return __igt_once(DRM_MM_INSERT_HIGH); 1901 1.1 riastrad } 1902 1.1 riastrad 1903 1.1 riastrad static void separate_adjacent_colors(const struct drm_mm_node *node, 1904 1.1 riastrad unsigned long color, 1905 1.1 riastrad u64 *start, 1906 1.1 riastrad u64 *end) 1907 1.1 riastrad { 1908 1.1 riastrad if (drm_mm_node_allocated(node) && node->color != color) 1909 1.1 riastrad ++*start; 1910 1.1 riastrad 1911 1.1 riastrad node = list_next_entry(node, node_list); 1912 1.1 riastrad if (drm_mm_node_allocated(node) && node->color != color) 1913 1.1 riastrad --*end; 1914 1.1 riastrad } 1915 1.1 riastrad 1916 1.1 riastrad static bool colors_abutt(const struct drm_mm_node *node) 1917 1.1 riastrad { 1918 1.1 riastrad if (!drm_mm_hole_follows(node) && 1919 1.1 riastrad drm_mm_node_allocated(list_next_entry(node, node_list))) { 1920 1.1 riastrad pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", 1921 1.1 riastrad node->color, node->start, node->size, 1922 1.1 riastrad list_next_entry(node, node_list)->color, 1923 1.1 riastrad list_next_entry(node, node_list)->start, 1924 1.1 riastrad list_next_entry(node, node_list)->size); 1925 1.1 riastrad return true; 1926 1.1 riastrad } 1927 1.1 riastrad 1928 1.1 riastrad return false; 1929 1.1 riastrad } 1930 1.1 riastrad 1931 1.1 riastrad static int igt_color(void *ignored) 1932 1.1 riastrad { 1933 1.1 riastrad const unsigned int count = min(4096u, max_iterations); 1934 1.1 riastrad const struct insert_mode *mode; 1935 1.1 riastrad struct drm_mm mm; 1936 1.1 riastrad struct drm_mm_node *node, *nn; 1937 1.1 riastrad unsigned int n; 1938 1.1 riastrad int ret = -EINVAL, err; 1939 1.1 riastrad 1940 1.1 riastrad /* Color adjustment complicates everything. First we just check 1941 1.1 riastrad * that when we insert a node we apply any color_adjustment callback. 1942 1.1 riastrad * The callback we use should ensure that there is a gap between 1943 1.1 riastrad * any two nodes, and so after each insertion we check that those 1944 1.1 riastrad * holes are inserted and that they are preserved. 1945 1.1 riastrad */ 1946 1.1 riastrad 1947 1.1 riastrad drm_mm_init(&mm, 0, U64_MAX); 1948 1.1 riastrad 1949 1.1 riastrad for (n = 1; n <= count; n++) { 1950 1.1 riastrad node = kzalloc(sizeof(*node), GFP_KERNEL); 1951 1.1 riastrad if (!node) { 1952 1.1 riastrad ret = -ENOMEM; 1953 1.1 riastrad goto out; 1954 1.1 riastrad } 1955 1.1 riastrad 1956 1.1 riastrad if (!expect_insert(&mm, node, 1957 1.1 riastrad n, 0, n, 1958 1.1 riastrad &insert_modes[0])) { 1959 1.1 riastrad pr_err("insert failed, step %d\n", n); 1960 1.1 riastrad kfree(node); 1961 1.1 riastrad goto out; 1962 1.1 riastrad } 1963 1.1 riastrad } 1964 1.1 riastrad 1965 1.1 riastrad drm_mm_for_each_node_safe(node, nn, &mm) { 1966 1.1 riastrad if (node->color != node->size) { 1967 1.1 riastrad pr_err("invalid color stored: expected %lld, found %ld\n", 1968 1.1 riastrad node->size, node->color); 1969 1.1 riastrad 1970 1.1 riastrad goto out; 1971 1.1 riastrad } 1972 1.1 riastrad 1973 1.1 riastrad drm_mm_remove_node(node); 1974 1.1 riastrad kfree(node); 1975 1.1 riastrad } 1976 1.1 riastrad 1977 1.1 riastrad /* Now, let's start experimenting with applying a color callback */ 1978 1.1 riastrad mm.color_adjust = separate_adjacent_colors; 1979 1.1 riastrad for (mode = insert_modes; mode->name; mode++) { 1980 1.1 riastrad u64 last; 1981 1.1 riastrad 1982 1.1 riastrad node = kzalloc(sizeof(*node), GFP_KERNEL); 1983 1.1 riastrad if (!node) { 1984 1.1 riastrad ret = -ENOMEM; 1985 1.1 riastrad goto out; 1986 1.1 riastrad } 1987 1.1 riastrad 1988 1.1 riastrad node->size = 1 + 2*count; 1989 1.1 riastrad node->color = node->size; 1990 1.1 riastrad 1991 1.1 riastrad err = drm_mm_reserve_node(&mm, node); 1992 1.1 riastrad if (err) { 1993 1.1 riastrad pr_err("initial reserve failed!\n"); 1994 1.1 riastrad ret = err; 1995 1.1 riastrad goto out; 1996 1.1 riastrad } 1997 1.1 riastrad 1998 1.1 riastrad last = node->start + node->size; 1999 1.1 riastrad 2000 1.1 riastrad for (n = 1; n <= count; n++) { 2001 1.1 riastrad int rem; 2002 1.1 riastrad 2003 1.1 riastrad node = kzalloc(sizeof(*node), GFP_KERNEL); 2004 1.1 riastrad if (!node) { 2005 1.1 riastrad ret = -ENOMEM; 2006 1.1 riastrad goto out; 2007 1.1 riastrad } 2008 1.1 riastrad 2009 1.1 riastrad node->start = last; 2010 1.1 riastrad node->size = n + count; 2011 1.1 riastrad node->color = node->size; 2012 1.1 riastrad 2013 1.1 riastrad err = drm_mm_reserve_node(&mm, node); 2014 1.1 riastrad if (err != -ENOSPC) { 2015 1.1 riastrad pr_err("reserve %d did not report color overlap! err=%d\n", 2016 1.1 riastrad n, err); 2017 1.1 riastrad goto out; 2018 1.1 riastrad } 2019 1.1 riastrad 2020 1.1 riastrad node->start += n + 1; 2021 1.1 riastrad rem = misalignment(node, n + count); 2022 1.1 riastrad node->start += n + count - rem; 2023 1.1 riastrad 2024 1.1 riastrad err = drm_mm_reserve_node(&mm, node); 2025 1.1 riastrad if (err) { 2026 1.1 riastrad pr_err("reserve %d failed, err=%d\n", n, err); 2027 1.1 riastrad ret = err; 2028 1.1 riastrad goto out; 2029 1.1 riastrad } 2030 1.1 riastrad 2031 1.1 riastrad last = node->start + node->size; 2032 1.1 riastrad } 2033 1.1 riastrad 2034 1.1 riastrad for (n = 1; n <= count; n++) { 2035 1.1 riastrad node = kzalloc(sizeof(*node), GFP_KERNEL); 2036 1.1 riastrad if (!node) { 2037 1.1 riastrad ret = -ENOMEM; 2038 1.1 riastrad goto out; 2039 1.1 riastrad } 2040 1.1 riastrad 2041 1.1 riastrad if (!expect_insert(&mm, node, 2042 1.1 riastrad n, n, n, 2043 1.1 riastrad mode)) { 2044 1.1 riastrad pr_err("%s insert failed, step %d\n", 2045 1.1 riastrad mode->name, n); 2046 1.1 riastrad kfree(node); 2047 1.1 riastrad goto out; 2048 1.1 riastrad } 2049 1.1 riastrad } 2050 1.1 riastrad 2051 1.1 riastrad drm_mm_for_each_node_safe(node, nn, &mm) { 2052 1.1 riastrad u64 rem; 2053 1.1 riastrad 2054 1.1 riastrad if (node->color != node->size) { 2055 1.1 riastrad pr_err("%s invalid color stored: expected %lld, found %ld\n", 2056 1.1 riastrad mode->name, node->size, node->color); 2057 1.1 riastrad 2058 1.1 riastrad goto out; 2059 1.1 riastrad } 2060 1.1 riastrad 2061 1.1 riastrad if (colors_abutt(node)) 2062 1.1 riastrad goto out; 2063 1.1 riastrad 2064 1.1 riastrad div64_u64_rem(node->start, node->size, &rem); 2065 1.1 riastrad if (rem) { 2066 1.1 riastrad pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", 2067 1.1 riastrad mode->name, node->start, node->size, rem); 2068 1.1 riastrad goto out; 2069 1.1 riastrad } 2070 1.1 riastrad 2071 1.1 riastrad drm_mm_remove_node(node); 2072 1.1 riastrad kfree(node); 2073 1.1 riastrad } 2074 1.1 riastrad 2075 1.1 riastrad cond_resched(); 2076 1.1 riastrad } 2077 1.1 riastrad 2078 1.1 riastrad ret = 0; 2079 1.1 riastrad out: 2080 1.1 riastrad drm_mm_for_each_node_safe(node, nn, &mm) { 2081 1.1 riastrad drm_mm_remove_node(node); 2082 1.1 riastrad kfree(node); 2083 1.1 riastrad } 2084 1.1 riastrad drm_mm_takedown(&mm); 2085 1.1 riastrad return ret; 2086 1.1 riastrad } 2087 1.1 riastrad 2088 1.1 riastrad static int evict_color(struct drm_mm *mm, 2089 1.1 riastrad u64 range_start, u64 range_end, 2090 1.1 riastrad struct evict_node *nodes, 2091 1.1 riastrad unsigned int *order, 2092 1.1 riastrad unsigned int count, 2093 1.1 riastrad unsigned int size, 2094 1.1 riastrad unsigned int alignment, 2095 1.1 riastrad unsigned long color, 2096 1.1 riastrad const struct insert_mode *mode) 2097 1.1 riastrad { 2098 1.1 riastrad struct drm_mm_scan scan; 2099 1.1 riastrad LIST_HEAD(evict_list); 2100 1.1 riastrad struct evict_node *e; 2101 1.1 riastrad struct drm_mm_node tmp; 2102 1.1 riastrad int err; 2103 1.1 riastrad 2104 1.1 riastrad drm_mm_scan_init_with_range(&scan, mm, 2105 1.1 riastrad size, alignment, color, 2106 1.1 riastrad range_start, range_end, 2107 1.1 riastrad mode->mode); 2108 1.1 riastrad if (!evict_nodes(&scan, 2109 1.1 riastrad nodes, order, count, true, 2110 1.1 riastrad &evict_list)) 2111 1.1 riastrad return -EINVAL; 2112 1.1 riastrad 2113 1.1 riastrad memset(&tmp, 0, sizeof(tmp)); 2114 1.1 riastrad err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, 2115 1.1 riastrad DRM_MM_INSERT_EVICT); 2116 1.1 riastrad if (err) { 2117 1.1 riastrad pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", 2118 1.1 riastrad size, alignment, color, err); 2119 1.1 riastrad show_scan(&scan); 2120 1.1 riastrad show_holes(mm, 3); 2121 1.1 riastrad return err; 2122 1.1 riastrad } 2123 1.1 riastrad 2124 1.1 riastrad if (tmp.start < range_start || tmp.start + tmp.size > range_end) { 2125 1.1 riastrad pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", 2126 1.1 riastrad tmp.start, tmp.size, range_start, range_end); 2127 1.1 riastrad err = -EINVAL; 2128 1.1 riastrad } 2129 1.1 riastrad 2130 1.1 riastrad if (colors_abutt(&tmp)) 2131 1.1 riastrad err = -EINVAL; 2132 1.1 riastrad 2133 1.1 riastrad if (!assert_node(&tmp, mm, size, alignment, color)) { 2134 1.1 riastrad pr_err("Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", 2135 1.1 riastrad tmp.size, size, 2136 1.1 riastrad alignment, misalignment(&tmp, alignment), tmp.start); 2137 1.1 riastrad err = -EINVAL; 2138 1.1 riastrad } 2139 1.1 riastrad 2140 1.1 riastrad drm_mm_remove_node(&tmp); 2141 1.1 riastrad if (err) 2142 1.1 riastrad return err; 2143 1.1 riastrad 2144 1.1 riastrad list_for_each_entry(e, &evict_list, link) { 2145 1.1 riastrad err = drm_mm_reserve_node(mm, &e->node); 2146 1.1 riastrad if (err) { 2147 1.1 riastrad pr_err("Failed to reinsert node after eviction: start=%llx\n", 2148 1.1 riastrad e->node.start); 2149 1.1 riastrad return err; 2150 1.1 riastrad } 2151 1.1 riastrad } 2152 1.1 riastrad 2153 1.1 riastrad cond_resched(); 2154 1.1 riastrad return 0; 2155 1.1 riastrad } 2156 1.1 riastrad 2157 1.1 riastrad static int igt_color_evict(void *ignored) 2158 1.1 riastrad { 2159 1.1 riastrad DRM_RND_STATE(prng, random_seed); 2160 1.1 riastrad const unsigned int total_size = min(8192u, max_iterations); 2161 1.1 riastrad const struct insert_mode *mode; 2162 1.1 riastrad unsigned long color = 0; 2163 1.1 riastrad struct drm_mm mm; 2164 1.1 riastrad struct evict_node *nodes; 2165 1.1 riastrad struct drm_mm_node *node, *next; 2166 1.1 riastrad unsigned int *order, n; 2167 1.1 riastrad int ret, err; 2168 1.1 riastrad 2169 1.1 riastrad /* Check that the drm_mm_scan also honours color adjustment when 2170 1.1 riastrad * choosing its victims to create a hole. Our color_adjust does not 2171 1.1 riastrad * allow two nodes to be placed together without an intervening hole 2172 1.1 riastrad * enlarging the set of victims that must be evicted. 2173 1.1 riastrad */ 2174 1.1 riastrad 2175 1.1 riastrad ret = -ENOMEM; 2176 1.1 riastrad nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 2177 1.1 riastrad if (!nodes) 2178 1.1 riastrad goto err; 2179 1.1 riastrad 2180 1.1 riastrad order = drm_random_order(total_size, &prng); 2181 1.1 riastrad if (!order) 2182 1.1 riastrad goto err_nodes; 2183 1.1 riastrad 2184 1.1 riastrad ret = -EINVAL; 2185 1.1 riastrad drm_mm_init(&mm, 0, 2*total_size - 1); 2186 1.1 riastrad mm.color_adjust = separate_adjacent_colors; 2187 1.1 riastrad for (n = 0; n < total_size; n++) { 2188 1.1 riastrad if (!expect_insert(&mm, &nodes[n].node, 2189 1.1 riastrad 1, 0, color++, 2190 1.1 riastrad &insert_modes[0])) { 2191 1.1 riastrad pr_err("insert failed, step %d\n", n); 2192 1.1 riastrad goto out; 2193 1.1 riastrad } 2194 1.1 riastrad } 2195 1.1 riastrad 2196 1.1 riastrad for (mode = evict_modes; mode->name; mode++) { 2197 1.1 riastrad for (n = 1; n <= total_size; n <<= 1) { 2198 1.1 riastrad drm_random_reorder(order, total_size, &prng); 2199 1.1 riastrad err = evict_color(&mm, 0, U64_MAX, 2200 1.1 riastrad nodes, order, total_size, 2201 1.1 riastrad n, 1, color++, 2202 1.1 riastrad mode); 2203 1.1 riastrad if (err) { 2204 1.1 riastrad pr_err("%s evict_color(size=%u) failed\n", 2205 1.1 riastrad mode->name, n); 2206 1.1 riastrad goto out; 2207 1.1 riastrad } 2208 1.1 riastrad } 2209 1.1 riastrad 2210 1.1 riastrad for (n = 1; n < total_size; n <<= 1) { 2211 1.1 riastrad drm_random_reorder(order, total_size, &prng); 2212 1.1 riastrad err = evict_color(&mm, 0, U64_MAX, 2213 1.1 riastrad nodes, order, total_size, 2214 1.1 riastrad total_size/2, n, color++, 2215 1.1 riastrad mode); 2216 1.1 riastrad if (err) { 2217 1.1 riastrad pr_err("%s evict_color(size=%u, alignment=%u) failed\n", 2218 1.1 riastrad mode->name, total_size/2, n); 2219 1.1 riastrad goto out; 2220 1.1 riastrad } 2221 1.1 riastrad } 2222 1.1 riastrad 2223 1.1 riastrad for_each_prime_number_from(n, 1, min(total_size, max_prime)) { 2224 1.1 riastrad unsigned int nsize = (total_size - n + 1) / 2; 2225 1.1 riastrad 2226 1.1 riastrad DRM_MM_BUG_ON(!nsize); 2227 1.1 riastrad 2228 1.1 riastrad drm_random_reorder(order, total_size, &prng); 2229 1.1 riastrad err = evict_color(&mm, 0, U64_MAX, 2230 1.1 riastrad nodes, order, total_size, 2231 1.1 riastrad nsize, n, color++, 2232 1.1 riastrad mode); 2233 1.1 riastrad if (err) { 2234 1.1 riastrad pr_err("%s evict_color(size=%u, alignment=%u) failed\n", 2235 1.1 riastrad mode->name, nsize, n); 2236 1.1 riastrad goto out; 2237 1.1 riastrad } 2238 1.1 riastrad } 2239 1.1 riastrad 2240 1.1 riastrad cond_resched(); 2241 1.1 riastrad } 2242 1.1 riastrad 2243 1.1 riastrad ret = 0; 2244 1.1 riastrad out: 2245 1.1 riastrad if (ret) 2246 1.1 riastrad show_mm(&mm); 2247 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 2248 1.1 riastrad drm_mm_remove_node(node); 2249 1.1 riastrad drm_mm_takedown(&mm); 2250 1.1 riastrad kfree(order); 2251 1.1 riastrad err_nodes: 2252 1.1 riastrad vfree(nodes); 2253 1.1 riastrad err: 2254 1.1 riastrad return ret; 2255 1.1 riastrad } 2256 1.1 riastrad 2257 1.1 riastrad static int igt_color_evict_range(void *ignored) 2258 1.1 riastrad { 2259 1.1 riastrad DRM_RND_STATE(prng, random_seed); 2260 1.1 riastrad const unsigned int total_size = 8192; 2261 1.1 riastrad const unsigned int range_size = total_size / 2; 2262 1.1 riastrad const unsigned int range_start = total_size / 4; 2263 1.1 riastrad const unsigned int range_end = range_start + range_size; 2264 1.1 riastrad const struct insert_mode *mode; 2265 1.1 riastrad unsigned long color = 0; 2266 1.1 riastrad struct drm_mm mm; 2267 1.1 riastrad struct evict_node *nodes; 2268 1.1 riastrad struct drm_mm_node *node, *next; 2269 1.1 riastrad unsigned int *order, n; 2270 1.1 riastrad int ret, err; 2271 1.1 riastrad 2272 1.1 riastrad /* Like igt_color_evict(), but limited to small portion of the full 2273 1.1 riastrad * drm_mm range. 2274 1.1 riastrad */ 2275 1.1 riastrad 2276 1.1 riastrad ret = -ENOMEM; 2277 1.1 riastrad nodes = vzalloc(array_size(total_size, sizeof(*nodes))); 2278 1.1 riastrad if (!nodes) 2279 1.1 riastrad goto err; 2280 1.1 riastrad 2281 1.1 riastrad order = drm_random_order(total_size, &prng); 2282 1.1 riastrad if (!order) 2283 1.1 riastrad goto err_nodes; 2284 1.1 riastrad 2285 1.1 riastrad ret = -EINVAL; 2286 1.1 riastrad drm_mm_init(&mm, 0, 2*total_size - 1); 2287 1.1 riastrad mm.color_adjust = separate_adjacent_colors; 2288 1.1 riastrad for (n = 0; n < total_size; n++) { 2289 1.1 riastrad if (!expect_insert(&mm, &nodes[n].node, 2290 1.1 riastrad 1, 0, color++, 2291 1.1 riastrad &insert_modes[0])) { 2292 1.1 riastrad pr_err("insert failed, step %d\n", n); 2293 1.1 riastrad goto out; 2294 1.1 riastrad } 2295 1.1 riastrad } 2296 1.1 riastrad 2297 1.1 riastrad for (mode = evict_modes; mode->name; mode++) { 2298 1.1 riastrad for (n = 1; n <= range_size; n <<= 1) { 2299 1.1 riastrad drm_random_reorder(order, range_size, &prng); 2300 1.1 riastrad err = evict_color(&mm, range_start, range_end, 2301 1.1 riastrad nodes, order, total_size, 2302 1.1 riastrad n, 1, color++, 2303 1.1 riastrad mode); 2304 1.1 riastrad if (err) { 2305 1.1 riastrad pr_err("%s evict_color(size=%u) failed for range [%x, %x]\n", 2306 1.1 riastrad mode->name, n, range_start, range_end); 2307 1.1 riastrad goto out; 2308 1.1 riastrad } 2309 1.1 riastrad } 2310 1.1 riastrad 2311 1.1 riastrad for (n = 1; n < range_size; n <<= 1) { 2312 1.1 riastrad drm_random_reorder(order, total_size, &prng); 2313 1.1 riastrad err = evict_color(&mm, range_start, range_end, 2314 1.1 riastrad nodes, order, total_size, 2315 1.1 riastrad range_size/2, n, color++, 2316 1.1 riastrad mode); 2317 1.1 riastrad if (err) { 2318 1.1 riastrad pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 2319 1.1 riastrad mode->name, total_size/2, n, range_start, range_end); 2320 1.1 riastrad goto out; 2321 1.1 riastrad } 2322 1.1 riastrad } 2323 1.1 riastrad 2324 1.1 riastrad for_each_prime_number_from(n, 1, min(range_size, max_prime)) { 2325 1.1 riastrad unsigned int nsize = (range_size - n + 1) / 2; 2326 1.1 riastrad 2327 1.1 riastrad DRM_MM_BUG_ON(!nsize); 2328 1.1 riastrad 2329 1.1 riastrad drm_random_reorder(order, total_size, &prng); 2330 1.1 riastrad err = evict_color(&mm, range_start, range_end, 2331 1.1 riastrad nodes, order, total_size, 2332 1.1 riastrad nsize, n, color++, 2333 1.1 riastrad mode); 2334 1.1 riastrad if (err) { 2335 1.1 riastrad pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", 2336 1.1 riastrad mode->name, nsize, n, range_start, range_end); 2337 1.1 riastrad goto out; 2338 1.1 riastrad } 2339 1.1 riastrad } 2340 1.1 riastrad 2341 1.1 riastrad cond_resched(); 2342 1.1 riastrad } 2343 1.1 riastrad 2344 1.1 riastrad ret = 0; 2345 1.1 riastrad out: 2346 1.1 riastrad if (ret) 2347 1.1 riastrad show_mm(&mm); 2348 1.1 riastrad drm_mm_for_each_node_safe(node, next, &mm) 2349 1.1 riastrad drm_mm_remove_node(node); 2350 1.1 riastrad drm_mm_takedown(&mm); 2351 1.1 riastrad kfree(order); 2352 1.1 riastrad err_nodes: 2353 1.1 riastrad vfree(nodes); 2354 1.1 riastrad err: 2355 1.1 riastrad return ret; 2356 1.1 riastrad } 2357 1.1 riastrad 2358 1.1 riastrad #include "drm_selftest.c" 2359 1.1 riastrad 2360 1.1 riastrad static int __init test_drm_mm_init(void) 2361 1.1 riastrad { 2362 1.1 riastrad int err; 2363 1.1 riastrad 2364 1.1 riastrad while (!random_seed) 2365 1.1 riastrad random_seed = get_random_int(); 2366 1.1 riastrad 2367 1.1 riastrad pr_info("Testing DRM range manger (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n", 2368 1.1 riastrad random_seed, max_iterations, max_prime); 2369 1.1 riastrad err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); 2370 1.1 riastrad 2371 1.1 riastrad return err > 0 ? 0 : err; 2372 1.1 riastrad } 2373 1.1 riastrad 2374 1.1 riastrad static void __exit test_drm_mm_exit(void) 2375 1.1 riastrad { 2376 1.1 riastrad } 2377 1.1 riastrad 2378 1.1 riastrad module_init(test_drm_mm_init); 2379 1.1 riastrad module_exit(test_drm_mm_exit); 2380 1.1 riastrad 2381 1.1 riastrad module_param(random_seed, uint, 0400); 2382 1.1 riastrad module_param(max_iterations, uint, 0400); 2383 1.1 riastrad module_param(max_prime, uint, 0400); 2384 1.1 riastrad 2385 1.1 riastrad MODULE_AUTHOR("Intel Corporation"); 2386 1.1 riastrad MODULE_LICENSE("GPL"); 2387