summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_fence.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-01-31 14:57:33 +1000
committerBen Skeggs <bskeggs@redhat.com>2013-02-20 16:00:48 +1000
commite18c080fb8695d038f69c26c248f5ecbd9e8aa77 (patch)
tree74e191678bb9ba028d85e219863ddb706f4e6fc8 /drivers/gpu/drm/nouveau/nouveau_fence.c
parenta2fa297378c54e9b8b8ad355e34c9fbed730250b (diff)
downloadop-kernel-dev-e18c080fb8695d038f69c26c248f5ecbd9e8aa77.zip
op-kernel-dev-e18c080fb8695d038f69c26c248f5ecbd9e8aa77.tar.gz
drm/nouveau/fence/nv84-: put processes to sleep while waiting on fences
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.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index b6b8e49..b7349a6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -33,6 +33,8 @@
#include "nouveau_dma.h"
#include "nouveau_fence.h"
+#include <engine/fifo.h>
+
void
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
@@ -107,13 +109,87 @@ nouveau_fence_done(struct nouveau_fence *fence)
return !fence->channel;
}
+struct nouveau_fence_uevent {
+ struct nouveau_eventh handler;
+ struct nouveau_fence_priv *priv;
+};
+
+static int
+nouveau_fence_wait_uevent_handler(struct nouveau_eventh *event, int index)
+{
+ struct nouveau_fence_uevent *uevent =
+ container_of(event, struct nouveau_fence_uevent, handler);
+ wake_up_all(&uevent->priv->waiting);
+ return NVKM_EVENT_KEEP;
+}
+
+static int
+nouveau_fence_wait_uevent(struct nouveau_fence *fence, bool intr)
+
+{
+ struct nouveau_channel *chan = fence->channel;
+ struct nouveau_fifo *pfifo = nouveau_fifo(chan->drm->device);
+ struct nouveau_fence_priv *priv = chan->drm->fence;
+ struct nouveau_fence_uevent uevent = {
+ .handler.func = nouveau_fence_wait_uevent_handler,
+ .priv = priv,
+ };
+ int ret = 0;
+
+ nouveau_event_get(pfifo->uevent, 0, &uevent.handler);
+
+ if (fence->timeout) {
+ unsigned long timeout = fence->timeout - jiffies;
+
+ if (time_before(jiffies, fence->timeout)) {
+ if (intr) {
+ ret = wait_event_interruptible_timeout(
+ priv->waiting,
+ nouveau_fence_done(fence),
+ timeout);
+ } else {
+ ret = wait_event_timeout(priv->waiting,
+ nouveau_fence_done(fence),
+ timeout);
+ }
+ }
+
+ if (ret >= 0) {
+ fence->timeout = jiffies + ret;
+ if (time_after_eq(jiffies, fence->timeout))
+ ret = -EBUSY;
+ }
+ } else {
+ if (intr) {
+ ret = wait_event_interruptible(priv->waiting,
+ nouveau_fence_done(fence));
+ } else {
+ wait_event(priv->waiting, nouveau_fence_done(fence));
+ }
+ }
+
+ nouveau_event_put(pfifo->uevent, 0, &uevent.handler);
+ if (unlikely(ret < 0))
+ return ret;
+
+ return 0;
+}
+
int
nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
{
+ struct nouveau_channel *chan = fence->channel;
+ struct nouveau_fence_priv *priv = chan ? chan->drm->fence : NULL;
unsigned long sleep_time = NSEC_PER_MSEC / 1000;
ktime_t t;
int ret = 0;
+ while (priv && priv->uevent && lazy && !nouveau_fence_done(fence)) {
+ ret = nouveau_fence_wait_uevent(fence, intr);
+ if (ret < 0)
+ return ret;
+ }
+
while (!nouveau_fence_done(fence)) {
if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
ret = -EBUSY;
OpenPOWER on IntegriCloud