| From 4ed7e2242b637bc4af0416e4aa9f945db30fb44a Mon Sep 17 00:00:00 2001 |
| From: Sinclair Yeh <syeh@vmware.com> |
| Date: Wed, 29 Jun 2016 13:20:26 -0700 |
| Subject: drm/vmwgfx: Check pin count before attempting to move a buffer |
| |
| From: Sinclair Yeh <syeh@vmware.com> |
| |
| commit 4ed7e2242b637bc4af0416e4aa9f945db30fb44a upstream. |
| |
| In certain scenarios, e.g. when fbdev is enabled, we can get into |
| a situation where a vmw_framebuffer_pin() is called on a buffer |
| that is already pinned. |
| |
| When this happens, ttm_bo_validate() will unintentially remove the |
| TTM_PL_FLAG_NO_EVICT flag, thus unpinning it, and leaving no way |
| to actually pin the buffer again. |
| |
| To prevent this, if a buffer is already pinned, then instead of |
| calling ttm_bo_validate(), just make sure the proposed placement is |
| compatible with the existing placement. |
| |
| Signed-off-by: Sinclair Yeh <syeh@vmware.com> |
| Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 25 ++++++++++++++++++++++--- |
| 1 file changed, 22 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c |
| +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c |
| @@ -49,6 +49,7 @@ int vmw_dmabuf_pin_in_placement(struct v |
| { |
| struct ttm_buffer_object *bo = &buf->base; |
| int ret; |
| + uint32_t new_flags; |
| |
| ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); |
| if (unlikely(ret != 0)) |
| @@ -60,7 +61,12 @@ int vmw_dmabuf_pin_in_placement(struct v |
| if (unlikely(ret != 0)) |
| goto err; |
| |
| - ret = ttm_bo_validate(bo, placement, interruptible, false); |
| + if (buf->pin_count > 0) |
| + ret = ttm_bo_mem_compat(placement, &bo->mem, |
| + &new_flags) == true ? 0 : -EINVAL; |
| + else |
| + ret = ttm_bo_validate(bo, placement, interruptible, false); |
| + |
| if (!ret) |
| vmw_bo_pin_reserved(buf, true); |
| |
| @@ -91,6 +97,7 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct |
| { |
| struct ttm_buffer_object *bo = &buf->base; |
| int ret; |
| + uint32_t new_flags; |
| |
| ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); |
| if (unlikely(ret != 0)) |
| @@ -102,6 +109,12 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct |
| if (unlikely(ret != 0)) |
| goto err; |
| |
| + if (buf->pin_count > 0) { |
| + ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem, |
| + &new_flags) == true ? 0 : -EINVAL; |
| + goto out_unreserve; |
| + } |
| + |
| ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, |
| false); |
| if (likely(ret == 0) || ret == -ERESTARTSYS) |
| @@ -161,6 +174,7 @@ int vmw_dmabuf_pin_in_start_of_vram(stru |
| struct ttm_placement placement; |
| struct ttm_place place; |
| int ret = 0; |
| + uint32_t new_flags; |
| |
| place = vmw_vram_placement.placement[0]; |
| place.lpfn = bo->num_pages; |
| @@ -185,10 +199,15 @@ int vmw_dmabuf_pin_in_start_of_vram(stru |
| */ |
| if (bo->mem.mem_type == TTM_PL_VRAM && |
| bo->mem.start < bo->num_pages && |
| - bo->mem.start > 0) |
| + bo->mem.start > 0 && |
| + buf->pin_count == 0) |
| (void) ttm_bo_validate(bo, &vmw_sys_placement, false, false); |
| |
| - ret = ttm_bo_validate(bo, &placement, interruptible, false); |
| + if (buf->pin_count > 0) |
| + ret = ttm_bo_mem_compat(&placement, &bo->mem, |
| + &new_flags) == true ? 0 : -EINVAL; |
| + else |
| + ret = ttm_bo_validate(bo, &placement, interruptible, false); |
| |
| /* For some reason we didn't end up at the start of vram */ |
| WARN_ON(ret == 0 && bo->offset != 0); |