From: Laurent Pinchart Date: Wed, 18 Feb 2015 11:21:56 +0000 (+0200) Subject: drm: rcar-du: Wait for page flip completion when turning the CRTC off X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=36693f3c3254d9361095f6b225d5e69bd8da5c32;p=deliverable%2Flinux.git drm: rcar-du: Wait for page flip completion when turning the CRTC off Turning a CRTC off will prevent a queued page flip from ever completing, potentially confusing userspace. Wait for queued page flips to complete before turning the CRTC off to avoid this. Signed-off-by: Laurent Pinchart --- diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index e0562f2b3261..7f5ae0269a61 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -300,11 +300,39 @@ static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc) spin_lock_irqsave(&dev->event_lock, flags); drm_send_vblank_event(dev, rcrtc->index, event); + wake_up(&rcrtc->flip_wait); spin_unlock_irqrestore(&dev->event_lock, flags); drm_vblank_put(dev, rcrtc->index); } +static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc) +{ + struct drm_device *dev = rcrtc->crtc.dev; + unsigned long flags; + bool pending; + + spin_lock_irqsave(&dev->event_lock, flags); + pending = rcrtc->event != NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + return pending; +} + +static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->group->dev; + + if (wait_event_timeout(rcrtc->flip_wait, + !rcar_du_crtc_page_flip_pending(rcrtc), + msecs_to_jiffies(50))) + return; + + dev_warn(rcdu->dev, "page flip timeout\n"); + + rcar_du_crtc_finish_page_flip(rcrtc); +} + /* ----------------------------------------------------------------------------- * Start/Stop and Suspend/Resume */ @@ -365,6 +393,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (!rcrtc->started) return; + /* Wait for page flip completion before stopping the CRTC as userspace + * excepts page flips to eventually complete. + */ + rcar_du_crtc_wait_page_flip(rcrtc); + mutex_lock(&rcrtc->group->planes.lock); rcrtc->plane->enabled = false; rcar_du_crtc_update_planes(crtc); @@ -644,6 +677,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) return -EPROBE_DEFER; } + init_waitqueue_head(&rcrtc->flip_wait); + rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index]; rcrtc->index = index; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index d2f89f7d2e5e..fb39e040f17b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,6 +15,7 @@ #define __RCAR_DU_CRTC_H__ #include +#include #include #include @@ -32,6 +33,8 @@ struct rcar_du_crtc { bool started; struct drm_pending_vblank_event *event; + wait_queue_head_t flip_wait; + unsigned int outputs; int dpms;