summaryrefslogtreecommitdiffstats
path: root/drivers/dma-buf
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2015-10-20 10:34:16 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-10-30 01:16:16 -0400
commita519435a96597d8cd96123246fea4ae5a6c90b02 (patch)
tree0a60a96397354c96d58f5eac2123aa672f0e84d5 /drivers/dma-buf
parentfe537d003f9a97c65848e47b3b9acbb0c5002fd9 (diff)
dma-buf/fence: add fence_wait_any_timeout function v2
Waiting for the first fence in an array of fences to signal. This is useful for device driver specific resource managers and also Vulkan needs something similar. v2: more parameter checks, handling for timeout==0, remove NULL entry support, better callback removal. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/dma-buf')
-rw-r--r--drivers/dma-buf/fence.c98
1 files changed, 98 insertions, 0 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}
398EXPORT_SYMBOL(fence_default_wait); 398EXPORT_SYMBOL(fence_default_wait);
399 399
400static bool
401fence_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 */
429signed long
430fence_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
487fence_rm_cb:
488 while (i-- > 0)
489 fence_remove_callback(fences[i], &cb[i].base);
490
491err_free_cb:
492 kfree(cb);
493
494 return ret;
495}
496EXPORT_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