drm/vmwgfx: Fix fbdev emulation using legacy functions
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 6 Apr 2017 20:02:56 +0000 (22:02 +0200)
committerSean Paul <seanpaul@chromium.org>
Fri, 7 Apr 2017 17:28:32 +0000 (13:28 -0400)
I've broken this by removing the backoff handling from the
set_config2atomic helper in

commit 38b6441e4e75c0b319cfe4d9364c1059fc1e3c2b
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Wed Mar 22 22:50:58 2017 +0100

    drm/atomic-helper: Remove the backoff hack from set_config

Fixing this properly would mean we get to wire the acquire_ctx all the
way through vmwgfx fbdev code, and doing the same was tricky for the
shared fbdev layer. Probably much better to look into refactoring the
entire code to use the helpers, but since that's not a viable
long-term solution fix the issue by open-coding a vmwgfx version of
set_config, that does the legacy backoff dance internally.

Note: Just compile-tested. The idea is to take
drm_mode_set_config_internal(), remove the "is this a legacy driver"
check, and whack the drm_atomic_legacy_backoff trickery at the end.
Since drm_atomic_legacy_backoff is for atomic commits only we need to
open-code it.

Cc: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170406200256.26040-1-daniel.vetter@ffwll.ch
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c

index 09e120d50e6551f70801d376ace6771ac406b606..6f4cb4678cbcc4d917f7ec1739f93ba3e4ae21cd 100644 (file)
@@ -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;