1 1.1 riastrad /* $NetBSD: i915_syncmap.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2017 Intel Corporation 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice (including the next 14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 15 1.1 riastrad * Software. 16 1.1 riastrad * 17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 1.1 riastrad * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 1.1 riastrad * IN THE SOFTWARE. 24 1.1 riastrad * 25 1.1 riastrad */ 26 1.1 riastrad 27 1.1 riastrad #include <sys/cdefs.h> 28 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: i915_syncmap.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $"); 29 1.1 riastrad 30 1.1 riastrad #include "../i915_selftest.h" 31 1.1 riastrad #include "i915_random.h" 32 1.1 riastrad 33 1.1 riastrad static char * 34 1.1 riastrad __sync_print(struct i915_syncmap *p, 35 1.1 riastrad char *buf, unsigned long *sz, 36 1.1 riastrad unsigned int depth, 37 1.1 riastrad unsigned int last, 38 1.1 riastrad unsigned int idx) 39 1.1 riastrad { 40 1.1 riastrad unsigned long len; 41 1.1 riastrad unsigned int i, X; 42 1.1 riastrad 43 1.1 riastrad if (depth) { 44 1.1 riastrad unsigned int d; 45 1.1 riastrad 46 1.1 riastrad for (d = 0; d < depth - 1; d++) { 47 1.1 riastrad if (last & BIT(depth - d - 1)) 48 1.1 riastrad len = scnprintf(buf, *sz, "| "); 49 1.1 riastrad else 50 1.1 riastrad len = scnprintf(buf, *sz, " "); 51 1.1 riastrad buf += len; 52 1.1 riastrad *sz -= len; 53 1.1 riastrad } 54 1.1 riastrad len = scnprintf(buf, *sz, "%x-> ", idx); 55 1.1 riastrad buf += len; 56 1.1 riastrad *sz -= len; 57 1.1 riastrad } 58 1.1 riastrad 59 1.1 riastrad /* We mark bits after the prefix as "X" */ 60 1.1 riastrad len = scnprintf(buf, *sz, "0x%016llx", p->prefix << p->height << SHIFT); 61 1.1 riastrad buf += len; 62 1.1 riastrad *sz -= len; 63 1.1 riastrad X = (p->height + SHIFT) / 4; 64 1.1 riastrad scnprintf(buf - X, *sz + X, "%*s", X, "XXXXXXXXXXXXXXXXX"); 65 1.1 riastrad 66 1.1 riastrad if (!p->height) { 67 1.1 riastrad for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { 68 1.1 riastrad len = scnprintf(buf, *sz, " %x:%x,", 69 1.1 riastrad i, __sync_seqno(p)[i]); 70 1.1 riastrad buf += len; 71 1.1 riastrad *sz -= len; 72 1.1 riastrad } 73 1.1 riastrad buf -= 1; 74 1.1 riastrad *sz += 1; 75 1.1 riastrad } 76 1.1 riastrad 77 1.1 riastrad len = scnprintf(buf, *sz, "\n"); 78 1.1 riastrad buf += len; 79 1.1 riastrad *sz -= len; 80 1.1 riastrad 81 1.1 riastrad if (p->height) { 82 1.1 riastrad for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { 83 1.1 riastrad buf = __sync_print(__sync_child(p)[i], buf, sz, 84 1.1 riastrad depth + 1, 85 1.1 riastrad last << 1 | !!(p->bitmap >> (i + 1)), 86 1.1 riastrad i); 87 1.1 riastrad } 88 1.1 riastrad } 89 1.1 riastrad 90 1.1 riastrad return buf; 91 1.1 riastrad } 92 1.1 riastrad 93 1.1 riastrad static bool 94 1.1 riastrad i915_syncmap_print_to_buf(struct i915_syncmap *p, char *buf, unsigned long sz) 95 1.1 riastrad { 96 1.1 riastrad if (!p) 97 1.1 riastrad return false; 98 1.1 riastrad 99 1.1 riastrad while (p->parent) 100 1.1 riastrad p = p->parent; 101 1.1 riastrad 102 1.1 riastrad __sync_print(p, buf, &sz, 0, 1, 0); 103 1.1 riastrad return true; 104 1.1 riastrad } 105 1.1 riastrad 106 1.1 riastrad static int check_syncmap_free(struct i915_syncmap **sync) 107 1.1 riastrad { 108 1.1 riastrad i915_syncmap_free(sync); 109 1.1 riastrad if (*sync) { 110 1.1 riastrad pr_err("sync not cleared after free\n"); 111 1.1 riastrad return -EINVAL; 112 1.1 riastrad } 113 1.1 riastrad 114 1.1 riastrad return 0; 115 1.1 riastrad } 116 1.1 riastrad 117 1.1 riastrad static int dump_syncmap(struct i915_syncmap *sync, int err) 118 1.1 riastrad { 119 1.1 riastrad char *buf; 120 1.1 riastrad 121 1.1 riastrad if (!err) 122 1.1 riastrad return check_syncmap_free(&sync); 123 1.1 riastrad 124 1.1 riastrad buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 125 1.1 riastrad if (!buf) 126 1.1 riastrad goto skip; 127 1.1 riastrad 128 1.1 riastrad if (i915_syncmap_print_to_buf(sync, buf, PAGE_SIZE)) 129 1.1 riastrad pr_err("%s", buf); 130 1.1 riastrad 131 1.1 riastrad kfree(buf); 132 1.1 riastrad 133 1.1 riastrad skip: 134 1.1 riastrad i915_syncmap_free(&sync); 135 1.1 riastrad return err; 136 1.1 riastrad } 137 1.1 riastrad 138 1.1 riastrad static int igt_syncmap_init(void *arg) 139 1.1 riastrad { 140 1.1 riastrad struct i915_syncmap *sync = (void *)~0ul; 141 1.1 riastrad 142 1.1 riastrad /* 143 1.1 riastrad * Cursory check that we can initialise a random pointer and transform 144 1.1 riastrad * it into the root pointer of a syncmap. 145 1.1 riastrad */ 146 1.1 riastrad 147 1.1 riastrad i915_syncmap_init(&sync); 148 1.1 riastrad return check_syncmap_free(&sync); 149 1.1 riastrad } 150 1.1 riastrad 151 1.1 riastrad static int check_seqno(struct i915_syncmap *leaf, unsigned int idx, u32 seqno) 152 1.1 riastrad { 153 1.1 riastrad if (leaf->height) { 154 1.1 riastrad pr_err("%s: not a leaf, height is %d\n", 155 1.1 riastrad __func__, leaf->height); 156 1.1 riastrad return -EINVAL; 157 1.1 riastrad } 158 1.1 riastrad 159 1.1 riastrad if (__sync_seqno(leaf)[idx] != seqno) { 160 1.1 riastrad pr_err("%s: seqno[%d], found %x, expected %x\n", 161 1.1 riastrad __func__, idx, __sync_seqno(leaf)[idx], seqno); 162 1.1 riastrad return -EINVAL; 163 1.1 riastrad } 164 1.1 riastrad 165 1.1 riastrad return 0; 166 1.1 riastrad } 167 1.1 riastrad 168 1.1 riastrad static int check_one(struct i915_syncmap **sync, u64 context, u32 seqno) 169 1.1 riastrad { 170 1.1 riastrad int err; 171 1.1 riastrad 172 1.1 riastrad err = i915_syncmap_set(sync, context, seqno); 173 1.1 riastrad if (err) 174 1.1 riastrad return err; 175 1.1 riastrad 176 1.1 riastrad if ((*sync)->height) { 177 1.1 riastrad pr_err("Inserting first context=%llx did not return leaf (height=%d, prefix=%llx\n", 178 1.1 riastrad context, (*sync)->height, (*sync)->prefix); 179 1.1 riastrad return -EINVAL; 180 1.1 riastrad } 181 1.1 riastrad 182 1.1 riastrad if ((*sync)->parent) { 183 1.1 riastrad pr_err("Inserting first context=%llx created branches!\n", 184 1.1 riastrad context); 185 1.1 riastrad return -EINVAL; 186 1.1 riastrad } 187 1.1 riastrad 188 1.1 riastrad if (hweight32((*sync)->bitmap) != 1) { 189 1.1 riastrad pr_err("First bitmap does not contain a single entry, found %x (count=%d)!\n", 190 1.1 riastrad (*sync)->bitmap, hweight32((*sync)->bitmap)); 191 1.1 riastrad return -EINVAL; 192 1.1 riastrad } 193 1.1 riastrad 194 1.1 riastrad err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno); 195 1.1 riastrad if (err) 196 1.1 riastrad return err; 197 1.1 riastrad 198 1.1 riastrad if (!i915_syncmap_is_later(sync, context, seqno)) { 199 1.1 riastrad pr_err("Lookup of first context=%llx/seqno=%x failed!\n", 200 1.1 riastrad context, seqno); 201 1.1 riastrad return -EINVAL; 202 1.1 riastrad } 203 1.1 riastrad 204 1.1 riastrad return 0; 205 1.1 riastrad } 206 1.1 riastrad 207 1.1 riastrad static int igt_syncmap_one(void *arg) 208 1.1 riastrad { 209 1.1 riastrad I915_RND_STATE(prng); 210 1.1 riastrad IGT_TIMEOUT(end_time); 211 1.1 riastrad struct i915_syncmap *sync; 212 1.1 riastrad unsigned long max = 1; 213 1.1 riastrad int err; 214 1.1 riastrad 215 1.1 riastrad /* 216 1.1 riastrad * Check that inserting a new id, creates a leaf and only that leaf. 217 1.1 riastrad */ 218 1.1 riastrad 219 1.1 riastrad i915_syncmap_init(&sync); 220 1.1 riastrad 221 1.1 riastrad do { 222 1.1 riastrad u64 context = i915_prandom_u64_state(&prng); 223 1.1 riastrad unsigned long loop; 224 1.1 riastrad 225 1.1 riastrad err = check_syncmap_free(&sync); 226 1.1 riastrad if (err) 227 1.1 riastrad goto out; 228 1.1 riastrad 229 1.1 riastrad for (loop = 0; loop <= max; loop++) { 230 1.1 riastrad err = check_one(&sync, context, 231 1.1 riastrad prandom_u32_state(&prng)); 232 1.1 riastrad if (err) 233 1.1 riastrad goto out; 234 1.1 riastrad } 235 1.1 riastrad max++; 236 1.1 riastrad } while (!__igt_timeout(end_time, NULL)); 237 1.1 riastrad pr_debug("%s: Completed %lu single insertions\n", 238 1.1 riastrad __func__, max * (max - 1) / 2); 239 1.1 riastrad out: 240 1.1 riastrad return dump_syncmap(sync, err); 241 1.1 riastrad } 242 1.1 riastrad 243 1.1 riastrad static int check_leaf(struct i915_syncmap **sync, u64 context, u32 seqno) 244 1.1 riastrad { 245 1.1 riastrad int err; 246 1.1 riastrad 247 1.1 riastrad err = i915_syncmap_set(sync, context, seqno); 248 1.1 riastrad if (err) 249 1.1 riastrad return err; 250 1.1 riastrad 251 1.1 riastrad if ((*sync)->height) { 252 1.1 riastrad pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n", 253 1.1 riastrad context, (*sync)->height, (*sync)->prefix); 254 1.1 riastrad return -EINVAL; 255 1.1 riastrad } 256 1.1 riastrad 257 1.1 riastrad if (hweight32((*sync)->bitmap) != 1) { 258 1.1 riastrad pr_err("First entry into leaf (context=%llx) does not contain a single entry, found %x (count=%d)!\n", 259 1.1 riastrad context, (*sync)->bitmap, hweight32((*sync)->bitmap)); 260 1.1 riastrad return -EINVAL; 261 1.1 riastrad } 262 1.1 riastrad 263 1.1 riastrad err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno); 264 1.1 riastrad if (err) 265 1.1 riastrad return err; 266 1.1 riastrad 267 1.1 riastrad if (!i915_syncmap_is_later(sync, context, seqno)) { 268 1.1 riastrad pr_err("Lookup of first entry context=%llx/seqno=%x failed!\n", 269 1.1 riastrad context, seqno); 270 1.1 riastrad return -EINVAL; 271 1.1 riastrad } 272 1.1 riastrad 273 1.1 riastrad return 0; 274 1.1 riastrad } 275 1.1 riastrad 276 1.1 riastrad static int igt_syncmap_join_above(void *arg) 277 1.1 riastrad { 278 1.1 riastrad struct i915_syncmap *sync; 279 1.1 riastrad unsigned int pass, order; 280 1.1 riastrad int err; 281 1.1 riastrad 282 1.1 riastrad i915_syncmap_init(&sync); 283 1.1 riastrad 284 1.1 riastrad /* 285 1.1 riastrad * When we have a new id that doesn't fit inside the existing tree, 286 1.1 riastrad * we need to add a new layer above. 287 1.1 riastrad * 288 1.1 riastrad * 1: 0x00000001 289 1.1 riastrad * 2: 0x00000010 290 1.1 riastrad * 3: 0x00000100 291 1.1 riastrad * 4: 0x00001000 292 1.1 riastrad * ... 293 1.1 riastrad * Each pass the common prefix shrinks and we have to insert a join. 294 1.1 riastrad * Each join will only contain two branches, the latest of which 295 1.1 riastrad * is always a leaf. 296 1.1 riastrad * 297 1.1 riastrad * If we then reuse the same set of contexts, we expect to build an 298 1.1 riastrad * identical tree. 299 1.1 riastrad */ 300 1.1 riastrad for (pass = 0; pass < 3; pass++) { 301 1.1 riastrad for (order = 0; order < 64; order += SHIFT) { 302 1.1 riastrad u64 context = BIT_ULL(order); 303 1.1 riastrad struct i915_syncmap *join; 304 1.1 riastrad 305 1.1 riastrad err = check_leaf(&sync, context, 0); 306 1.1 riastrad if (err) 307 1.1 riastrad goto out; 308 1.1 riastrad 309 1.1 riastrad join = sync->parent; 310 1.1 riastrad if (!join) /* very first insert will have no parents */ 311 1.1 riastrad continue; 312 1.1 riastrad 313 1.1 riastrad if (!join->height) { 314 1.1 riastrad pr_err("Parent with no height!\n"); 315 1.1 riastrad err = -EINVAL; 316 1.1 riastrad goto out; 317 1.1 riastrad } 318 1.1 riastrad 319 1.1 riastrad if (hweight32(join->bitmap) != 2) { 320 1.1 riastrad pr_err("Join does not have 2 children: %x (%d)\n", 321 1.1 riastrad join->bitmap, hweight32(join->bitmap)); 322 1.1 riastrad err = -EINVAL; 323 1.1 riastrad goto out; 324 1.1 riastrad } 325 1.1 riastrad 326 1.1 riastrad if (__sync_child(join)[__sync_branch_idx(join, context)] != sync) { 327 1.1 riastrad pr_err("Leaf misplaced in parent!\n"); 328 1.1 riastrad err = -EINVAL; 329 1.1 riastrad goto out; 330 1.1 riastrad } 331 1.1 riastrad } 332 1.1 riastrad } 333 1.1 riastrad out: 334 1.1 riastrad return dump_syncmap(sync, err); 335 1.1 riastrad } 336 1.1 riastrad 337 1.1 riastrad static int igt_syncmap_join_below(void *arg) 338 1.1 riastrad { 339 1.1 riastrad struct i915_syncmap *sync; 340 1.1 riastrad unsigned int step, order, idx; 341 1.1 riastrad int err = -ENODEV; 342 1.1 riastrad 343 1.1 riastrad i915_syncmap_init(&sync); 344 1.1 riastrad 345 1.1 riastrad /* 346 1.1 riastrad * Check that we can split a compacted branch by replacing it with 347 1.1 riastrad * a join. 348 1.1 riastrad */ 349 1.1 riastrad for (step = 0; step < KSYNCMAP; step++) { 350 1.1 riastrad for (order = 64 - SHIFT; order > 0; order -= SHIFT) { 351 1.1 riastrad u64 context = step * BIT_ULL(order); 352 1.1 riastrad 353 1.1 riastrad err = i915_syncmap_set(&sync, context, 0); 354 1.1 riastrad if (err) 355 1.1 riastrad goto out; 356 1.1 riastrad 357 1.1 riastrad if (sync->height) { 358 1.1 riastrad pr_err("Inserting context=%llx (order=%d, step=%d) did not return leaf (height=%d, prefix=%llx\n", 359 1.1 riastrad context, order, step, sync->height, sync->prefix); 360 1.1 riastrad err = -EINVAL; 361 1.1 riastrad goto out; 362 1.1 riastrad } 363 1.1 riastrad } 364 1.1 riastrad } 365 1.1 riastrad 366 1.1 riastrad for (step = 0; step < KSYNCMAP; step++) { 367 1.1 riastrad for (order = SHIFT; order < 64; order += SHIFT) { 368 1.1 riastrad u64 context = step * BIT_ULL(order); 369 1.1 riastrad 370 1.1 riastrad if (!i915_syncmap_is_later(&sync, context, 0)) { 371 1.1 riastrad pr_err("1: context %llx (order=%d, step=%d) not found\n", 372 1.1 riastrad context, order, step); 373 1.1 riastrad err = -EINVAL; 374 1.1 riastrad goto out; 375 1.1 riastrad } 376 1.1 riastrad 377 1.1 riastrad for (idx = 1; idx < KSYNCMAP; idx++) { 378 1.1 riastrad if (i915_syncmap_is_later(&sync, context + idx, 0)) { 379 1.1 riastrad pr_err("1: context %llx (order=%d, step=%d) should not exist\n", 380 1.1 riastrad context + idx, order, step); 381 1.1 riastrad err = -EINVAL; 382 1.1 riastrad goto out; 383 1.1 riastrad } 384 1.1 riastrad } 385 1.1 riastrad } 386 1.1 riastrad } 387 1.1 riastrad 388 1.1 riastrad for (order = SHIFT; order < 64; order += SHIFT) { 389 1.1 riastrad for (step = 0; step < KSYNCMAP; step++) { 390 1.1 riastrad u64 context = step * BIT_ULL(order); 391 1.1 riastrad 392 1.1 riastrad if (!i915_syncmap_is_later(&sync, context, 0)) { 393 1.1 riastrad pr_err("2: context %llx (order=%d, step=%d) not found\n", 394 1.1 riastrad context, order, step); 395 1.1 riastrad err = -EINVAL; 396 1.1 riastrad goto out; 397 1.1 riastrad } 398 1.1 riastrad } 399 1.1 riastrad } 400 1.1 riastrad 401 1.1 riastrad out: 402 1.1 riastrad return dump_syncmap(sync, err); 403 1.1 riastrad } 404 1.1 riastrad 405 1.1 riastrad static int igt_syncmap_neighbours(void *arg) 406 1.1 riastrad { 407 1.1 riastrad I915_RND_STATE(prng); 408 1.1 riastrad IGT_TIMEOUT(end_time); 409 1.1 riastrad struct i915_syncmap *sync; 410 1.1 riastrad int err = -ENODEV; 411 1.1 riastrad 412 1.1 riastrad /* 413 1.1 riastrad * Each leaf holds KSYNCMAP seqno. Check that when we create KSYNCMAP 414 1.1 riastrad * neighbouring ids, they all fit into the same leaf. 415 1.1 riastrad */ 416 1.1 riastrad 417 1.1 riastrad i915_syncmap_init(&sync); 418 1.1 riastrad do { 419 1.1 riastrad u64 context = i915_prandom_u64_state(&prng) & ~MASK; 420 1.1 riastrad unsigned int idx; 421 1.1 riastrad 422 1.1 riastrad if (i915_syncmap_is_later(&sync, context, 0)) /* Skip repeats */ 423 1.1 riastrad continue; 424 1.1 riastrad 425 1.1 riastrad for (idx = 0; idx < KSYNCMAP; idx++) { 426 1.1 riastrad err = i915_syncmap_set(&sync, context + idx, 0); 427 1.1 riastrad if (err) 428 1.1 riastrad goto out; 429 1.1 riastrad 430 1.1 riastrad if (sync->height) { 431 1.1 riastrad pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n", 432 1.1 riastrad context, sync->height, sync->prefix); 433 1.1 riastrad err = -EINVAL; 434 1.1 riastrad goto out; 435 1.1 riastrad } 436 1.1 riastrad 437 1.1 riastrad if (sync->bitmap != BIT(idx + 1) - 1) { 438 1.1 riastrad pr_err("Inserting neighbouring context=0x%llx+%d, did not fit into the same leaf bitmap=%x (%d), expected %lx (%d)\n", 439 1.1 riastrad context, idx, 440 1.1 riastrad sync->bitmap, hweight32(sync->bitmap), 441 1.1 riastrad BIT(idx + 1) - 1, idx + 1); 442 1.1 riastrad err = -EINVAL; 443 1.1 riastrad goto out; 444 1.1 riastrad } 445 1.1 riastrad } 446 1.1 riastrad } while (!__igt_timeout(end_time, NULL)); 447 1.1 riastrad out: 448 1.1 riastrad return dump_syncmap(sync, err); 449 1.1 riastrad } 450 1.1 riastrad 451 1.1 riastrad static int igt_syncmap_compact(void *arg) 452 1.1 riastrad { 453 1.1 riastrad struct i915_syncmap *sync; 454 1.1 riastrad unsigned int idx, order; 455 1.1 riastrad int err = -ENODEV; 456 1.1 riastrad 457 1.1 riastrad i915_syncmap_init(&sync); 458 1.1 riastrad 459 1.1 riastrad /* 460 1.1 riastrad * The syncmap are "space efficient" compressed radix trees - any 461 1.1 riastrad * branch with only one child is skipped and replaced by the child. 462 1.1 riastrad * 463 1.1 riastrad * If we construct a tree with ids that are neighbouring at a non-zero 464 1.1 riastrad * height, we form a join but each child of that join is directly a 465 1.1 riastrad * leaf holding the single id. 466 1.1 riastrad */ 467 1.1 riastrad for (order = SHIFT; order < 64; order += SHIFT) { 468 1.1 riastrad err = check_syncmap_free(&sync); 469 1.1 riastrad if (err) 470 1.1 riastrad goto out; 471 1.1 riastrad 472 1.1 riastrad /* Create neighbours in the parent */ 473 1.1 riastrad for (idx = 0; idx < KSYNCMAP; idx++) { 474 1.1 riastrad u64 context = idx * BIT_ULL(order) + idx; 475 1.1 riastrad 476 1.1 riastrad err = i915_syncmap_set(&sync, context, 0); 477 1.1 riastrad if (err) 478 1.1 riastrad goto out; 479 1.1 riastrad 480 1.1 riastrad if (sync->height) { 481 1.1 riastrad pr_err("Inserting context=%llx (order=%d, idx=%d) did not return leaf (height=%d, prefix=%llx\n", 482 1.1 riastrad context, order, idx, 483 1.1 riastrad sync->height, sync->prefix); 484 1.1 riastrad err = -EINVAL; 485 1.1 riastrad goto out; 486 1.1 riastrad } 487 1.1 riastrad } 488 1.1 riastrad 489 1.1 riastrad sync = sync->parent; 490 1.1 riastrad if (sync->parent) { 491 1.1 riastrad pr_err("Parent (join) of last leaf was not the sync!\n"); 492 1.1 riastrad err = -EINVAL; 493 1.1 riastrad goto out; 494 1.1 riastrad } 495 1.1 riastrad 496 1.1 riastrad if (sync->height != order) { 497 1.1 riastrad pr_err("Join does not have the expected height, found %d, expected %d\n", 498 1.1 riastrad sync->height, order); 499 1.1 riastrad err = -EINVAL; 500 1.1 riastrad goto out; 501 1.1 riastrad } 502 1.1 riastrad 503 1.1 riastrad if (sync->bitmap != BIT(KSYNCMAP) - 1) { 504 1.1 riastrad pr_err("Join is not full!, found %x (%d) expected %lx (%d)\n", 505 1.1 riastrad sync->bitmap, hweight32(sync->bitmap), 506 1.1 riastrad BIT(KSYNCMAP) - 1, KSYNCMAP); 507 1.1 riastrad err = -EINVAL; 508 1.1 riastrad goto out; 509 1.1 riastrad } 510 1.1 riastrad 511 1.1 riastrad /* Each of our children should be a leaf */ 512 1.1 riastrad for (idx = 0; idx < KSYNCMAP; idx++) { 513 1.1 riastrad struct i915_syncmap *leaf = __sync_child(sync)[idx]; 514 1.1 riastrad 515 1.1 riastrad if (leaf->height) { 516 1.1 riastrad pr_err("Child %d is a not leaf!\n", idx); 517 1.1 riastrad err = -EINVAL; 518 1.1 riastrad goto out; 519 1.1 riastrad } 520 1.1 riastrad 521 1.1 riastrad if (leaf->parent != sync) { 522 1.1 riastrad pr_err("Child %d is not attached to us!\n", 523 1.1 riastrad idx); 524 1.1 riastrad err = -EINVAL; 525 1.1 riastrad goto out; 526 1.1 riastrad } 527 1.1 riastrad 528 1.1 riastrad if (!is_power_of_2(leaf->bitmap)) { 529 1.1 riastrad pr_err("Child %d holds more than one id, found %x (%d)\n", 530 1.1 riastrad idx, leaf->bitmap, hweight32(leaf->bitmap)); 531 1.1 riastrad err = -EINVAL; 532 1.1 riastrad goto out; 533 1.1 riastrad } 534 1.1 riastrad 535 1.1 riastrad if (leaf->bitmap != BIT(idx)) { 536 1.1 riastrad pr_err("Child %d has wrong seqno idx, found %d, expected %d\n", 537 1.1 riastrad idx, ilog2(leaf->bitmap), idx); 538 1.1 riastrad err = -EINVAL; 539 1.1 riastrad goto out; 540 1.1 riastrad } 541 1.1 riastrad } 542 1.1 riastrad } 543 1.1 riastrad out: 544 1.1 riastrad return dump_syncmap(sync, err); 545 1.1 riastrad } 546 1.1 riastrad 547 1.1 riastrad static int igt_syncmap_random(void *arg) 548 1.1 riastrad { 549 1.1 riastrad I915_RND_STATE(prng); 550 1.1 riastrad IGT_TIMEOUT(end_time); 551 1.1 riastrad struct i915_syncmap *sync; 552 1.1 riastrad unsigned long count, phase, i; 553 1.1 riastrad u32 seqno; 554 1.1 riastrad int err; 555 1.1 riastrad 556 1.1 riastrad i915_syncmap_init(&sync); 557 1.1 riastrad 558 1.1 riastrad /* 559 1.1 riastrad * Having tried to test the individual operations within i915_syncmap, 560 1.1 riastrad * run a smoketest exploring the entire u64 space with random 561 1.1 riastrad * insertions. 562 1.1 riastrad */ 563 1.1 riastrad 564 1.1 riastrad count = 0; 565 1.1 riastrad phase = jiffies + HZ/100 + 1; 566 1.1 riastrad do { 567 1.1 riastrad u64 context = i915_prandom_u64_state(&prng); 568 1.1 riastrad 569 1.1 riastrad err = i915_syncmap_set(&sync, context, 0); 570 1.1 riastrad if (err) 571 1.1 riastrad goto out; 572 1.1 riastrad 573 1.1 riastrad count++; 574 1.1 riastrad } while (!time_after(jiffies, phase)); 575 1.1 riastrad seqno = 0; 576 1.1 riastrad 577 1.1 riastrad phase = 0; 578 1.1 riastrad do { 579 1.1 riastrad I915_RND_STATE(ctx); 580 1.1 riastrad u32 last_seqno = seqno; 581 1.1 riastrad bool expect; 582 1.1 riastrad 583 1.1 riastrad seqno = prandom_u32_state(&prng); 584 1.1 riastrad expect = seqno_later(last_seqno, seqno); 585 1.1 riastrad 586 1.1 riastrad for (i = 0; i < count; i++) { 587 1.1 riastrad u64 context = i915_prandom_u64_state(&ctx); 588 1.1 riastrad 589 1.1 riastrad if (i915_syncmap_is_later(&sync, context, seqno) != expect) { 590 1.1 riastrad pr_err("context=%llu, last=%u this=%u did not match expectation (%d)\n", 591 1.1 riastrad context, last_seqno, seqno, expect); 592 1.1 riastrad err = -EINVAL; 593 1.1 riastrad goto out; 594 1.1 riastrad } 595 1.1 riastrad 596 1.1 riastrad err = i915_syncmap_set(&sync, context, seqno); 597 1.1 riastrad if (err) 598 1.1 riastrad goto out; 599 1.1 riastrad } 600 1.1 riastrad 601 1.1 riastrad phase++; 602 1.1 riastrad } while (!__igt_timeout(end_time, NULL)); 603 1.1 riastrad pr_debug("Completed %lu passes, each of %lu contexts\n", phase, count); 604 1.1 riastrad out: 605 1.1 riastrad return dump_syncmap(sync, err); 606 1.1 riastrad } 607 1.1 riastrad 608 1.1 riastrad int i915_syncmap_mock_selftests(void) 609 1.1 riastrad { 610 1.1 riastrad static const struct i915_subtest tests[] = { 611 1.1 riastrad SUBTEST(igt_syncmap_init), 612 1.1 riastrad SUBTEST(igt_syncmap_one), 613 1.1 riastrad SUBTEST(igt_syncmap_join_above), 614 1.1 riastrad SUBTEST(igt_syncmap_join_below), 615 1.1 riastrad SUBTEST(igt_syncmap_neighbours), 616 1.1 riastrad SUBTEST(igt_syncmap_compact), 617 1.1 riastrad SUBTEST(igt_syncmap_random), 618 1.1 riastrad }; 619 1.1 riastrad 620 1.1 riastrad return i915_subtests(tests, NULL); 621 1.1 riastrad } 622