summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2014-11-17 19:03:22 -0800
committerEric Anholt <eric@anholt.net>2015-06-04 14:15:24 -0700
commitc8ddb165e37f939f405ddfbc24f859fdc9c798dd (patch)
tree8a9c4c70e3e8b4e33fa92abbb4ac87fbaa285a1d
parent631c7adff119fc2fedb09e64a9e2057501648d59 (diff)
downloadlinux-c8ddb165e37f939f405ddfbc24f859fdc9c798dd.tar.gz
drm/vc4: Use interrupts for frame end handling.
We still exec synchronously, but this gets rid of the busy wait. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h3
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c39
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c14
3 files changed, 44 insertions, 12 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 8b745c3bac40..4c600e0d3a85 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -19,6 +19,9 @@ struct vc4_dev {
struct vc4_crtc *crtc[3];
struct vc4_v3d *v3d;
+ wait_queue_head_t frame_done_queue;
+ bool frame_done;
+
/* List of struct vc4_list_bo_entry allocated to accomodate
* binner overflow. These will be freed when the exec is
* done.
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 3c38e41bd41f..35e14f81ddbf 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -61,21 +61,37 @@ submit_cl(struct drm_device *dev, uint32_t thread, uint32_t start, uint32_t end)
barrier();
}
-static bool
-thread_stopped(struct drm_device *dev, uint32_t thread)
+static int
+vc4_wait_for_job(struct drm_device *dev, struct exec_info *exec,
+ unsigned timeout)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ int ret = 0;
+ unsigned long timeout_expire;
+ DEFINE_WAIT(wait);
- barrier();
- return !(V3D_READ(V3D_PCS) & (0x3 << thread));
-}
+ if (vc4->frame_done)
+ return 0;
-static int
-wait_for_job(struct drm_device *dev, struct exec_info *exec)
-{
- int ret;
+ timeout_expire = jiffies + msecs_to_jiffies(timeout);
+
+ for (;;) {
+ prepare_to_wait(&vc4->frame_done_queue, &wait,
+ TASK_UNINTERRUPTIBLE);
+
+ if (time_after_eq(jiffies, timeout_expire)) {
+ ret = -ETIME;
+ break;
+ }
+
+ if (vc4->frame_done)
+ break;
+
+ schedule_timeout(timeout_expire - jiffies);
+ }
+
+ finish_wait(&vc4->frame_done_queue, &wait);
- ret = wait_for(thread_stopped(dev, 1), 1000);
if (ret) {
DRM_ERROR("timeout waiting for render thread idle\n");
return ret;
@@ -125,10 +141,11 @@ vc4_submit(struct drm_device *dev, struct exec_info *exec)
V3D_WRITE(V3D_BPOA, 0);
V3D_WRITE(V3D_BPOS, 0);
+ vc4->frame_done = false;
submit_cl(dev, 0, ct0ca, ct0ea);
submit_cl(dev, 1, ct1ca, ct1ea);
- ret = wait_for_job(dev, exec);
+ ret = vc4_wait_for_job(dev, exec, 1000);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index dfc302606762..b0e6fa847367 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -24,7 +24,10 @@
#include "vc4_drv.h"
#include "vc4_regs.h"
-#define V3D_DRIVER_IRQS V3D_INT_OUTOMEM
+#define V3D_DRIVER_IRQS (V3D_INT_OUTOMEM | \
+ V3D_INT_FRDONE)
+
+DECLARE_WAIT_QUEUE_HEAD(render_wait);
static void
vc4_overflow_mem_work(struct work_struct *work)
@@ -70,6 +73,11 @@ vc4_irq(int irq, void *arg)
schedule_work(&vc4->overflow_mem_work);
}
+ if (intctl & V3D_INT_FRDONE) {
+ vc4->frame_done = true;
+ wake_up_all(&vc4->frame_done_queue);
+ }
+
return intctl ? IRQ_HANDLED : IRQ_NONE;
}
@@ -78,6 +86,7 @@ vc4_irq_preinstall(struct drm_device *dev)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ init_waitqueue_head(&vc4->frame_done_queue);
INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
/* Clear any pending interrupts someone might have left around
@@ -126,4 +135,7 @@ void vc4_irq_reset(struct drm_device *dev)
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
V3D_WRITE(V3D_INTDIS, 0);
V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
+
+ vc4->frame_done = true;
+ wake_up_all(&vc4->frame_done_queue);
}