diff options
author | Sinclair Yeh <syeh@vmware.com> | 2016-06-29 13:20:26 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-07-27 09:47:35 -0700 |
commit | e587d4e630827c5207ee15986fc83e29d78073c9 (patch) | |
tree | 9d33f9b0e38f4a3165e642af20e8ba3ceaa78b76 /drivers | |
parent | b40c9ac7286e6a5578649098861c7bfcd40451de (diff) | |
download | lwn-e587d4e630827c5207ee15986fc83e29d78073c9.tar.gz lwn-e587d4e630827c5207ee15986fc83e29d78073c9.zip |
drm/vmwgfx: Check pin count before attempting to move a buffer
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 299925a1f6c6..eadc981ee79a 100644 --- 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 vmw_private *dev_priv, { 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 vmw_private *dev_priv, 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 vmw_private *dev_priv, { 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 vmw_private *dev_priv, 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(struct vmw_private *dev_priv, 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(struct vmw_private *dev_priv, */ 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); |