mirror of https://gitee.com/openkylin/linux.git
drm/vmwgfx: Check pin count before attempting to move a buffer
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> Cc: <stable@vger.kernel.org> --- This is the 2nd patch in a 3-patch series to fix a console black screen issue on Ubuntu 16.04 server. This fixes a BUG_ON() condition where a pinned buffer gets accidentally put onto the LRU list.
This commit is contained in:
parent
94477bff39
commit
4ed7e2242b
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue