1 | /* |
2 | * Copyright © 2017 Intel Corporation |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
21 | * IN THE SOFTWARE. |
22 | * |
23 | */ |
24 | |
25 | #include <linux/completion.h> |
26 | #include <linux/delay.h> |
27 | #include <linux/prime_numbers.h> |
28 | |
29 | #include "../i915_selftest.h" |
30 | |
31 | static int |
32 | fence_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) |
33 | { |
34 | switch (state) { |
35 | case FENCE_COMPLETE: |
36 | break; |
37 | |
38 | case FENCE_FREE: |
39 | /* Leave the fence for the caller to free it after testing */ |
40 | break; |
41 | } |
42 | |
43 | return NOTIFY_DONE; |
44 | } |
45 | |
46 | static struct i915_sw_fence *alloc_fence(void) |
47 | { |
48 | struct i915_sw_fence *fence; |
49 | |
50 | fence = kmalloc(size: sizeof(*fence), GFP_KERNEL); |
51 | if (!fence) |
52 | return NULL; |
53 | |
54 | i915_sw_fence_init(fence, fence_notify); |
55 | return fence; |
56 | } |
57 | |
58 | static void free_fence(struct i915_sw_fence *fence) |
59 | { |
60 | i915_sw_fence_fini(fence); |
61 | kfree(objp: fence); |
62 | } |
63 | |
64 | static int __test_self(struct i915_sw_fence *fence) |
65 | { |
66 | if (i915_sw_fence_done(fence)) |
67 | return -EINVAL; |
68 | |
69 | i915_sw_fence_commit(fence); |
70 | if (!i915_sw_fence_done(fence)) |
71 | return -EINVAL; |
72 | |
73 | i915_sw_fence_wait(fence); |
74 | if (!i915_sw_fence_done(fence)) |
75 | return -EINVAL; |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int test_self(void *arg) |
81 | { |
82 | struct i915_sw_fence *fence; |
83 | int ret; |
84 | |
85 | /* Test i915_sw_fence signaling and completion testing */ |
86 | fence = alloc_fence(); |
87 | if (!fence) |
88 | return -ENOMEM; |
89 | |
90 | ret = __test_self(fence); |
91 | |
92 | free_fence(fence); |
93 | return ret; |
94 | } |
95 | |
96 | static int test_dag(void *arg) |
97 | { |
98 | struct i915_sw_fence *A, *B, *C; |
99 | int ret = -EINVAL; |
100 | |
101 | /* Test detection of cycles within the i915_sw_fence graphs */ |
102 | if (!IS_ENABLED(CONFIG_DRM_I915_SW_FENCE_CHECK_DAG)) |
103 | return 0; |
104 | |
105 | A = alloc_fence(); |
106 | if (!A) |
107 | return -ENOMEM; |
108 | |
109 | if (i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: A, GFP_KERNEL) != -EINVAL) { |
110 | pr_err("recursive cycle not detected (AA)\n" ); |
111 | goto err_A; |
112 | } |
113 | |
114 | B = alloc_fence(); |
115 | if (!B) { |
116 | ret = -ENOMEM; |
117 | goto err_A; |
118 | } |
119 | |
120 | i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: B, GFP_KERNEL); |
121 | if (i915_sw_fence_await_sw_fence_gfp(fence: B, signaler: A, GFP_KERNEL) != -EINVAL) { |
122 | pr_err("single depth cycle not detected (BAB)\n" ); |
123 | goto err_B; |
124 | } |
125 | |
126 | C = alloc_fence(); |
127 | if (!C) { |
128 | ret = -ENOMEM; |
129 | goto err_B; |
130 | } |
131 | |
132 | if (i915_sw_fence_await_sw_fence_gfp(fence: B, signaler: C, GFP_KERNEL) == -EINVAL) { |
133 | pr_err("invalid cycle detected\n" ); |
134 | goto err_C; |
135 | } |
136 | if (i915_sw_fence_await_sw_fence_gfp(fence: C, signaler: B, GFP_KERNEL) != -EINVAL) { |
137 | pr_err("single depth cycle not detected (CBC)\n" ); |
138 | goto err_C; |
139 | } |
140 | if (i915_sw_fence_await_sw_fence_gfp(fence: C, signaler: A, GFP_KERNEL) != -EINVAL) { |
141 | pr_err("cycle not detected (BA, CB, AC)\n" ); |
142 | goto err_C; |
143 | } |
144 | if (i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: C, GFP_KERNEL) == -EINVAL) { |
145 | pr_err("invalid cycle detected\n" ); |
146 | goto err_C; |
147 | } |
148 | |
149 | i915_sw_fence_commit(fence: A); |
150 | i915_sw_fence_commit(fence: B); |
151 | i915_sw_fence_commit(fence: C); |
152 | |
153 | ret = 0; |
154 | if (!i915_sw_fence_done(fence: C)) { |
155 | pr_err("fence C not done\n" ); |
156 | ret = -EINVAL; |
157 | } |
158 | if (!i915_sw_fence_done(fence: B)) { |
159 | pr_err("fence B not done\n" ); |
160 | ret = -EINVAL; |
161 | } |
162 | if (!i915_sw_fence_done(fence: A)) { |
163 | pr_err("fence A not done\n" ); |
164 | ret = -EINVAL; |
165 | } |
166 | err_C: |
167 | free_fence(fence: C); |
168 | err_B: |
169 | free_fence(fence: B); |
170 | err_A: |
171 | free_fence(fence: A); |
172 | return ret; |
173 | } |
174 | |
175 | static int test_AB(void *arg) |
176 | { |
177 | struct i915_sw_fence *A, *B; |
178 | int ret; |
179 | |
180 | /* Test i915_sw_fence (A) waiting on an event source (B) */ |
181 | A = alloc_fence(); |
182 | if (!A) |
183 | return -ENOMEM; |
184 | B = alloc_fence(); |
185 | if (!B) { |
186 | ret = -ENOMEM; |
187 | goto err_A; |
188 | } |
189 | |
190 | ret = i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: B, GFP_KERNEL); |
191 | if (ret < 0) |
192 | goto err_B; |
193 | if (ret == 0) { |
194 | pr_err("Incorrectly reported fence A was complete before await\n" ); |
195 | ret = -EINVAL; |
196 | goto err_B; |
197 | } |
198 | |
199 | ret = -EINVAL; |
200 | i915_sw_fence_commit(fence: A); |
201 | if (i915_sw_fence_done(fence: A)) |
202 | goto err_B; |
203 | |
204 | i915_sw_fence_commit(fence: B); |
205 | if (!i915_sw_fence_done(fence: B)) { |
206 | pr_err("Fence B is not done\n" ); |
207 | goto err_B; |
208 | } |
209 | |
210 | if (!i915_sw_fence_done(fence: A)) { |
211 | pr_err("Fence A is not done\n" ); |
212 | goto err_B; |
213 | } |
214 | |
215 | ret = 0; |
216 | err_B: |
217 | free_fence(fence: B); |
218 | err_A: |
219 | free_fence(fence: A); |
220 | return ret; |
221 | } |
222 | |
223 | static int test_ABC(void *arg) |
224 | { |
225 | struct i915_sw_fence *A, *B, *C; |
226 | int ret; |
227 | |
228 | /* Test a chain of fences, A waits on B who waits on C */ |
229 | A = alloc_fence(); |
230 | if (!A) |
231 | return -ENOMEM; |
232 | |
233 | B = alloc_fence(); |
234 | if (!B) { |
235 | ret = -ENOMEM; |
236 | goto err_A; |
237 | } |
238 | |
239 | C = alloc_fence(); |
240 | if (!C) { |
241 | ret = -ENOMEM; |
242 | goto err_B; |
243 | } |
244 | |
245 | ret = i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: B, GFP_KERNEL); |
246 | if (ret < 0) |
247 | goto err_C; |
248 | if (ret == 0) { |
249 | pr_err("Incorrectly reported fence B was complete before await\n" ); |
250 | goto err_C; |
251 | } |
252 | |
253 | ret = i915_sw_fence_await_sw_fence_gfp(fence: B, signaler: C, GFP_KERNEL); |
254 | if (ret < 0) |
255 | goto err_C; |
256 | if (ret == 0) { |
257 | pr_err("Incorrectly reported fence C was complete before await\n" ); |
258 | goto err_C; |
259 | } |
260 | |
261 | ret = -EINVAL; |
262 | i915_sw_fence_commit(fence: A); |
263 | if (i915_sw_fence_done(fence: A)) { |
264 | pr_err("Fence A completed early\n" ); |
265 | goto err_C; |
266 | } |
267 | |
268 | i915_sw_fence_commit(fence: B); |
269 | if (i915_sw_fence_done(fence: B)) { |
270 | pr_err("Fence B completed early\n" ); |
271 | goto err_C; |
272 | } |
273 | |
274 | if (i915_sw_fence_done(fence: A)) { |
275 | pr_err("Fence A completed early (after signaling B)\n" ); |
276 | goto err_C; |
277 | } |
278 | |
279 | i915_sw_fence_commit(fence: C); |
280 | |
281 | ret = 0; |
282 | if (!i915_sw_fence_done(fence: C)) { |
283 | pr_err("Fence C not done\n" ); |
284 | ret = -EINVAL; |
285 | } |
286 | if (!i915_sw_fence_done(fence: B)) { |
287 | pr_err("Fence B not done\n" ); |
288 | ret = -EINVAL; |
289 | } |
290 | if (!i915_sw_fence_done(fence: A)) { |
291 | pr_err("Fence A not done\n" ); |
292 | ret = -EINVAL; |
293 | } |
294 | err_C: |
295 | free_fence(fence: C); |
296 | err_B: |
297 | free_fence(fence: B); |
298 | err_A: |
299 | free_fence(fence: A); |
300 | return ret; |
301 | } |
302 | |
303 | static int test_AB_C(void *arg) |
304 | { |
305 | struct i915_sw_fence *A, *B, *C; |
306 | int ret = -EINVAL; |
307 | |
308 | /* Test multiple fences (AB) waiting on a single event (C) */ |
309 | A = alloc_fence(); |
310 | if (!A) |
311 | return -ENOMEM; |
312 | |
313 | B = alloc_fence(); |
314 | if (!B) { |
315 | ret = -ENOMEM; |
316 | goto err_A; |
317 | } |
318 | |
319 | C = alloc_fence(); |
320 | if (!C) { |
321 | ret = -ENOMEM; |
322 | goto err_B; |
323 | } |
324 | |
325 | ret = i915_sw_fence_await_sw_fence_gfp(fence: A, signaler: C, GFP_KERNEL); |
326 | if (ret < 0) |
327 | goto err_C; |
328 | if (ret == 0) { |
329 | ret = -EINVAL; |
330 | goto err_C; |
331 | } |
332 | |
333 | ret = i915_sw_fence_await_sw_fence_gfp(fence: B, signaler: C, GFP_KERNEL); |
334 | if (ret < 0) |
335 | goto err_C; |
336 | if (ret == 0) { |
337 | ret = -EINVAL; |
338 | goto err_C; |
339 | } |
340 | |
341 | i915_sw_fence_commit(fence: A); |
342 | i915_sw_fence_commit(fence: B); |
343 | |
344 | ret = 0; |
345 | if (i915_sw_fence_done(fence: A)) { |
346 | pr_err("Fence A completed early\n" ); |
347 | ret = -EINVAL; |
348 | } |
349 | |
350 | if (i915_sw_fence_done(fence: B)) { |
351 | pr_err("Fence B completed early\n" ); |
352 | ret = -EINVAL; |
353 | } |
354 | |
355 | i915_sw_fence_commit(fence: C); |
356 | if (!i915_sw_fence_done(fence: C)) { |
357 | pr_err("Fence C not done\n" ); |
358 | ret = -EINVAL; |
359 | } |
360 | |
361 | if (!i915_sw_fence_done(fence: B)) { |
362 | pr_err("Fence B not done\n" ); |
363 | ret = -EINVAL; |
364 | } |
365 | |
366 | if (!i915_sw_fence_done(fence: A)) { |
367 | pr_err("Fence A not done\n" ); |
368 | ret = -EINVAL; |
369 | } |
370 | |
371 | err_C: |
372 | free_fence(fence: C); |
373 | err_B: |
374 | free_fence(fence: B); |
375 | err_A: |
376 | free_fence(fence: A); |
377 | return ret; |
378 | } |
379 | |
380 | static int test_C_AB(void *arg) |
381 | { |
382 | struct i915_sw_fence *A, *B, *C; |
383 | int ret; |
384 | |
385 | /* Test multiple event sources (A,B) for a single fence (C) */ |
386 | A = alloc_fence(); |
387 | if (!A) |
388 | return -ENOMEM; |
389 | |
390 | B = alloc_fence(); |
391 | if (!B) { |
392 | ret = -ENOMEM; |
393 | goto err_A; |
394 | } |
395 | |
396 | C = alloc_fence(); |
397 | if (!C) { |
398 | ret = -ENOMEM; |
399 | goto err_B; |
400 | } |
401 | |
402 | ret = i915_sw_fence_await_sw_fence_gfp(fence: C, signaler: A, GFP_KERNEL); |
403 | if (ret < 0) |
404 | goto err_C; |
405 | if (ret == 0) { |
406 | ret = -EINVAL; |
407 | goto err_C; |
408 | } |
409 | |
410 | ret = i915_sw_fence_await_sw_fence_gfp(fence: C, signaler: B, GFP_KERNEL); |
411 | if (ret < 0) |
412 | goto err_C; |
413 | if (ret == 0) { |
414 | ret = -EINVAL; |
415 | goto err_C; |
416 | } |
417 | |
418 | ret = 0; |
419 | i915_sw_fence_commit(fence: C); |
420 | if (i915_sw_fence_done(fence: C)) |
421 | ret = -EINVAL; |
422 | |
423 | i915_sw_fence_commit(fence: A); |
424 | i915_sw_fence_commit(fence: B); |
425 | |
426 | if (!i915_sw_fence_done(fence: A)) { |
427 | pr_err("Fence A not done\n" ); |
428 | ret = -EINVAL; |
429 | } |
430 | |
431 | if (!i915_sw_fence_done(fence: B)) { |
432 | pr_err("Fence B not done\n" ); |
433 | ret = -EINVAL; |
434 | } |
435 | |
436 | if (!i915_sw_fence_done(fence: C)) { |
437 | pr_err("Fence C not done\n" ); |
438 | ret = -EINVAL; |
439 | } |
440 | |
441 | err_C: |
442 | free_fence(fence: C); |
443 | err_B: |
444 | free_fence(fence: B); |
445 | err_A: |
446 | free_fence(fence: A); |
447 | return ret; |
448 | } |
449 | |
450 | static int test_chain(void *arg) |
451 | { |
452 | int nfences = 4096; |
453 | struct i915_sw_fence **fences; |
454 | int ret, i; |
455 | |
456 | /* Test a long chain of fences */ |
457 | fences = kmalloc_array(n: nfences, size: sizeof(*fences), GFP_KERNEL); |
458 | if (!fences) |
459 | return -ENOMEM; |
460 | |
461 | for (i = 0; i < nfences; i++) { |
462 | fences[i] = alloc_fence(); |
463 | if (!fences[i]) { |
464 | nfences = i; |
465 | ret = -ENOMEM; |
466 | goto err; |
467 | } |
468 | |
469 | if (i > 0) { |
470 | ret = i915_sw_fence_await_sw_fence_gfp(fence: fences[i], |
471 | signaler: fences[i - 1], |
472 | GFP_KERNEL); |
473 | if (ret < 0) { |
474 | nfences = i + 1; |
475 | goto err; |
476 | } |
477 | |
478 | i915_sw_fence_commit(fence: fences[i]); |
479 | } |
480 | } |
481 | |
482 | ret = 0; |
483 | for (i = nfences; --i; ) { |
484 | if (i915_sw_fence_done(fence: fences[i])) { |
485 | if (ret == 0) |
486 | pr_err("Fence[%d] completed early\n" , i); |
487 | ret = -EINVAL; |
488 | } |
489 | } |
490 | i915_sw_fence_commit(fence: fences[0]); |
491 | for (i = 0; ret == 0 && i < nfences; i++) { |
492 | if (!i915_sw_fence_done(fence: fences[i])) { |
493 | pr_err("Fence[%d] is not done\n" , i); |
494 | ret = -EINVAL; |
495 | } |
496 | } |
497 | |
498 | err: |
499 | for (i = 0; i < nfences; i++) |
500 | free_fence(fence: fences[i]); |
501 | kfree(objp: fences); |
502 | return ret; |
503 | } |
504 | |
505 | struct task_ipc { |
506 | struct work_struct work; |
507 | struct completion started; |
508 | struct i915_sw_fence *in, *out; |
509 | int value; |
510 | }; |
511 | |
512 | static void task_ipc(struct work_struct *work) |
513 | { |
514 | struct task_ipc *ipc = container_of(work, typeof(*ipc), work); |
515 | |
516 | complete(&ipc->started); |
517 | |
518 | i915_sw_fence_wait(fence: ipc->in); |
519 | smp_store_mb(ipc->value, 1); |
520 | i915_sw_fence_commit(fence: ipc->out); |
521 | } |
522 | |
523 | static int test_ipc(void *arg) |
524 | { |
525 | struct task_ipc ipc; |
526 | struct workqueue_struct *wq; |
527 | int ret = 0; |
528 | |
529 | wq = alloc_workqueue(fmt: "i1915-selftest" , flags: 0, max_active: 0); |
530 | if (wq == NULL) |
531 | return -ENOMEM; |
532 | |
533 | /* Test use of i915_sw_fence as an interprocess signaling mechanism */ |
534 | ipc.in = alloc_fence(); |
535 | if (!ipc.in) { |
536 | ret = -ENOMEM; |
537 | goto err_work; |
538 | } |
539 | ipc.out = alloc_fence(); |
540 | if (!ipc.out) { |
541 | ret = -ENOMEM; |
542 | goto err_in; |
543 | } |
544 | |
545 | /* use a completion to avoid chicken-and-egg testing */ |
546 | init_completion(x: &ipc.started); |
547 | |
548 | ipc.value = 0; |
549 | INIT_WORK_ONSTACK(&ipc.work, task_ipc); |
550 | queue_work(wq, work: &ipc.work); |
551 | |
552 | wait_for_completion(&ipc.started); |
553 | |
554 | usleep_range(min: 1000, max: 2000); |
555 | if (READ_ONCE(ipc.value)) { |
556 | pr_err("worker updated value before i915_sw_fence was signaled\n" ); |
557 | ret = -EINVAL; |
558 | } |
559 | |
560 | i915_sw_fence_commit(fence: ipc.in); |
561 | i915_sw_fence_wait(fence: ipc.out); |
562 | |
563 | if (!READ_ONCE(ipc.value)) { |
564 | pr_err("worker signaled i915_sw_fence before value was posted\n" ); |
565 | ret = -EINVAL; |
566 | } |
567 | |
568 | flush_work(work: &ipc.work); |
569 | destroy_work_on_stack(work: &ipc.work); |
570 | free_fence(fence: ipc.out); |
571 | err_in: |
572 | free_fence(fence: ipc.in); |
573 | err_work: |
574 | destroy_workqueue(wq); |
575 | |
576 | return ret; |
577 | } |
578 | |
579 | static int test_timer(void *arg) |
580 | { |
581 | unsigned long target, delay; |
582 | struct timed_fence tf; |
583 | |
584 | preempt_disable(); |
585 | timed_fence_init(tf: &tf, expires: target = jiffies); |
586 | if (!i915_sw_fence_done(fence: &tf.fence)) { |
587 | pr_err("Fence with immediate expiration not signaled\n" ); |
588 | goto err; |
589 | } |
590 | preempt_enable(); |
591 | timed_fence_fini(tf: &tf); |
592 | |
593 | for_each_prime_number(delay, i915_selftest.timeout_jiffies/2) { |
594 | preempt_disable(); |
595 | timed_fence_init(tf: &tf, expires: target = jiffies + delay); |
596 | if (i915_sw_fence_done(fence: &tf.fence)) { |
597 | pr_err("Fence with future expiration (%lu jiffies) already signaled\n" , delay); |
598 | goto err; |
599 | } |
600 | preempt_enable(); |
601 | |
602 | i915_sw_fence_wait(fence: &tf.fence); |
603 | |
604 | preempt_disable(); |
605 | if (!i915_sw_fence_done(fence: &tf.fence)) { |
606 | pr_err("Fence not signaled after wait\n" ); |
607 | goto err; |
608 | } |
609 | if (time_before(jiffies, target)) { |
610 | pr_err("Fence signaled too early, target=%lu, now=%lu\n" , |
611 | target, jiffies); |
612 | goto err; |
613 | } |
614 | preempt_enable(); |
615 | timed_fence_fini(tf: &tf); |
616 | } |
617 | |
618 | return 0; |
619 | |
620 | err: |
621 | preempt_enable(); |
622 | timed_fence_fini(tf: &tf); |
623 | return -EINVAL; |
624 | } |
625 | |
626 | static const char *mock_name(struct dma_fence *fence) |
627 | { |
628 | return "mock" ; |
629 | } |
630 | |
631 | static const struct dma_fence_ops mock_fence_ops = { |
632 | .get_driver_name = mock_name, |
633 | .get_timeline_name = mock_name, |
634 | }; |
635 | |
636 | static DEFINE_SPINLOCK(mock_fence_lock); |
637 | |
638 | static struct dma_fence *alloc_dma_fence(void) |
639 | { |
640 | struct dma_fence *dma; |
641 | |
642 | dma = kmalloc(size: sizeof(*dma), GFP_KERNEL); |
643 | if (dma) |
644 | dma_fence_init(fence: dma, ops: &mock_fence_ops, lock: &mock_fence_lock, context: 0, seqno: 0); |
645 | |
646 | return dma; |
647 | } |
648 | |
649 | static struct i915_sw_fence * |
650 | wrap_dma_fence(struct dma_fence *dma, unsigned long delay) |
651 | { |
652 | struct i915_sw_fence *fence; |
653 | int err; |
654 | |
655 | fence = alloc_fence(); |
656 | if (!fence) |
657 | return ERR_PTR(error: -ENOMEM); |
658 | |
659 | err = i915_sw_fence_await_dma_fence(fence, dma, timeout: delay, GFP_NOWAIT); |
660 | i915_sw_fence_commit(fence); |
661 | if (err < 0) { |
662 | free_fence(fence); |
663 | return ERR_PTR(error: err); |
664 | } |
665 | |
666 | return fence; |
667 | } |
668 | |
669 | static int test_dma_fence(void *arg) |
670 | { |
671 | struct i915_sw_fence *timeout = NULL, *not = NULL; |
672 | unsigned long delay = i915_selftest.timeout_jiffies; |
673 | unsigned long end, sleep; |
674 | struct dma_fence *dma; |
675 | int err; |
676 | |
677 | dma = alloc_dma_fence(); |
678 | if (!dma) |
679 | return -ENOMEM; |
680 | |
681 | timeout = wrap_dma_fence(dma, delay); |
682 | if (IS_ERR(ptr: timeout)) { |
683 | err = PTR_ERR(ptr: timeout); |
684 | goto err; |
685 | } |
686 | |
687 | not = wrap_dma_fence(dma, delay: 0); |
688 | if (IS_ERR(ptr: not)) { |
689 | err = PTR_ERR(ptr: not); |
690 | goto err; |
691 | } |
692 | |
693 | err = -EINVAL; |
694 | if (i915_sw_fence_done(fence: timeout) || i915_sw_fence_done(fence: not)) { |
695 | pr_err("Fences immediately signaled\n" ); |
696 | goto err; |
697 | } |
698 | |
699 | /* We round the timeout for the fence up to the next second */ |
700 | end = round_jiffies_up(j: jiffies + delay); |
701 | |
702 | sleep = jiffies_to_usecs(j: delay) / 3; |
703 | usleep_range(min: sleep, max: 2 * sleep); |
704 | if (time_after(jiffies, end)) { |
705 | pr_debug("Slept too long, delay=%lu, (target=%lu, now=%lu) skipping\n" , |
706 | delay, end, jiffies); |
707 | goto skip; |
708 | } |
709 | |
710 | if (i915_sw_fence_done(fence: timeout) || i915_sw_fence_done(fence: not)) { |
711 | pr_err("Fences signaled too early\n" ); |
712 | goto err; |
713 | } |
714 | |
715 | if (!wait_event_timeout(timeout->wait, |
716 | i915_sw_fence_done(timeout), |
717 | 2 * (end - jiffies) + 1)) { |
718 | pr_err("Timeout fence unsignaled!\n" ); |
719 | goto err; |
720 | } |
721 | |
722 | if (i915_sw_fence_done(fence: not)) { |
723 | pr_err("No timeout fence signaled!\n" ); |
724 | goto err; |
725 | } |
726 | |
727 | skip: |
728 | dma_fence_signal(fence: dma); |
729 | |
730 | if (!i915_sw_fence_done(fence: timeout) || !i915_sw_fence_done(fence: not)) { |
731 | pr_err("Fences unsignaled\n" ); |
732 | goto err; |
733 | } |
734 | |
735 | free_fence(fence: not); |
736 | free_fence(fence: timeout); |
737 | dma_fence_put(fence: dma); |
738 | |
739 | return 0; |
740 | |
741 | err: |
742 | dma_fence_signal(fence: dma); |
743 | if (!IS_ERR_OR_NULL(ptr: timeout)) |
744 | free_fence(fence: timeout); |
745 | if (!IS_ERR_OR_NULL(ptr: not)) |
746 | free_fence(fence: not); |
747 | dma_fence_put(fence: dma); |
748 | return err; |
749 | } |
750 | |
751 | int i915_sw_fence_mock_selftests(void) |
752 | { |
753 | static const struct i915_subtest tests[] = { |
754 | SUBTEST(test_self), |
755 | SUBTEST(test_dag), |
756 | SUBTEST(test_AB), |
757 | SUBTEST(test_ABC), |
758 | SUBTEST(test_AB_C), |
759 | SUBTEST(test_C_AB), |
760 | SUBTEST(test_chain), |
761 | SUBTEST(test_ipc), |
762 | SUBTEST(test_timer), |
763 | SUBTEST(test_dma_fence), |
764 | }; |
765 | |
766 | return i915_subtests(tests, NULL); |
767 | } |
768 | |