drm/amdgpu: prevent command submission failures under memory pressure v2

As last resort try to evict BOs from the current working set into other
memory domains. This effectively prevents command submission failures when
VM page tables have been swapped out.

v2: fix typos

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Christian König 2016-09-01 12:13:18 +02:00 committed by Alex Deucher
parent 1abdc3d73d
commit 662bfa61ff
2 changed files with 63 additions and 1 deletions

View File

@ -1225,6 +1225,7 @@ struct amdgpu_cs_parser {
struct fence *fence;
uint64_t bytes_moved_threshold;
uint64_t bytes_moved;
struct amdgpu_bo_list_entry *evictable;
/* user fence */
struct amdgpu_bo_list_entry uf_entry;

View File

@ -379,6 +379,58 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
return r;
}
/* Last resort, try to evict something from the current working set */
static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,
struct amdgpu_bo_list_entry *lobj)
{
uint32_t domain = lobj->robj->allowed_domains;
int r;
if (!p->evictable)
return false;
for (;&p->evictable->tv.head != &p->validated;
p->evictable = list_prev_entry(p->evictable, tv.head)) {
struct amdgpu_bo_list_entry *candidate = p->evictable;
struct amdgpu_bo *bo = candidate->robj;
u64 initial_bytes_moved;
uint32_t other;
/* If we reached our current BO we can forget it */
if (candidate == lobj)
break;
other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
/* Check if this BO is in one of the domains we need space for */
if (!(other & domain))
continue;
/* Check if we can move this BO somewhere else */
other = bo->allowed_domains & ~domain;
if (!other)
continue;
/* Good we can try to move this BO somewhere else */
amdgpu_ttm_placement_from_domain(bo, other);
initial_bytes_moved = atomic64_read(&bo->adev->num_bytes_moved);
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
p->bytes_moved += atomic64_read(&bo->adev->num_bytes_moved) -
initial_bytes_moved;
if (unlikely(r))
break;
p->evictable = list_prev_entry(p->evictable, tv.head);
list_move(&candidate->tv.head, &p->validated);
return true;
}
return false;
}
int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
struct list_head *validated)
{
@ -403,9 +455,15 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
binding_userptr = true;
}
r = amdgpu_cs_bo_validate(p, bo);
if (p->evictable == lobj)
p->evictable = NULL;
do {
r = amdgpu_cs_bo_validate(p, bo);
} while (r == -ENOMEM && amdgpu_cs_try_evict(p, lobj));
if (r)
return r;
if (bo->shadow) {
r = amdgpu_cs_bo_validate(p, bo);
if (r)
@ -533,6 +591,9 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
p->bytes_moved_threshold = amdgpu_cs_get_threshold_for_moves(p->adev);
p->bytes_moved = 0;
p->evictable = list_last_entry(&p->validated,
struct amdgpu_bo_list_entry,
tv.head);
r = amdgpu_cs_list_validate(p, &duplicates);
if (r) {