drm/atomic-helper: Reject legacy flips on a disabled pipe
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 8 Dec 2015 08:49:20 +0000 (09:49 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 5 Jan 2016 09:07:51 +0000 (10:07 +0100)
We want this for consistency with existing page_flip semantics.

Since this spurred quite a discussion on IRC also document why we
reject event generation when the pipe is off: It's not that it's hard
to implement, but userspace has a track recording which proves that it's
way too easy to accidentally abuse and cause havoc. We want to make
sure userspace doesn't get away with that.

v2: Somehow thought we do reject events already, but that code only
existed in my imagination ... Also suggestions from Thierry.

Cc: Daniel Stone <daniels@collabora.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449564561-3896-4-git-send-email-daniel.vetter@ffwll.ch
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
include/drm/drm_crtc.h

index 14b32158051717e210b983bdea123a977f9c1b7c..6050c80f1dbc33950d0479ae02b4dcafd4837bf7 100644 (file)
@@ -508,6 +508,22 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /*
+        * Reject event generation for when a CRTC is off and stays off.
+        * It wouldn't be hard to implement this, but userspace has a track
+        * record of happily burning through 100% cpu (or worse, crash) when the
+        * display pipe is suspended. To avoid all that fun just reject updates
+        * that ask for events since likely that indicates a bug in the
+        * compositor's drawing loop. This is consistent with the vblank IOCTL
+        * and legacy page_flip IOCTL which also reject service on a disabled
+        * pipe.
+        */
+       if (state->event && !state->active && !crtc->state->active) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] requesting event but off\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index 26d258d0618b529cdbb05a21b90ad65885f4cf4e..738104b68d26ad6285d2f4e84bccc58fff25f1be 100644 (file)
@@ -2284,6 +2284,15 @@ retry:
                goto fail;
        drm_atomic_set_fb_for_plane(plane_state, fb);
 
+       /* Make sure we don't accidentally do a full modeset. */
+       state->allow_modeset = false;
+       if (!crtc_state->active) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n",
+                                crtc->base.id);
+               ret = -EINVAL;
+               goto fail;
+       }
+
        ret = drm_atomic_async_commit(state);
        if (ret != 0)
                goto fail;
index e3c4d486e1af853a44422620be736823102c2a8a..c65a212db77e7a99b26735c262cb31a9b2504195 100644 (file)
@@ -551,7 +551,8 @@ struct drm_crtc_funcs {
         * ->page_flip() operation is already pending the callback should return
         * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode
         * or just runtime disabled through DPMS respectively the new atomic
-        * "ACTIVE" state) should result in an -EINVAL error code.
+        * "ACTIVE" state) should result in an -EINVAL error code. Note that
+        * drm_atomic_helper_page_flip() checks this already for atomic drivers.
         */
        int (*page_flip)(struct drm_crtc *crtc,
                         struct drm_framebuffer *fb,