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