diff options
-rw-r--r-- | drivers/dma-buf/fence.c | 98 | ||||
-rw-r--r-- | include/linux/fence.h | 3 |
2 files changed, 100 insertions, 1 deletions
diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c index 50ef8bd8708b..7b05dbe9b296 100644 --- a/drivers/dma-buf/fence.c +++ b/drivers/dma-buf/fence.c | |||
@@ -397,6 +397,104 @@ out: | |||
397 | } | 397 | } |
398 | EXPORT_SYMBOL(fence_default_wait); | 398 | EXPORT_SYMBOL(fence_default_wait); |
399 | 399 | ||
400 | static bool | ||
401 | fence_test_signaled_any(struct fence **fences, uint32_t count) | ||
402 | { | ||
403 | int i; | ||
404 | |||
405 | for (i = 0; i < count; ++i) { | ||
406 | struct fence *fence = fences[i]; | ||
407 | if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) | ||
408 | return true; | ||
409 | } | ||
410 | return false; | ||
411 | } | ||
412 | |||
413 | /** | ||
414 | * fence_wait_any_timeout - sleep until any fence gets signaled | ||
415 | * or until timeout elapses | ||
416 | * @fences: [in] array of fences to wait on | ||
417 | * @count: [in] number of fences to wait on | ||
418 | * @intr: [in] if true, do an interruptible wait | ||
419 | * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT | ||
420 | * | ||
421 | * Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if | ||
422 | * interrupted, 0 if the wait timed out, or the remaining timeout in jiffies | ||
423 | * on success. | ||
424 | * | ||
425 | * Synchronous waits for the first fence in the array to be signaled. The | ||
426 | * caller needs to hold a reference to all fences in the array, otherwise a | ||
427 | * fence might be freed before return, resulting in undefined behavior. | ||
428 | */ | ||
429 | signed long | ||
430 | fence_wait_any_timeout(struct fence **fences, uint32_t count, | ||
431 | bool intr, signed long timeout) | ||
432 | { | ||
433 | struct default_wait_cb *cb; | ||
434 | signed long ret = timeout; | ||
435 | unsigned i; | ||
436 | |||
437 | if (WARN_ON(!fences || !count || timeout < 0)) | ||
438 | return -EINVAL; | ||
439 | |||
440 | if (timeout == 0) { | ||
441 | for (i = 0; i < count; ++i) | ||
442 | if (fence_is_signaled(fences[i])) | ||
443 | return 1; | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | cb = kcalloc(count, sizeof(struct default_wait_cb), GFP_KERNEL); | ||
449 | if (cb == NULL) { | ||
450 | ret = -ENOMEM; | ||
451 | goto err_free_cb; | ||
452 | } | ||
453 | |||
454 | for (i = 0; i < count; ++i) { | ||
455 | struct fence *fence = fences[i]; | ||
456 | |||
457 | if (fence->ops->wait != fence_default_wait) { | ||
458 | ret = -EINVAL; | ||
459 | goto fence_rm_cb; | ||
460 | } | ||
461 | |||
462 | cb[i].task = current; | ||
463 | if (fence_add_callback(fence, &cb[i].base, | ||
464 | fence_default_wait_cb)) { | ||
465 | /* This fence is already signaled */ | ||
466 | goto fence_rm_cb; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | while (ret > 0) { | ||
471 | if (intr) | ||
472 | set_current_state(TASK_INTERRUPTIBLE); | ||
473 | else | ||
474 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
475 | |||
476 | if (fence_test_signaled_any(fences, count)) | ||
477 | break; | ||
478 | |||
479 | ret = schedule_timeout(ret); | ||
480 | |||
481 | if (ret > 0 && intr && signal_pending(current)) | ||
482 | ret = -ERESTARTSYS; | ||
483 | } | ||
484 | |||
485 | __set_current_state(TASK_RUNNING); | ||
486 | |||
487 | fence_rm_cb: | ||
488 | while (i-- > 0) | ||
489 | fence_remove_callback(fences[i], &cb[i].base); | ||
490 | |||
491 | err_free_cb: | ||
492 | kfree(cb); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | EXPORT_SYMBOL(fence_wait_any_timeout); | ||
497 | |||
400 | /** | 498 | /** |
401 | * fence_init - Initialize a custom fence. | 499 | * fence_init - Initialize a custom fence. |
402 | * @fence: [in] the fence to initialize | 500 | * @fence: [in] the fence to initialize |
diff --git a/include/linux/fence.h b/include/linux/fence.h index 39efee130d2b..a4084d6bb851 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h | |||
@@ -305,7 +305,8 @@ static inline struct fence *fence_later(struct fence *f1, struct fence *f2) | |||
305 | } | 305 | } |
306 | 306 | ||
307 | signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout); | 307 | signed long fence_wait_timeout(struct fence *, bool intr, signed long timeout); |
308 | 308 | signed long fence_wait_any_timeout(struct fence **fences, uint32_t count, | |
309 | bool intr, signed long timeout); | ||
309 | 310 | ||
310 | /** | 311 | /** |
311 | * fence_wait - sleep until the fence gets signaled | 312 | * fence_wait - sleep until the fence gets signaled |