1 // SPDX-License-Identifier: MIT 2 3 /* 4 * Copyright (C) 2022 Advanced Micro Devices, Inc. 5 */ 6 7 #include <linux/dma-fence.h> 8 #include <linux/dma-fence-array.h> 9 #include <linux/dma-fence-chain.h> 10 #include <linux/dma-fence-unwrap.h> 11 12 #include "selftest.h" 13 14 #define CHAIN_SZ (4 << 10) 15 16 struct mock_fence { 17 struct dma_fence base; 18 spinlock_t lock; 19 }; 20 21 static const char *mock_name(struct dma_fence *f) 22 { 23 return "mock"; 24 } 25 26 static const struct dma_fence_ops mock_ops = { 27 .get_driver_name = mock_name, 28 .get_timeline_name = mock_name, 29 }; 30 31 static struct dma_fence *__mock_fence(u64 context, u64 seqno) 32 { 33 struct mock_fence *f; 34 35 f = kmalloc(sizeof(*f), GFP_KERNEL); 36 if (!f) 37 return NULL; 38 39 spin_lock_init(&f->lock); 40 dma_fence_init(&f->base, &mock_ops, &f->lock, context, seqno); 41 42 return &f->base; 43 } 44 45 static struct dma_fence *mock_fence(void) 46 { 47 return __mock_fence(dma_fence_context_alloc(1), 1); 48 } 49 50 static struct dma_fence *mock_array(unsigned int num_fences, ...) 51 { 52 struct dma_fence_array *array; 53 struct dma_fence **fences; 54 va_list valist; 55 int i; 56 57 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); 58 if (!fences) 59 goto error_put; 60 61 va_start(valist, num_fences); 62 for (i = 0; i < num_fences; ++i) 63 fences[i] = va_arg(valist, typeof(*fences)); 64 va_end(valist); 65 66 array = dma_fence_array_create(num_fences, fences, 67 dma_fence_context_alloc(1), 68 1, false); 69 if (!array) 70 goto error_free; 71 return &array->base; 72 73 error_free: 74 kfree(fences); 75 76 error_put: 77 va_start(valist, num_fences); 78 for (i = 0; i < num_fences; ++i) 79 dma_fence_put(va_arg(valist, typeof(*fences))); 80 va_end(valist); 81 return NULL; 82 } 83 84 static struct dma_fence *mock_chain(struct dma_fence *prev, 85 struct dma_fence *fence) 86 { 87 struct dma_fence_chain *f; 88 89 f = dma_fence_chain_alloc(); 90 if (!f) { 91 dma_fence_put(prev); 92 dma_fence_put(fence); 93 return NULL; 94 } 95 96 dma_fence_chain_init(f, prev, fence, 1); 97 return &f->base; 98 } 99 100 static int sanitycheck(void *arg) 101 { 102 struct dma_fence *f, *chain, *array; 103 int err = 0; 104 105 f = mock_fence(); 106 if (!f) 107 return -ENOMEM; 108 109 dma_fence_enable_sw_signaling(f); 110 111 array = mock_array(1, f); 112 if (!array) 113 return -ENOMEM; 114 115 chain = mock_chain(NULL, array); 116 if (!chain) 117 return -ENOMEM; 118 119 dma_fence_put(chain); 120 return err; 121 } 122 123 static int unwrap_array(void *arg) 124 { 125 struct dma_fence *fence, *f1, *f2, *array; 126 struct dma_fence_unwrap iter; 127 int err = 0; 128 129 f1 = mock_fence(); 130 if (!f1) 131 return -ENOMEM; 132 133 dma_fence_enable_sw_signaling(f1); 134 135 f2 = mock_fence(); 136 if (!f2) { 137 dma_fence_put(f1); 138 return -ENOMEM; 139 } 140 141 dma_fence_enable_sw_signaling(f2); 142 143 array = mock_array(2, f1, f2); 144 if (!array) 145 return -ENOMEM; 146 147 dma_fence_unwrap_for_each(fence, &iter, array) { 148 if (fence == f1) { 149 f1 = NULL; 150 } else if (fence == f2) { 151 f2 = NULL; 152 } else { 153 pr_err("Unexpected fence!\n"); 154 err = -EINVAL; 155 } 156 } 157 158 if (f1 || f2) { 159 pr_err("Not all fences seen!\n"); 160 err = -EINVAL; 161 } 162 163 dma_fence_put(array); 164 return err; 165 } 166 167 static int unwrap_chain(void *arg) 168 { 169 struct dma_fence *fence, *f1, *f2, *chain; 170 struct dma_fence_unwrap iter; 171 int err = 0; 172 173 f1 = mock_fence(); 174 if (!f1) 175 return -ENOMEM; 176 177 dma_fence_enable_sw_signaling(f1); 178 179 f2 = mock_fence(); 180 if (!f2) { 181 dma_fence_put(f1); 182 return -ENOMEM; 183 } 184 185 dma_fence_enable_sw_signaling(f2); 186 187 chain = mock_chain(f1, f2); 188 if (!chain) 189 return -ENOMEM; 190 191 dma_fence_unwrap_for_each(fence, &iter, chain) { 192 if (fence == f1) { 193 f1 = NULL; 194 } else if (fence == f2) { 195 f2 = NULL; 196 } else { 197 pr_err("Unexpected fence!\n"); 198 err = -EINVAL; 199 } 200 } 201 202 if (f1 || f2) { 203 pr_err("Not all fences seen!\n"); 204 err = -EINVAL; 205 } 206 207 dma_fence_put(chain); 208 return err; 209 } 210 211 static int unwrap_chain_array(void *arg) 212 { 213 struct dma_fence *fence, *f1, *f2, *array, *chain; 214 struct dma_fence_unwrap iter; 215 int err = 0; 216 217 f1 = mock_fence(); 218 if (!f1) 219 return -ENOMEM; 220 221 dma_fence_enable_sw_signaling(f1); 222 223 f2 = mock_fence(); 224 if (!f2) { 225 dma_fence_put(f1); 226 return -ENOMEM; 227 } 228 229 dma_fence_enable_sw_signaling(f2); 230 231 array = mock_array(2, f1, f2); 232 if (!array) 233 return -ENOMEM; 234 235 chain = mock_chain(NULL, array); 236 if (!chain) 237 return -ENOMEM; 238 239 dma_fence_unwrap_for_each(fence, &iter, chain) { 240 if (fence == f1) { 241 f1 = NULL; 242 } else if (fence == f2) { 243 f2 = NULL; 244 } else { 245 pr_err("Unexpected fence!\n"); 246 err = -EINVAL; 247 } 248 } 249 250 if (f1 || f2) { 251 pr_err("Not all fences seen!\n"); 252 err = -EINVAL; 253 } 254 255 dma_fence_put(chain); 256 return err; 257 } 258 259 static int unwrap_merge(void *arg) 260 { 261 struct dma_fence *fence, *f1, *f2, *f3; 262 struct dma_fence_unwrap iter; 263 int err = 0; 264 265 f1 = mock_fence(); 266 if (!f1) 267 return -ENOMEM; 268 269 dma_fence_enable_sw_signaling(f1); 270 271 f2 = mock_fence(); 272 if (!f2) { 273 err = -ENOMEM; 274 goto error_put_f1; 275 } 276 277 dma_fence_enable_sw_signaling(f2); 278 279 f3 = dma_fence_unwrap_merge(f1, f2); 280 if (!f3) { 281 err = -ENOMEM; 282 goto error_put_f2; 283 } 284 285 dma_fence_unwrap_for_each(fence, &iter, f3) { 286 if (fence == f1) { 287 dma_fence_put(f1); 288 f1 = NULL; 289 } else if (fence == f2) { 290 dma_fence_put(f2); 291 f2 = NULL; 292 } else { 293 pr_err("Unexpected fence!\n"); 294 err = -EINVAL; 295 } 296 } 297 298 if (f1 || f2) { 299 pr_err("Not all fences seen!\n"); 300 err = -EINVAL; 301 } 302 303 dma_fence_put(f3); 304 error_put_f2: 305 dma_fence_put(f2); 306 error_put_f1: 307 dma_fence_put(f1); 308 return err; 309 } 310 311 static int unwrap_merge_duplicate(void *arg) 312 { 313 struct dma_fence *fence, *f1, *f2; 314 struct dma_fence_unwrap iter; 315 int err = 0; 316 317 f1 = mock_fence(); 318 if (!f1) 319 return -ENOMEM; 320 321 dma_fence_enable_sw_signaling(f1); 322 323 f2 = dma_fence_unwrap_merge(f1, f1); 324 if (!f2) { 325 err = -ENOMEM; 326 goto error_put_f1; 327 } 328 329 dma_fence_unwrap_for_each(fence, &iter, f2) { 330 if (fence == f1) { 331 dma_fence_put(f1); 332 f1 = NULL; 333 } else { 334 pr_err("Unexpected fence!\n"); 335 err = -EINVAL; 336 } 337 } 338 339 if (f1) { 340 pr_err("Not all fences seen!\n"); 341 err = -EINVAL; 342 } 343 344 dma_fence_put(f2); 345 error_put_f1: 346 dma_fence_put(f1); 347 return err; 348 } 349 350 static int unwrap_merge_seqno(void *arg) 351 { 352 struct dma_fence *fence, *f1, *f2, *f3, *f4; 353 struct dma_fence_unwrap iter; 354 int err = 0; 355 u64 ctx[2]; 356 357 ctx[0] = dma_fence_context_alloc(1); 358 ctx[1] = dma_fence_context_alloc(1); 359 360 f1 = __mock_fence(ctx[1], 1); 361 if (!f1) 362 return -ENOMEM; 363 364 dma_fence_enable_sw_signaling(f1); 365 366 f2 = __mock_fence(ctx[1], 2); 367 if (!f2) { 368 err = -ENOMEM; 369 goto error_put_f1; 370 } 371 372 dma_fence_enable_sw_signaling(f2); 373 374 f3 = __mock_fence(ctx[0], 1); 375 if (!f3) { 376 err = -ENOMEM; 377 goto error_put_f2; 378 } 379 380 dma_fence_enable_sw_signaling(f3); 381 382 f4 = dma_fence_unwrap_merge(f1, f2, f3); 383 if (!f4) { 384 err = -ENOMEM; 385 goto error_put_f3; 386 } 387 388 dma_fence_unwrap_for_each(fence, &iter, f4) { 389 if (fence == f3 && f2) { 390 dma_fence_put(f3); 391 f3 = NULL; 392 } else if (fence == f2 && !f3) { 393 dma_fence_put(f2); 394 f2 = NULL; 395 } else { 396 pr_err("Unexpected fence!\n"); 397 err = -EINVAL; 398 } 399 } 400 401 if (f2 || f3) { 402 pr_err("Not all fences seen!\n"); 403 err = -EINVAL; 404 } 405 406 dma_fence_put(f4); 407 error_put_f3: 408 dma_fence_put(f3); 409 error_put_f2: 410 dma_fence_put(f2); 411 error_put_f1: 412 dma_fence_put(f1); 413 return err; 414 } 415 416 static int unwrap_merge_order(void *arg) 417 { 418 struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2; 419 struct dma_fence_unwrap iter; 420 int err = 0; 421 422 f1 = mock_fence(); 423 if (!f1) 424 return -ENOMEM; 425 426 dma_fence_enable_sw_signaling(f1); 427 428 f2 = mock_fence(); 429 if (!f2) { 430 dma_fence_put(f1); 431 return -ENOMEM; 432 } 433 434 dma_fence_enable_sw_signaling(f2); 435 436 a1 = mock_array(2, f1, f2); 437 if (!a1) 438 return -ENOMEM; 439 440 c1 = mock_chain(NULL, dma_fence_get(f1)); 441 if (!c1) 442 goto error_put_a1; 443 444 c2 = mock_chain(c1, dma_fence_get(f2)); 445 if (!c2) 446 goto error_put_a1; 447 448 /* 449 * The fences in the chain are the same as in a1 but in oposite order, 450 * the dma_fence_merge() function should be able to handle that. 451 */ 452 a2 = dma_fence_unwrap_merge(a1, c2); 453 454 dma_fence_unwrap_for_each(fence, &iter, a2) { 455 if (fence == f1) { 456 f1 = NULL; 457 if (!f2) 458 pr_err("Unexpected order!\n"); 459 } else if (fence == f2) { 460 f2 = NULL; 461 if (f1) 462 pr_err("Unexpected order!\n"); 463 } else { 464 pr_err("Unexpected fence!\n"); 465 err = -EINVAL; 466 } 467 } 468 469 if (f1 || f2) { 470 pr_err("Not all fences seen!\n"); 471 err = -EINVAL; 472 } 473 474 dma_fence_put(a2); 475 return err; 476 477 error_put_a1: 478 dma_fence_put(a1); 479 return -ENOMEM; 480 } 481 482 static int unwrap_merge_complex(void *arg) 483 { 484 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5; 485 struct dma_fence_unwrap iter; 486 int err = -ENOMEM; 487 488 f1 = mock_fence(); 489 if (!f1) 490 return -ENOMEM; 491 492 dma_fence_enable_sw_signaling(f1); 493 494 f2 = mock_fence(); 495 if (!f2) 496 goto error_put_f1; 497 498 dma_fence_enable_sw_signaling(f2); 499 500 f3 = dma_fence_unwrap_merge(f1, f2); 501 if (!f3) 502 goto error_put_f2; 503 504 /* The resulting array has the fences in reverse */ 505 f4 = mock_array(2, dma_fence_get(f2), dma_fence_get(f1)); 506 if (!f4) 507 goto error_put_f3; 508 509 /* Signaled fences should be filtered, the two arrays merged. */ 510 f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub()); 511 if (!f5) 512 goto error_put_f4; 513 514 err = 0; 515 dma_fence_unwrap_for_each(fence, &iter, f5) { 516 if (fence == f1) { 517 dma_fence_put(f1); 518 f1 = NULL; 519 } else if (fence == f2) { 520 dma_fence_put(f2); 521 f2 = NULL; 522 } else { 523 pr_err("Unexpected fence!\n"); 524 err = -EINVAL; 525 } 526 } 527 528 if (f1 || f2) { 529 pr_err("Not all fences seen!\n"); 530 err = -EINVAL; 531 } 532 533 dma_fence_put(f5); 534 error_put_f4: 535 dma_fence_put(f4); 536 error_put_f3: 537 dma_fence_put(f3); 538 error_put_f2: 539 dma_fence_put(f2); 540 error_put_f1: 541 dma_fence_put(f1); 542 return err; 543 } 544 545 static int unwrap_merge_complex_seqno(void *arg) 546 { 547 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5, *f6, *f7; 548 struct dma_fence_unwrap iter; 549 int err = -ENOMEM; 550 u64 ctx[2]; 551 552 ctx[0] = dma_fence_context_alloc(1); 553 ctx[1] = dma_fence_context_alloc(1); 554 555 f1 = __mock_fence(ctx[0], 2); 556 if (!f1) 557 return -ENOMEM; 558 559 dma_fence_enable_sw_signaling(f1); 560 561 f2 = __mock_fence(ctx[1], 1); 562 if (!f2) 563 goto error_put_f1; 564 565 dma_fence_enable_sw_signaling(f2); 566 567 f3 = __mock_fence(ctx[0], 1); 568 if (!f3) 569 goto error_put_f2; 570 571 dma_fence_enable_sw_signaling(f3); 572 573 f4 = __mock_fence(ctx[1], 2); 574 if (!f4) 575 goto error_put_f3; 576 577 dma_fence_enable_sw_signaling(f4); 578 579 f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2)); 580 if (!f5) 581 goto error_put_f4; 582 583 f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4)); 584 if (!f6) 585 goto error_put_f5; 586 587 f7 = dma_fence_unwrap_merge(f5, f6); 588 if (!f7) 589 goto error_put_f6; 590 591 err = 0; 592 dma_fence_unwrap_for_each(fence, &iter, f7) { 593 if (fence == f1 && f4) { 594 dma_fence_put(f1); 595 f1 = NULL; 596 } else if (fence == f4 && !f1) { 597 dma_fence_put(f4); 598 f4 = NULL; 599 } else { 600 pr_err("Unexpected fence!\n"); 601 err = -EINVAL; 602 } 603 } 604 605 if (f1 || f4) { 606 pr_err("Not all fences seen!\n"); 607 err = -EINVAL; 608 } 609 610 dma_fence_put(f7); 611 error_put_f6: 612 dma_fence_put(f6); 613 error_put_f5: 614 dma_fence_put(f5); 615 error_put_f4: 616 dma_fence_put(f4); 617 error_put_f3: 618 dma_fence_put(f3); 619 error_put_f2: 620 dma_fence_put(f2); 621 error_put_f1: 622 dma_fence_put(f1); 623 return err; 624 } 625 626 int dma_fence_unwrap(void) 627 { 628 static const struct subtest tests[] = { 629 SUBTEST(sanitycheck), 630 SUBTEST(unwrap_array), 631 SUBTEST(unwrap_chain), 632 SUBTEST(unwrap_chain_array), 633 SUBTEST(unwrap_merge), 634 SUBTEST(unwrap_merge_duplicate), 635 SUBTEST(unwrap_merge_seqno), 636 SUBTEST(unwrap_merge_order), 637 SUBTEST(unwrap_merge_complex), 638 SUBTEST(unwrap_merge_complex_seqno), 639 }; 640 641 return subtests(tests, NULL); 642 } 643