drm/i915: Block enabling FBC until flips have been completed
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Mon, 25 Jun 2018 16:37:57 +0000 (18:37 +0200)
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Fri, 29 Jun 2018 08:06:08 +0000 (10:06 +0200)
There is a small race window in which FBC can be enabled after
pre_plane_update is called, but before the page flip has been
queued or completed.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103167
Link: https://patchwork.freedesktop.org/patch/msgid/20180625163758.10871-1-maarten.lankhorst@linux.intel.com
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_fbc.c

index 2b684f431c600ca8e15d7dd8e230ab6d42f1a0c3..615ed807ea32441389a1ee927d0ceb6c1ace0176 100644 (file)
@@ -512,6 +512,7 @@ struct intel_fbc {
 
        bool enabled;
        bool active;
+       bool flip_pending;
 
        bool underrun_detected;
        struct work_struct underrun_work;
index b431b6733cc1582e826760a60cf1bd49e4feacff..9f9ea0b5452fed37c4dbd1b245572f676494a11f 100644 (file)
@@ -924,13 +924,6 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc,
                                                32 * fbc->threshold) * 8;
 }
 
-static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
-                                      struct intel_fbc_reg_params *params2)
-{
-       /* We can use this since intel_fbc_get_reg_params() does a memset. */
-       return memcmp(params1, params2, sizeof(*params1)) == 0;
-}
-
 void intel_fbc_pre_update(struct intel_crtc *crtc,
                          struct intel_crtc_state *crtc_state,
                          struct intel_plane_state *plane_state)
@@ -953,6 +946,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc,
                goto unlock;
 
        intel_fbc_update_state_cache(crtc, crtc_state, plane_state);
+       fbc->flip_pending = true;
 
 deactivate:
        intel_fbc_deactivate(dev_priv, reason);
@@ -988,13 +982,15 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        struct intel_fbc *fbc = &dev_priv->fbc;
-       struct intel_fbc_reg_params old_params;
 
        WARN_ON(!mutex_is_locked(&fbc->lock));
 
        if (!fbc->enabled || fbc->crtc != crtc)
                return;
 
+       fbc->flip_pending = false;
+       WARN_ON(fbc->active);
+
        if (!i915_modparams.enable_fbc) {
                intel_fbc_deactivate(dev_priv, "disabled at runtime per module param");
                __intel_fbc_disable(dev_priv);
@@ -1002,25 +998,16 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc)
                return;
        }
 
-       if (!intel_fbc_can_activate(crtc)) {
-               WARN_ON(fbc->active);
-               return;
-       }
-
-       old_params = fbc->params;
        intel_fbc_get_reg_params(crtc, &fbc->params);
 
-       /* If the scanout has not changed, don't modify the FBC settings.
-        * Note that we make the fundamental assumption that the fb->obj
-        * cannot be unpinned (and have its GTT offset and fence revoked)
-        * without first being decoupled from the scanout and FBC disabled.
-        */
-       if (fbc->active &&
-           intel_fbc_reg_params_equal(&old_params, &fbc->params))
+       if (!intel_fbc_can_activate(crtc))
                return;
 
-       intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)");
-       intel_fbc_schedule_activation(crtc);
+       if (!fbc->busy_bits) {
+               intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)");
+               intel_fbc_schedule_activation(crtc);
+       } else
+               intel_fbc_deactivate(dev_priv, "frontbuffer write");
 }
 
 void intel_fbc_post_update(struct intel_crtc *crtc)
@@ -1085,7 +1072,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
            (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) {
                if (fbc->active)
                        intel_fbc_recompress(dev_priv);
-               else
+               else if (!fbc->flip_pending)
                        __intel_fbc_post_update(fbc->crtc);
        }