st-dma-fence-unwrap.c 11 KB

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