drm/nouveau/kms: take more care when pulling down accelerated fbcon
authorBen Skeggs <bskeggs@redhat.com>
Sat, 28 Jun 2014 10:44:07 +0000 (20:44 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:11:08 +0000 (05:11 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fbcon.h

index 41be3424c9060d83c555f2ea99719ee5d40468d6..8b17d7d49e26d9536146c2eafa8f737ea3dc7fd3 100644 (file)
@@ -915,9 +915,9 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
        struct drm_device *dev = drm->dev;
 
        if (state == ENTER_ATOMIC_MODE_SET)
-               nouveau_fbcon_save_disable_accel(dev);
+               nouveau_fbcon_accel_save_disable(dev);
        else
-               nouveau_fbcon_restore_accel(dev);
+               nouveau_fbcon_accel_restore(dev);
 
        return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
 }
index 758c11cb9a9a8575218d5b2352b3db94b15ba71e..ba004932435a905c0226a8083b2703b870c6a07c 100644 (file)
@@ -212,6 +212,58 @@ static struct fb_ops nouveau_fbcon_sw_ops = {
        .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
+void
+nouveau_fbcon_accel_save_disable(struct drm_device *dev)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       if (drm->fbcon) {
+               drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
+               drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+       }
+}
+
+void
+nouveau_fbcon_accel_restore(struct drm_device *dev)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       if (drm->fbcon) {
+               drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
+       }
+}
+
+void
+nouveau_fbcon_accel_fini(struct drm_device *dev)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_fbdev *fbcon = drm->fbcon;
+       if (fbcon && drm->channel) {
+               console_lock();
+               fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+               console_unlock();
+               nouveau_channel_idle(drm->channel);
+       }
+}
+
+void
+nouveau_fbcon_accel_init(struct drm_device *dev)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_fbdev *fbcon = drm->fbcon;
+       struct fb_info *info = fbcon->helper.fbdev;
+       int ret;
+
+       if (nv_device(drm->device)->card_type < NV_50)
+               ret = nv04_fbcon_accel_init(info);
+       else
+       if (nv_device(drm->device)->card_type < NV_C0)
+               ret = nv50_fbcon_accel_init(info);
+       else
+               ret = nvc0_fbcon_accel_init(info);
+
+       if (ret == 0)
+               info->fbops = &nouveau_fbcon_ops;
+}
+
 static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
                                    u16 blue, int regno)
 {
@@ -357,20 +409,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
 
        mutex_unlock(&dev->struct_mutex);
 
-       if (chan) {
-               ret = -ENODEV;
-               if (device->card_type < NV_50)
-                       ret = nv04_fbcon_accel_init(info);
-               else
-               if (device->card_type < NV_C0)
-                       ret = nv50_fbcon_accel_init(info);
-               else
-                       ret = nvc0_fbcon_accel_init(info);
-
-               if (ret == 0)
-                       info->fbops = &nouveau_fbcon_ops;
-       }
-
+       if (chan)
+               nouveau_fbcon_accel_init(dev);
        nouveau_fbcon_zfill(dev, fbcon);
 
        /* To allow resizeing without swapping buffers */
@@ -499,30 +539,12 @@ nouveau_fbcon_fini(struct drm_device *dev)
        if (!drm->fbcon)
                return;
 
+       nouveau_fbcon_accel_fini(dev);
        nouveau_fbcon_destroy(dev, drm->fbcon);
        kfree(drm->fbcon);
        drm->fbcon = NULL;
 }
 
-void
-nouveau_fbcon_save_disable_accel(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (drm->fbcon) {
-               drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
-               drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
-       }
-}
-
-void
-nouveau_fbcon_restore_accel(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (drm->fbcon) {
-               drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
-       }
-}
-
 void
 nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
 {
@@ -530,10 +552,10 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
        if (drm->fbcon) {
                console_lock();
                if (state == 1)
-                       nouveau_fbcon_save_disable_accel(dev);
+                       nouveau_fbcon_accel_save_disable(dev);
                fb_set_suspend(drm->fbcon->helper.fbdev, state);
                if (state == 0) {
-                       nouveau_fbcon_restore_accel(dev);
+                       nouveau_fbcon_accel_restore(dev);
                        nouveau_fbcon_zfill(dev, drm->fbcon);
                }
                console_unlock();
index fcff797d208481e4c4a61012647f52f0feec45ed..6d857e2869c9bdfee64232356563da9397cbc66e 100644 (file)
@@ -61,8 +61,8 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info);
 int nouveau_fbcon_init(struct drm_device *dev);
 void nouveau_fbcon_fini(struct drm_device *dev);
 void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
-void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
-void nouveau_fbcon_restore_accel(struct drm_device *dev);
+void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
+void nouveau_fbcon_accel_restore(struct drm_device *dev);
 
 void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
 #endif /* __NV50_FBCON_H__ */