From ed93394c14ba50e3e53ef289116625f0f05f8616 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2015 23:26:06 -0800 Subject: [PATCH] drm/vmwgfx: Add an interface to pin a resource v3 For screen targets it appears we need to pin surfaces while they are bound as screen targets, so add a small interface to do that. v2: Always increase pin_count on pin. v3: Add missing reservation sem. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 91 +++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 8fd40c6bad06..338dce3607fb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -113,6 +113,7 @@ struct vmw_resource { bool backup_dirty; /* Protected by backup buffer reserved */ struct vmw_dma_buffer *backup; unsigned long backup_offset; + unsigned long pin_count; /* Protected by resource reserved */ const struct vmw_res_func *func; struct list_head lru_head; /* Protected by the resource lock */ struct list_head mob_head; /* Protected by @backup reserved */ @@ -941,6 +942,9 @@ int vmw_dumb_map_offset(struct drm_file *file_priv, int vmw_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle); +extern int vmw_resource_pin(struct vmw_resource *res); +extern void vmw_resource_unpin(struct vmw_resource *res); + /** * Overlay control - vmwgfx_overlay.c */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 3fd80701771a..6738c1ebf09a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1183,7 +1183,7 @@ void vmw_resource_unreserve(struct vmw_resource *res, if (new_backup) res->backup_offset = new_backup_offset; - if (!res->func->may_evict || res->id == -1) + if (!res->func->may_evict || res->id == -1 || res->pin_count) return; write_lock(&dev_priv->resource_lock); @@ -1573,3 +1573,92 @@ void vmw_resource_evict_all(struct vmw_private *dev_priv) mutex_unlock(&dev_priv->cmdbuf_mutex); } + +/** + * vmw_resource_pin - Add a pin reference on a resource + * + * @res: The resource to add a pin reference on + * + * This function adds a pin reference, and if needed validates the resource. + * Having a pin reference means that the resource can never be evicted, and + * its id will never change as long as there is a pin reference. + * This function returns 0 on success and a negative error code on failure. + */ +int vmw_resource_pin(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + int ret; + + ttm_write_lock(&dev_priv->reservation_sem, false); + mutex_lock(&dev_priv->cmdbuf_mutex); + ret = vmw_resource_reserve(res, false); + if (ret) + goto out_no_reserve; + + if (res->pin_count == 0) { + struct ttm_buffer_object *bo = NULL; + + if (res->backup) { + bo = &res->backup->base; + + ttm_bo_reserve(bo, false, false, false, NULL); + ret = ttm_bo_validate(bo, res->func->backup_placement, + false, false); + if (ret) { + ttm_bo_unreserve(bo); + goto out_no_validate; + } + + /* Do we really need to pin the MOB as well? */ + vmw_bo_pin(bo, true); + } + ret = vmw_resource_validate(res); + if (bo) + ttm_bo_unreserve(bo); + if (ret) + goto out_no_validate; + } + res->pin_count++; + +out_no_validate: + vmw_resource_unreserve(res, NULL, 0UL); +out_no_reserve: + mutex_unlock(&dev_priv->cmdbuf_mutex); + ttm_write_unlock(&dev_priv->reservation_sem); + + return ret; +} + +/** + * vmw_resource_unpin - Remove a pin reference from a resource + * + * @res: The resource to remove a pin reference from + * + * Having a pin reference means that the resource can never be evicted, and + * its id will never change as long as there is a pin reference. + */ +void vmw_resource_unpin(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + int ret; + + ttm_read_lock(&dev_priv->reservation_sem, false); + mutex_lock(&dev_priv->cmdbuf_mutex); + + ret = vmw_resource_reserve(res, true); + WARN_ON(ret); + + WARN_ON(res->pin_count == 0); + if (--res->pin_count == 0 && res->backup) { + struct ttm_buffer_object *bo = &res->backup->base; + + ttm_bo_reserve(bo, false, false, false, NULL); + vmw_bo_pin(bo, false); + ttm_bo_unreserve(bo); + } + + vmw_resource_unreserve(res, NULL, 0UL); + + mutex_unlock(&dev_priv->cmdbuf_mutex); + ttm_read_unlock(&dev_priv->reservation_sem); +} -- 2.25.1