summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_fence.c
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-09-21 22:49:39 +0400
committerBen Skeggs <bskeggs@redhat.com>2010-10-05 03:59:12 +0400
commit8ac3891b48906b38db4b153c2d0d55db2ef81aee (patch)
treea01cfeb53235f2d112e2f327e52d603b7ef67f11 /drivers/gpu/drm/nouveau/nouveau_fence.c
parent2730723bbc4a8b289fa536fc3555e15947da09c1 (diff)
downloadlinux-8ac3891b48906b38db4b153c2d0d55db2ef81aee.tar.xz
drm/nouveau: Provide a means to have arbitrary work run on fence completion.
Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_fence.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 62f13189698a..fbb2c3b26239 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -39,6 +39,9 @@ struct nouveau_fence {
uint32_t sequence;
bool signalled;
+
+ void (*work)(void *priv, bool signalled);
+ void *priv;
};
static inline struct nouveau_fence *
@@ -78,6 +81,10 @@ nouveau_fence_update(struct nouveau_channel *chan)
sequence = fence->sequence;
fence->signalled = true;
list_del(&fence->entry);
+
+ if (unlikely(fence->work))
+ fence->work(fence->priv, true);
+
kref_put(&fence->refcount, nouveau_fence_del);
if (sequence == chan->fence.sequence_ack)
@@ -148,6 +155,25 @@ nouveau_fence_emit(struct nouveau_fence *fence)
}
void
+nouveau_fence_work(struct nouveau_fence *fence,
+ void (*work)(void *priv, bool signalled),
+ void *priv)
+{
+ BUG_ON(fence->work);
+
+ spin_lock(&fence->channel->fence.lock);
+
+ if (fence->signalled) {
+ work(priv, true);
+ } else {
+ fence->work = work;
+ fence->priv = priv;
+ }
+
+ spin_unlock(&fence->channel->fence.lock);
+}
+
+void
nouveau_fence_unref(void **sync_obj)
{
struct nouveau_fence *fence = nouveau_fence(*sync_obj);
@@ -268,6 +294,10 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan)
list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
fence->signalled = true;
list_del(&fence->entry);
+
+ if (unlikely(fence->work))
+ fence->work(fence->priv, false);
+
kref_put(&fence->refcount, nouveau_fence_del);
}
}