diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 09e120d50e6551f70801d376ace6771ac406b606..6f4cb4678cbcc4d917f7ec1739f93ba3e4ae21cd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -418,6 +418,60 @@ static int vmw_fb_compute_depth(struct fb_var_screeninfo *var,
 	return 0;
 }
 
+static int vmwgfx_set_config_internal(struct drm_mode_set *set)
+{
+	struct drm_crtc *crtc = set->crtc;
+	struct drm_framebuffer *fb;
+	struct drm_crtc *tmp;
+	struct drm_modeset_acquire_ctx *ctx;
+	struct drm_device *dev = set->crtc->dev;
+	int ret;
+
+	ctx = dev->mode_config.acquire_ctx;
+
+restart:
+	/*
+	 * NOTE: ->set_config can also disable other crtcs (if we steal all
+	 * connectors from it), hence we need to refcount the fbs across all
+	 * crtcs. Atomic modeset will have saner semantics ...
+	 */
+	drm_for_each_crtc(tmp, dev)
+		tmp->primary->old_fb = tmp->primary->fb;
+
+	fb = set->fb;
+
+	ret = crtc->funcs->set_config(set, ctx);
+	if (ret == 0) {
+		crtc->primary->crtc = crtc;
+		crtc->primary->fb = fb;
+	}
+
+	drm_for_each_crtc(tmp, dev) {
+		if (tmp->primary->fb)
+			drm_framebuffer_get(tmp->primary->fb);
+		if (tmp->primary->old_fb)
+			drm_framebuffer_put(tmp->primary->old_fb);
+		tmp->primary->old_fb = NULL;
+	}
+
+	if (ret == -EDEADLK) {
+		dev->mode_config.acquire_ctx = NULL;
+
+retry_locking:
+		drm_modeset_backoff(ctx);
+
+		ret = drm_modeset_lock_all_ctx(dev, ctx);
+		if (ret)
+			goto retry_locking;
+
+		dev->mode_config.acquire_ctx = ctx;
+
+		goto restart;
+	}
+
+	return ret;
+}
+
 static int vmw_fb_kms_detach(struct vmw_fb_par *par,
 			     bool detach_bo,
 			     bool unref_bo)
@@ -436,7 +490,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
 		set.fb = NULL;
 		set.num_connectors = 0;
 		set.connectors = &par->con;
-		ret = drm_mode_set_config_internal(&set);
+		ret = vmwgfx_set_config_internal(&set);
 		if (ret) {
 			DRM_ERROR("Could not unset a mode.\n");
 			return ret;
@@ -578,7 +632,7 @@ static int vmw_fb_set_par(struct fb_info *info)
 	set.num_connectors = 1;
 	set.connectors = &par->con;
 
-	ret = drm_mode_set_config_internal(&set);
+	ret = vmwgfx_set_config_internal(&set);
 	if (ret)
 		goto out_unlock;