drm: rcar-du: Arm the page flip event after queuing the page flip
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Sat, 4 Mar 2017 13:14:47 +0000 (15:14 +0200)
committerKieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Mon, 22 May 2017 15:11:41 +0000 (16:11 +0100)
The page flip event is armed in the atomic begin handler, creating a
race condition with the frame end interrupt that could send the event
before the atomic operation actually completes. To avoid that, arm the
event in the atomic flush handler after queuing the page flip.

This change doesn't fully close the race window, as the frame end
interrupt could be generated before the page flip is committed to
hardware but only handled after the event is armed. However, the race
window is now much smaller.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
drivers/gpu/drm/rcar-du/rcar_du_crtc.c

index 4ed6f2340af024a4298c126e62a6fd1b46512ef8..5f0664bcd12d6b0a503c8f2cfb26dd76f42fe7fb 100644 (file)
@@ -581,17 +581,6 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
                                      struct drm_crtc_state *old_crtc_state)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
-       struct drm_device *dev = rcrtc->crtc.dev;
-       unsigned long flags;
-
-       if (crtc->state->event) {
-               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-
-               spin_lock_irqsave(&dev->event_lock, flags);
-               rcrtc->event = crtc->state->event;
-               crtc->state->event = NULL;
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       }
 
        if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
                rcar_du_vsp_atomic_begin(rcrtc);
@@ -601,9 +590,20 @@ static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc,
                                      struct drm_crtc_state *old_crtc_state)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+       struct drm_device *dev = rcrtc->crtc.dev;
+       unsigned long flags;
 
        rcar_du_crtc_update_planes(rcrtc);
 
+       if (crtc->state->event) {
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+               spin_lock_irqsave(&dev->event_lock, flags);
+               rcrtc->event = crtc->state->event;
+               crtc->state->event = NULL;
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
+
        if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
                rcar_du_vsp_atomic_flush(rcrtc);
 }