diff options
author | Eric Anholt <eric@anholt.net> | 2014-11-17 19:03:22 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2015-06-04 14:15:24 -0700 |
commit | c8ddb165e37f939f405ddfbc24f859fdc9c798dd (patch) | |
tree | 8a9c4c70e3e8b4e33fa92abbb4ac87fbaa285a1d | |
parent | 631c7adff119fc2fedb09e64a9e2057501648d59 (diff) | |
download | linux-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.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_gem.c | 39 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_irq.c | 14 |
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); } |