summaryrefslogtreecommitdiffstats
path: root/drivers/dma-buf/fence.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-10-25 14:00:45 +0200
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-10-25 14:40:39 +0200
commitf54d1867005c3323f5d8ad83eed823e84226c429 (patch)
tree026c3f57bc546d3a0205389d0f8e0d02ce8a76ac /drivers/dma-buf/fence.c
parentMerge remote-tracking branch 'airlied/drm-next' into topic/drm-misc (diff)
downloadlinux-f54d1867005c3323f5d8ad83eed823e84226c429.tar.xz
linux-f54d1867005c3323f5d8ad83eed823e84226c429.zip
dma-buf: Rename struct fence to dma_fence
I plan to usurp the short name of struct fence for a core kernel struct, and so I need to rename the specialised fence/timeline for DMA operations to make room. A consensus was reached in https://lists.freedesktop.org/archives/dri-devel/2016-July/113083.html that making clear this fence applies to DMA operations was a good thing. Since then the patch has grown a bit as usage increases, so hopefully it remains a good thing! (v2...: rebase, rerun spatch) v3: Compile on msm, spotted a manual fixup that I broke. v4: Try again for msm, sorry Daniel coccinelle script: @@ @@ - struct fence + struct dma_fence @@ @@ - struct fence_ops + struct dma_fence_ops @@ @@ - struct fence_cb + struct dma_fence_cb @@ @@ - struct fence_array + struct dma_fence_array @@ @@ - enum fence_flag_bits + enum dma_fence_flag_bits @@ @@ ( - fence_init + dma_fence_init | - fence_release + dma_fence_release | - fence_free + dma_fence_free | - fence_get + dma_fence_get | - fence_get_rcu + dma_fence_get_rcu | - fence_put + dma_fence_put | - fence_signal + dma_fence_signal | - fence_signal_locked + dma_fence_signal_locked | - fence_default_wait + dma_fence_default_wait | - fence_add_callback + dma_fence_add_callback | - fence_remove_callback + dma_fence_remove_callback | - fence_enable_sw_signaling + dma_fence_enable_sw_signaling | - fence_is_signaled_locked + dma_fence_is_signaled_locked | - fence_is_signaled + dma_fence_is_signaled | - fence_is_later + dma_fence_is_later | - fence_later + dma_fence_later | - fence_wait_timeout + dma_fence_wait_timeout | - fence_wait_any_timeout + dma_fence_wait_any_timeout | - fence_wait + dma_fence_wait | - fence_context_alloc + dma_fence_context_alloc | - fence_array_create + dma_fence_array_create | - to_fence_array + to_dma_fence_array | - fence_is_array + dma_fence_is_array | - trace_fence_emit + trace_dma_fence_emit | - FENCE_TRACE + DMA_FENCE_TRACE | - FENCE_WARN + DMA_FENCE_WARN | - FENCE_ERR + DMA_FENCE_ERR ) ( ... ) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Acked-by: Sumit Semwal <sumit.semwal@linaro.org> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/20161025120045.28839-1-chris@chris-wilson.co.uk
Diffstat (limited to 'drivers/dma-buf/fence.c')
-rw-r--r--drivers/dma-buf/fence.c534
1 files changed, 0 insertions, 534 deletions
diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c
deleted file mode 100644
index cc05dddc77a6..000000000000
--- a/drivers/dma-buf/fence.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Fence mechanism for dma-buf and to allow for asynchronous dma access
- *
- * Copyright (C) 2012 Canonical Ltd
- * Copyright (C) 2012 Texas Instruments
- *
- * Authors:
- * Rob Clark <robdclark@gmail.com>
- * Maarten Lankhorst <maarten.lankhorst@canonical.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/atomic.h>
-#include <linux/fence.h>
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/fence.h>
-
-EXPORT_TRACEPOINT_SYMBOL(fence_annotate_wait_on);
-EXPORT_TRACEPOINT_SYMBOL(fence_emit);
-
-/*
- * fence context counter: each execution context should have its own
- * fence context, this allows checking if fences belong to the same
- * context or not. One device can have multiple separate contexts,
- * and they're used if some engine can run independently of another.
- */
-static atomic64_t fence_context_counter = ATOMIC64_INIT(0);
-
-/**
- * fence_context_alloc - allocate an array of fence contexts
- * @num: [in] amount of contexts to allocate
- *
- * This function will return the first index of the number of fences allocated.
- * The fence context is used for setting fence->context to a unique number.
- */
-u64 fence_context_alloc(unsigned num)
-{
- BUG_ON(!num);
- return atomic64_add_return(num, &fence_context_counter) - num;
-}
-EXPORT_SYMBOL(fence_context_alloc);
-
-/**
- * fence_signal_locked - signal completion of a fence
- * @fence: the fence to signal
- *
- * Signal completion for software callbacks on a fence, this will unblock
- * fence_wait() calls and run all the callbacks added with
- * fence_add_callback(). Can be called multiple times, but since a fence
- * can only go from unsignaled to signaled state, it will only be effective
- * the first time.
- *
- * Unlike fence_signal, this function must be called with fence->lock held.
- */
-int fence_signal_locked(struct fence *fence)
-{
- struct fence_cb *cur, *tmp;
- int ret = 0;
-
- lockdep_assert_held(fence->lock);
-
- if (WARN_ON(!fence))
- return -EINVAL;
-
- if (!ktime_to_ns(fence->timestamp)) {
- fence->timestamp = ktime_get();
- smp_mb__before_atomic();
- }
-
- if (test_and_set_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
- ret = -EINVAL;
-
- /*
- * we might have raced with the unlocked fence_signal,
- * still run through all callbacks
- */
- } else
- trace_fence_signaled(fence);
-
- list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
- list_del_init(&cur->node);
- cur->func(fence, cur);
- }
- return ret;
-}
-EXPORT_SYMBOL(fence_signal_locked);
-
-/**
- * fence_signal - signal completion of a fence
- * @fence: the fence to signal
- *
- * Signal completion for software callbacks on a fence, this will unblock
- * fence_wait() calls and run all the callbacks added with
- * fence_add_callback(). Can be called multiple times, but since a fence
- * can only go from unsignaled to signaled state, it will only be effective
- * the first time.
- */
-int fence_signal(struct fence *fence)
-{
- unsigned long flags;
-
- if (!fence)
- return -EINVAL;
-
- if (!ktime_to_ns(fence->timestamp)) {
- fence->timestamp = ktime_get();
- smp_mb__before_atomic();
- }
-
- if (test_and_set_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
- return -EINVAL;
-
- trace_fence_signaled(fence);
-
- if (test_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) {
- struct fence_cb *cur, *tmp;
-
- spin_lock_irqsave(fence->lock, flags);
- list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
- list_del_init(&cur->node);
- cur->func(fence, cur);
- }
- spin_unlock_irqrestore(fence->lock, flags);
- }
- return 0;
-}
-EXPORT_SYMBOL(fence_signal);
-
-/**
- * fence_wait_timeout - sleep until the fence gets signaled
- * or until timeout elapses
- * @fence: [in] the fence to wait on
- * @intr: [in] if true, do an interruptible wait
- * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
- *
- * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the
- * remaining timeout in jiffies on success. Other error values may be
- * returned on custom implementations.
- *
- * Performs a synchronous wait on this fence. It is assumed the caller
- * directly or indirectly (buf-mgr between reservation and committing)
- * holds a reference to the fence, otherwise the fence might be
- * freed before return, resulting in undefined behavior.
- */
-signed long
-fence_wait_timeout(struct fence *fence, bool intr, signed long timeout)
-{
- signed long ret;
-
- if (WARN_ON(timeout < 0))
- return -EINVAL;
-
- if (timeout == 0)
- return fence_is_signaled(fence);
-
- trace_fence_wait_start(fence);
- ret = fence->ops->wait(fence, intr, timeout);
- trace_fence_wait_end(fence);
- return ret;
-}
-EXPORT_SYMBOL(fence_wait_timeout);
-
-void fence_release(struct kref *kref)
-{
- struct fence *fence =
- container_of(kref, struct fence, refcount);
-
- trace_fence_destroy(fence);
-
- BUG_ON(!list_empty(&fence->cb_list));
-
- if (fence->ops->release)
- fence->ops->release(fence);
- else
- fence_free(fence);
-}
-EXPORT_SYMBOL(fence_release);
-
-void fence_free(struct fence *fence)
-{
- kfree_rcu(fence, rcu);
-}
-EXPORT_SYMBOL(fence_free);
-
-/**
- * fence_enable_sw_signaling - enable signaling on fence
- * @fence: [in] the fence to enable
- *
- * this will request for sw signaling to be enabled, to make the fence
- * complete as soon as possible
- */
-void fence_enable_sw_signaling(struct fence *fence)
-{
- unsigned long flags;
-
- if (!test_and_set_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) &&
- !test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
- trace_fence_enable_signal(fence);
-
- spin_lock_irqsave(fence->lock, flags);
-
- if (!fence->ops->enable_signaling(fence))
- fence_signal_locked(fence);
-
- spin_unlock_irqrestore(fence->lock, flags);
- }
-}
-EXPORT_SYMBOL(fence_enable_sw_signaling);
-
-/**
- * fence_add_callback - add a callback to be called when the fence
- * is signaled
- * @fence: [in] the fence to wait on
- * @cb: [in] the callback to register
- * @func: [in] the function to call
- *
- * cb will be initialized by fence_add_callback, no initialization
- * by the caller is required. Any number of callbacks can be registered
- * to a fence, but a callback can only be registered to one fence at a time.
- *
- * Note that the callback can be called from an atomic context. If
- * fence is already signaled, this function will return -ENOENT (and
- * *not* call the callback)
- *
- * Add a software callback to the fence. Same restrictions apply to
- * refcount as it does to fence_wait, however the caller doesn't need to
- * keep a refcount to fence afterwards: when software access is enabled,
- * the creator of the fence is required to keep the fence alive until
- * after it signals with fence_signal. The callback itself can be called
- * from irq context.
- *
- */
-int fence_add_callback(struct fence *fence, struct fence_cb *cb,
- fence_func_t func)
-{
- unsigned long flags;
- int ret = 0;
- bool was_set;
-
- if (WARN_ON(!fence || !func))
- return -EINVAL;
-
- if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
- INIT_LIST_HEAD(&cb->node);
- return -ENOENT;
- }
-
- spin_lock_irqsave(fence->lock, flags);
-
- was_set = test_and_set_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags);
-
- if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
- ret = -ENOENT;
- else if (!was_set) {
- trace_fence_enable_signal(fence);
-
- if (!fence->ops->enable_signaling(fence)) {
- fence_signal_locked(fence);
- ret = -ENOENT;
- }
- }
-
- if (!ret) {
- cb->func = func;
- list_add_tail(&cb->node, &fence->cb_list);
- } else
- INIT_LIST_HEAD(&cb->node);
- spin_unlock_irqrestore(fence->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(fence_add_callback);
-
-/**
- * fence_remove_callback - remove a callback from the signaling list
- * @fence: [in] the fence to wait on
- * @cb: [in] the callback to remove
- *
- * Remove a previously queued callback from the fence. This function returns
- * true if the callback is successfully removed, or false if the fence has
- * already been signaled.
- *
- * *WARNING*:
- * Cancelling a callback should only be done if you really know what you're
- * doing, since deadlocks and race conditions could occur all too easily. For
- * this reason, it should only ever be done on hardware lockup recovery,
- * with a reference held to the fence.
- */
-bool
-fence_remove_callback(struct fence *fence, struct fence_cb *cb)
-{
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(fence->lock, flags);
-
- ret = !list_empty(&cb->node);
- if (ret)
- list_del_init(&cb->node);
-
- spin_unlock_irqrestore(fence->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(fence_remove_callback);
-
-struct default_wait_cb {
- struct fence_cb base;
- struct task_struct *task;
-};
-
-static void
-fence_default_wait_cb(struct fence *fence, struct fence_cb *cb)
-{
- struct default_wait_cb *wait =
- container_of(cb, struct default_wait_cb, base);
-
- wake_up_state(wait->task, TASK_NORMAL);
-}
-
-/**
- * fence_default_wait - default sleep until the fence gets signaled
- * or until timeout elapses
- * @fence: [in] the fence to wait on
- * @intr: [in] if true, do an interruptible wait
- * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
- *
- * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the
- * remaining timeout in jiffies on success.
- */
-signed long
-fence_default_wait(struct fence *fence, bool intr, signed long timeout)
-{
- struct default_wait_cb cb;
- unsigned long flags;
- signed long ret = timeout;
- bool was_set;
-
- if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
- return timeout;
-
- spin_lock_irqsave(fence->lock, flags);
-
- if (intr && signal_pending(current)) {
- ret = -ERESTARTSYS;
- goto out;
- }
-
- was_set = test_and_set_bit(FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags);
-
- if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
- goto out;
-
- if (!was_set) {
- trace_fence_enable_signal(fence);
-
- if (!fence->ops->enable_signaling(fence)) {
- fence_signal_locked(fence);
- goto out;
- }
- }
-
- cb.base.func = fence_default_wait_cb;
- cb.task = current;
- list_add(&cb.base.node, &fence->cb_list);
-
- while (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags) && ret > 0) {
- if (intr)
- __set_current_state(TASK_INTERRUPTIBLE);
- else
- __set_current_state(TASK_UNINTERRUPTIBLE);
- spin_unlock_irqrestore(fence->lock, flags);
-
- ret = schedule_timeout(ret);
-
- spin_lock_irqsave(fence->lock, flags);
- if (ret > 0 && intr && signal_pending(current))
- ret = -ERESTARTSYS;
- }
-
- if (!list_empty(&cb.base.node))
- list_del(&cb.base.node);
- __set_current_state(TASK_RUNNING);
-
-out:
- spin_unlock_irqrestore(fence->lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(fence_default_wait);
-
-static bool
-fence_test_signaled_any(struct fence **fences, uint32_t count)
-{
- int i;
-
- for (i = 0; i < count; ++i) {
- struct fence *fence = fences[i];
- if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags))
- return true;
- }
- return false;
-}
-
-/**
- * fence_wait_any_timeout - sleep until any fence gets signaled
- * or until timeout elapses
- * @fences: [in] array of fences to wait on
- * @count: [in] number of fences to wait on
- * @intr: [in] if true, do an interruptible wait
- * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
- *
- * Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if
- * interrupted, 0 if the wait timed out, or the remaining timeout in jiffies
- * on success.
- *
- * Synchronous waits for the first fence in the array to be signaled. The
- * caller needs to hold a reference to all fences in the array, otherwise a
- * fence might be freed before return, resulting in undefined behavior.
- */
-signed long
-fence_wait_any_timeout(struct fence **fences, uint32_t count,
- bool intr, signed long timeout)
-{
- struct default_wait_cb *cb;
- signed long ret = timeout;
- unsigned i;
-
- if (WARN_ON(!fences || !count || timeout < 0))
- return -EINVAL;
-
- if (timeout == 0) {
- for (i = 0; i < count; ++i)
- if (fence_is_signaled(fences[i]))
- return 1;
-
- return 0;
- }
-
- cb = kcalloc(count, sizeof(struct default_wait_cb), GFP_KERNEL);
- if (cb == NULL) {
- ret = -ENOMEM;
- goto err_free_cb;
- }
-
- for (i = 0; i < count; ++i) {
- struct fence *fence = fences[i];
-
- if (fence->ops->wait != fence_default_wait) {
- ret = -EINVAL;
- goto fence_rm_cb;
- }
-
- cb[i].task = current;
- if (fence_add_callback(fence, &cb[i].base,
- fence_default_wait_cb)) {
- /* This fence is already signaled */
- goto fence_rm_cb;
- }
- }
-
- while (ret > 0) {
- if (intr)
- set_current_state(TASK_INTERRUPTIBLE);
- else
- set_current_state(TASK_UNINTERRUPTIBLE);
-
- if (fence_test_signaled_any(fences, count))
- break;
-
- ret = schedule_timeout(ret);
-
- if (ret > 0 && intr && signal_pending(current))
- ret = -ERESTARTSYS;
- }
-
- __set_current_state(TASK_RUNNING);
-
-fence_rm_cb:
- while (i-- > 0)
- fence_remove_callback(fences[i], &cb[i].base);
-
-err_free_cb:
- kfree(cb);
-
- return ret;
-}
-EXPORT_SYMBOL(fence_wait_any_timeout);
-
-/**
- * fence_init - Initialize a custom fence.
- * @fence: [in] the fence to initialize
- * @ops: [in] the fence_ops for operations on this fence
- * @lock: [in] the irqsafe spinlock to use for locking this fence
- * @context: [in] the execution context this fence is run on
- * @seqno: [in] a linear increasing sequence number for this context
- *
- * Initializes an allocated fence, the caller doesn't have to keep its
- * refcount after committing with this fence, but it will need to hold a
- * refcount again if fence_ops.enable_signaling gets called. This can
- * be used for other implementing other types of fence.
- *
- * context and seqno are used for easy comparison between fences, allowing
- * to check which fence is later by simply using fence_later.
- */
-void
-fence_init(struct fence *fence, const struct fence_ops *ops,
- spinlock_t *lock, u64 context, unsigned seqno)
-{
- BUG_ON(!lock);
- BUG_ON(!ops || !ops->wait || !ops->enable_signaling ||
- !ops->get_driver_name || !ops->get_timeline_name);
-
- kref_init(&fence->refcount);
- fence->ops = ops;
- INIT_LIST_HEAD(&fence->cb_list);
- fence->lock = lock;
- fence->context = context;
- fence->seqno = seqno;
- fence->flags = 0UL;
-
- trace_fence_init(fence);
-}
-EXPORT_SYMBOL(fence_init);