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)
committerThomas Hellstrom <thellstrom@vmware.com>
Thu, 22 Mar 2018 11:08:24 +0000 (12:08 +0100)
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>
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c

index 3b7bf7ca18b9638211da1116f9517a0f5dbd22e8..419185f60278460a0d0b771f1b52cd0db33ef37e 100644 (file)
@@ -405,7 +405,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;
 
@@ -443,10 +447,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;
@@ -456,7 +467,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
@@ -467,13 +477,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);
 }