intel_update_watermarks(&crtc->base);
 
        if (atomic->update_fbc)
-               intel_fbc_update(crtc);
+               intel_fbc_post_update(crtc);
 
        if (atomic->post_enable_primary)
                intel_post_enable_primary(&crtc->base);
        struct intel_crtc_state *pipe_config =
                to_intel_crtc_state(crtc->base.state);
 
-       if (atomic->disable_fbc)
-               intel_fbc_deactivate(crtc);
+       if (atomic->update_fbc)
+               intel_fbc_pre_update(crtc);
 
        if (crtc->atomic.disable_ips)
                hsw_disable_ips(crtc);
        mutex_unlock(&dev->struct_mutex);
 
        intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
-       intel_fbc_update(crtc);
+       intel_fbc_post_update(crtc);
        drm_framebuffer_unreference(work->old_fb);
 
        BUG_ON(atomic_read(&crtc->unpin_work_count) == 0);
                          to_intel_plane(primary)->frontbuffer_bit);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_fbc_deactivate(intel_crtc);
+       intel_fbc_pre_update(intel_crtc);
        intel_frontbuffer_flip_prepare(dev,
                                       to_intel_plane(primary)->frontbuffer_bit);
 
        case DRM_PLANE_TYPE_PRIMARY:
                intel_crtc->atomic.pre_disable_primary = turn_off;
                intel_crtc->atomic.post_enable_primary = turn_on;
-               intel_crtc->atomic.disable_fbc = true;
                intel_crtc->atomic.update_fbc = true;
 
                if (turn_off) {
 
  */
 struct intel_crtc_atomic_commit {
        /* Sleepable operations to perform before commit */
-       bool disable_fbc;
        bool disable_ips;
        bool pre_disable_primary;
 
        /* Sleepable operations to perform after commit */
        unsigned fb_bits;
        bool wait_vblank;
-       bool update_fbc;
        bool post_enable_primary;
        unsigned update_sprite_watermarks;
+
+       /* Sleepable operations to perform before and after commit */
+       bool update_fbc;
 };
 
 struct intel_crtc {
 /* intel_fbc.c */
 bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
 void intel_fbc_deactivate(struct intel_crtc *crtc);
-void intel_fbc_update(struct intel_crtc *crtc);
+void intel_fbc_pre_update(struct intel_crtc *crtc);
+void intel_fbc_post_update(struct intel_crtc *crtc);
 void intel_fbc_init(struct drm_i915_private *dev_priv);
 void intel_fbc_enable(struct intel_crtc *crtc);
 void intel_fbc_disable(struct drm_i915_private *dev_priv);
 
        if (INTEL_INFO(dev_priv)->gen > 4)
                return true;
 
+       /* FIXME: we don't have the appropriate state locks to do this here. */
        for_each_pipe(dev_priv, pipe) {
                crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_fbc *fbc = &dev_priv->fbc;
        struct intel_fbc_state_cache *cache = &fbc->state_cache;
-       struct intel_crtc_state *crtc_state = crtc->config;
+       struct intel_crtc_state *crtc_state =
+               to_intel_crtc_state(crtc->base.state);
        struct intel_plane_state *plane_state =
                to_intel_plane_state(crtc->base.primary->state);
        struct drm_framebuffer *fb = plane_state->base.fb;
        struct drm_i915_gem_object *obj;
 
+       WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
+       WARN_ON(!drm_modeset_is_locked(&crtc->base.primary->mutex));
+
        cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
                cache->crtc.hsw_bdw_pixel_rate =
        return memcmp(params1, params2, sizeof(*params1)) == 0;
 }
 
-static void intel_fbc_pre_update(struct intel_crtc *crtc)
+void intel_fbc_pre_update(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_fbc *fbc = &dev_priv->fbc;
 
-       WARN_ON(!mutex_is_locked(&fbc->lock));
+       if (!fbc_supported(dev_priv))
+               return;
+
+       mutex_lock(&fbc->lock);
 
        if (!multiple_pipes_ok(dev_priv)) {
                set_no_fbc_reason(dev_priv, "more than one pipe active");
        }
 
        if (!fbc->enabled || fbc->crtc != crtc)
-               return;
+               goto unlock;
 
        intel_fbc_update_state_cache(crtc);
 
 deactivate:
        __intel_fbc_deactivate(dev_priv);
+unlock:
+       mutex_unlock(&fbc->lock);
 }
 
-static void intel_fbc_post_update(struct intel_crtc *crtc)
+static void __intel_fbc_post_update(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_fbc *fbc = &dev_priv->fbc;
        fbc->no_fbc_reason = "FBC enabled (active or scheduled)";
 }
 
-/*
- * intel_fbc_update - activate/deactivate FBC as needed
- * @crtc: the CRTC that triggered the update
- *
- * This function reevaluates the overall state and activates or deactivates FBC.
- */
-void intel_fbc_update(struct intel_crtc *crtc)
+void intel_fbc_post_update(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_fbc *fbc = &dev_priv->fbc;
                return;
 
        mutex_lock(&fbc->lock);
-       intel_fbc_pre_update(crtc);
-       intel_fbc_post_update(crtc);
+       __intel_fbc_post_update(crtc);
        mutex_unlock(&fbc->lock);
 }
 
                if (fbc->active)
                        intel_fbc_recompress(dev_priv);
                else
-                       intel_fbc_post_update(fbc->crtc);
+                       __intel_fbc_post_update(fbc->crtc);
        }
 
        mutex_unlock(&fbc->lock);