drm/vmwgfx: Unpin the screen object backup buffer when not used
authorThomas Hellstrom <thellstrom@vmware.com>
Thu, 22 Mar 2018 09:35:18 +0000 (10:35 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 May 2018 05:52:30 +0000 (07:52 +0200)
[ Upstream commit 20fb5a635a0c8478ac98f15cfafc2ea83df29565 ]

We were relying on the pinned screen object backup buffer to be destroyed
when not used. But if we hold a copy of the atomic state, like when
hibernating, the backup buffer might not be destroyed since it's
refcounted by the atomic state. This causes us to hibernate with a
buffer pinned in VRAM.

Fix this by only having the buffer pinned when it is actually used by a
screen object.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c

index aacce47..7fae4bb 100644 (file)
@@ -453,7 +453,11 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
                                 struct drm_plane_state *old_state)
 {
        struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
+       struct drm_crtc *crtc = plane->state->crtc ?
+               plane->state->crtc : old_state->crtc;
 
+       if (vps->dmabuf)
+               vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false);
        vmw_dmabuf_unreference(&vps->dmabuf);
        vps->dmabuf_size = 0;
 
@@ -491,10 +495,17 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
        }
 
        size = new_state->crtc_w * new_state->crtc_h * 4;
+       dev_priv = vmw_priv(crtc->dev);
 
        if (vps->dmabuf) {
-               if (vps->dmabuf_size == size)
-                       return 0;
+               if (vps->dmabuf_size == size) {
+                       /*
+                        * Note that this might temporarily up the pin-count
+                        * to 2, until cleanup_fb() is called.
+                        */
+                       return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf,
+                                                     true);
+               }
 
                vmw_dmabuf_unreference(&vps->dmabuf);
                vps->dmabuf_size = 0;
@@ -504,7 +515,6 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
        if (!vps->dmabuf)
                return -ENOMEM;
 
-       dev_priv = vmw_priv(crtc->dev);
        vmw_svga_enable(dev_priv);
 
        /* After we have alloced the backing store might not be able to
@@ -515,13 +525,16 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
                              &vmw_vram_ne_placement,
                              false, &vmw_dmabuf_bo_free);
        vmw_overlay_resume_all(dev_priv);
-
-       if (ret != 0)
+       if (ret) {
                vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */
-       else
-               vps->dmabuf_size = size;
+               return ret;
+       }
 
-       return ret;
+       /*
+        * TTM already thinks the buffer is pinned, but make sure the
+        * pin_count is upped.
+        */
+       return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true);
 }