[PATCH 4/6] drm/ttm: add the infrastructur for pipelined evictions
Alex Deucher
alexdeucher at gmail.com
Wed Jun 15 16:21:16 UTC 2016
On Wed, Jun 15, 2016 at 7:44 AM, Christian König
<deathsimple at vodafone.de> wrote:
> From: Christian König <christian.koenig at amd.com>
>
> Free up the memory immediately, remember the last eviction for each domain and
> make new allocations depend on the last eviction to be completed.
>
> Signed-off-by: Christian König <christian.koenig at amd.com>
Minor typo in the patch title:
s/infrastructur/infrastructure/
Alex
> ---
> drivers/gpu/drm/ttm/ttm_bo.c | 49 ++++++++++++++++++---
> drivers/gpu/drm/ttm/ttm_bo_util.c | 92 +++++++++++++++++++++++++++++++++++++++
> include/drm/ttm/ttm_bo_driver.h | 24 ++++++++++
> 3 files changed, 160 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 28cd535..5d93169 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -788,6 +788,34 @@ void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
> EXPORT_SYMBOL(ttm_bo_mem_put);
>
> /**
> + * Add the last move fence to the BO and reserve a new shared slot.
> + */
> +static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
> + struct ttm_mem_type_manager *man,
> + struct ttm_mem_reg *mem)
> +{
> + struct fence *fence;
> + int ret;
> +
> + spin_lock(&man->move_lock);
> + fence = fence_get(man->move);
> + spin_unlock(&man->move_lock);
> +
> + if (fence) {
> + reservation_object_add_shared_fence(bo->resv, fence);
> +
> + ret = reservation_object_reserve_shared(bo->resv);
> + if (unlikely(ret))
> + return ret;
> +
> + fence_put(bo->moving);
> + bo->moving = fence;
> + }
> +
> + return 0;
> +}
> +
> +/**
> * Repeatedly evict memory from the LRU for @mem_type until we create enough
> * space, or we've evicted everything and there isn't enough space.
> */
> @@ -813,10 +841,8 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
> if (unlikely(ret != 0))
> return ret;
> } while (1);
> - if (mem->mm_node == NULL)
> - return -ENOMEM;
> mem->mem_type = mem_type;
> - return 0;
> + return ttm_bo_add_move_fence(bo, man, mem);
> }
>
> static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man,
> @@ -886,6 +912,10 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
> bool has_erestartsys = false;
> int i, ret;
>
> + ret = reservation_object_reserve_shared(bo->resv);
> + if (unlikely(ret))
> + return ret;
> +
> mem->mm_node = NULL;
> for (i = 0; i < placement->num_placement; ++i) {
> const struct ttm_place *place = &placement->placement[i];
> @@ -919,9 +949,15 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
> ret = (*man->func->get_node)(man, bo, place, mem);
> if (unlikely(ret))
> return ret;
> -
> - if (mem->mm_node)
> +
> + if (mem->mm_node) {
> + ret = ttm_bo_add_move_fence(bo, man, mem);
> + if (unlikely(ret)) {
> + (*man->func->put_node)(man, mem);
> + return ret;
> + }
> break;
> + }
> }
>
> if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || mem->mm_node) {
> @@ -1290,6 +1326,7 @@ int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
> mem_type);
> return ret;
> }
> + fence_put(man->move);
>
> man->use_type = false;
> man->has_type = false;
> @@ -1335,6 +1372,7 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
> man->io_reserve_fastpath = true;
> man->use_io_reserve_lru = false;
> mutex_init(&man->io_reserve_mutex);
> + spin_lock_init(&man->move_lock);
> INIT_LIST_HEAD(&man->io_reserve_lru);
>
> ret = bdev->driver->init_mem_type(bdev, type, man);
> @@ -1353,6 +1391,7 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
> man->size = p_size;
>
> INIT_LIST_HEAD(&man->lru);
> + man->move = NULL;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
> index 9ea8d02..0c389a5 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo_util.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
> @@ -696,3 +696,95 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
> return 0;
> }
> EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
> +
> +int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
> + struct fence *fence, bool evict,
> + struct ttm_mem_reg *new_mem)
> +{
> + struct ttm_bo_device *bdev = bo->bdev;
> + struct ttm_mem_reg *old_mem = &bo->mem;
> +
> + struct ttm_mem_type_manager *from = &bdev->man[old_mem->mem_type];
> + struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type];
> +
> + int ret;
> +
> + reservation_object_add_excl_fence(bo->resv, fence);
> +
> + if (!evict) {
> + struct ttm_buffer_object *ghost_obj;
> +
> + /**
> + * This should help pipeline ordinary buffer moves.
> + *
> + * Hang old buffer memory on a new buffer object,
> + * and leave it to be released when the GPU
> + * operation has completed.
> + */
> +
> + fence_put(bo->moving);
> + bo->moving = fence_get(fence);
> +
> + ret = ttm_buffer_object_transfer(bo, &ghost_obj);
> + if (ret)
> + return ret;
> +
> + reservation_object_add_excl_fence(ghost_obj->resv, fence);
> +
> + /**
> + * If we're not moving to fixed memory, the TTM object
> + * needs to stay alive. Otherwhise hang it on the ghost
> + * bo to be unbound and destroyed.
> + */
> +
> + if (!(to->flags & TTM_MEMTYPE_FLAG_FIXED))
> + ghost_obj->ttm = NULL;
> + else
> + bo->ttm = NULL;
> +
> + ttm_bo_unreserve(ghost_obj);
> + ttm_bo_unref(&ghost_obj);
> +
> + } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) {
> +
> + /**
> + * BO doesn't have a TTM we need to bind/unbind. Just remember
> + * this eviction and free up the allocation
> + */
> +
> + spin_lock(&from->move_lock);
> + if (!from->move || fence_is_later(from->move, fence)) {
> + fence_put(from->move);
> + from->move = fence_get(fence);
> + }
> + spin_unlock(&from->move_lock);
> +
> + ttm_bo_free_old_node(bo);
> +
> + fence_put(bo->moving);
> + bo->moving = fence_get(fence);
> +
> + } else {
> + /**
> + * Last resort, wait for the move to be completed.
> + *
> + * Should never happen in pratice.
> + */
> +
> + ret = ttm_bo_wait(bo, false, false);
> + if (ret)
> + return ret;
> +
> + if (to->flags & TTM_MEMTYPE_FLAG_FIXED) {
> + ttm_tt_destroy(bo->ttm);
> + bo->ttm = NULL;
> + }
> + ttm_bo_free_old_node(bo);
> + }
> +
> + *old_mem = *new_mem;
> + new_mem->mm_node = NULL;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(ttm_bo_pipeline_move);
> diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
> index 44dea22..e2ebe66 100644
> --- a/include/drm/ttm/ttm_bo_driver.h
> +++ b/include/drm/ttm/ttm_bo_driver.h
> @@ -258,8 +258,10 @@ struct ttm_mem_type_manager_func {
> * reserved by the TTM vm system.
> * @io_reserve_lru: Optional lru list for unreserving io mem regions.
> * @io_reserve_fastpath: Only use bdev::driver::io_mem_reserve to obtain
> + * @move_lock: lock for move fence
> * static information. bdev::driver::io_mem_free is never used.
> * @lru: The lru list for this memory type.
> + * @move: The fence of the last pipelined move operation.
> *
> * This structure is used to identify and manage memory types for a device.
> * It's set up by the ttm_bo_driver::init_mem_type method.
> @@ -286,6 +288,7 @@ struct ttm_mem_type_manager {
> struct mutex io_reserve_mutex;
> bool use_io_reserve_lru;
> bool io_reserve_fastpath;
> + spinlock_t move_lock;
>
> /*
> * Protected by @io_reserve_mutex:
> @@ -298,6 +301,11 @@ struct ttm_mem_type_manager {
> */
>
> struct list_head lru;
> +
> + /*
> + * Protected by @move_lock.
> + */
> + struct fence *move;
> };
>
> /**
> @@ -1014,6 +1022,22 @@ extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
> extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
> struct fence *fence, bool evict,
> struct ttm_mem_reg *new_mem);
> +
> +/**
> + * ttm_bo_pipeline_move.
> + *
> + * @bo: A pointer to a struct ttm_buffer_object.
> + * @fence: A fence object that signals when moving is complete.
> + * @evict: This is an evict move. Don't return until the buffer is idle.
> + * @new_mem: struct ttm_mem_reg indicating where to move.
> + *
> + * Function for pipelining accelerated moves. Either free the memory
> + * immediately or hang it on a temporary buffer object.
> + */
> +int ttm_bo_pipeline_move(struct ttm_buffer_object *bo,
> + struct fence *fence, bool evict,
> + struct ttm_mem_reg *new_mem);
> +
> /**
> * ttm_io_prot
> *
> --
> 2.5.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list