Skip to content

Commit

Permalink
drm/radeon: rework VM page table handling
Browse files Browse the repository at this point in the history
Removing the need to wait for anything.

Still not ideal, since we need to free pt on va remove.

Signed-off-by: Christian König <deathsimple@vodafone.de>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
  • Loading branch information
Christian König authored and Alex Deucher committed Sep 20, 2012
1 parent ee60e29 commit ddf03f5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 116 deletions.
4 changes: 1 addition & 3 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ struct radeon_bo_va {
uint64_t soffset;
uint64_t eoffset;
uint32_t flags;
struct radeon_fence *fence;
bool valid;
};

Expand Down Expand Up @@ -1832,8 +1831,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev);
void radeon_vm_manager_fini(struct radeon_device *rdev);
int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);
void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm);
int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm);
void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm);
struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
struct radeon_vm *vm, int ring);
void radeon_vm_fence(struct radeon_device *rdev,
Expand Down
28 changes: 1 addition & 27 deletions drivers/gpu/drm/radeon/radeon_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,30 +286,6 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
return 0;
}

static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser,
struct radeon_fence *fence)
{
struct radeon_fpriv *fpriv = parser->filp->driver_priv;
struct radeon_vm *vm = &fpriv->vm;
struct radeon_bo_list *lobj;

if (parser->chunk_ib_idx == -1) {
return;
}
if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) {
return;
}

list_for_each_entry(lobj, &parser->validated, tv.head) {
struct radeon_bo_va *bo_va;
struct radeon_bo *rbo = lobj->bo;

bo_va = radeon_bo_va(rbo, vm);
radeon_fence_unref(&bo_va->fence);
bo_va->fence = radeon_fence_ref(fence);
}
}

/**
* cs_parser_fini() - clean parser states
* @parser: parser structure holding parsing context.
Expand All @@ -323,8 +299,6 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
unsigned i;

if (!error) {
/* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */
radeon_bo_vm_fence_va(parser, parser->ib.fence);
ttm_eu_fence_buffer_objects(&parser->validated,
parser->ib.fence);
} else {
Expand Down Expand Up @@ -475,7 +449,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,

mutex_lock(&rdev->vm_manager.lock);
mutex_lock(&vm->mutex);
r = radeon_vm_bind(rdev, vm);
r = radeon_vm_alloc_pt(rdev, vm);
if (r) {
goto out;
}
Expand Down
107 changes: 33 additions & 74 deletions drivers/gpu/drm/radeon/radeon_gart.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,43 +478,26 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
return 0;
}

/* global mutex must be lock */
/**
* radeon_vm_unbind_locked - unbind a specific vm
* radeon_vm_free_pt - free the page table for a specific vm
*
* @rdev: radeon_device pointer
* @vm: vm to unbind
*
* Unbind the requested vm (cayman+).
* Wait for use of the VM to finish, then unbind the page table,
* and free the page table memory.
* Free the page table of a specific vm (cayman+).
*
* Global and local mutex must be lock!
*/
static void radeon_vm_unbind_locked(struct radeon_device *rdev,
static void radeon_vm_free_pt(struct radeon_device *rdev,
struct radeon_vm *vm)
{
struct radeon_bo_va *bo_va;

/* wait for vm use to end */
while (vm->fence) {
int r;
r = radeon_fence_wait(vm->fence, false);
if (r)
DRM_ERROR("error while waiting for fence: %d\n", r);
if (r == -EDEADLK) {
mutex_unlock(&rdev->vm_manager.lock);
r = radeon_gpu_reset(rdev);
mutex_lock(&rdev->vm_manager.lock);
if (!r)
continue;
}
break;
}
radeon_fence_unref(&vm->fence);
radeon_fence_unref(&vm->last_flush);
if (!vm->sa_bo)
return;

/* hw unbind */
list_del_init(&vm->list);
radeon_sa_bo_free(rdev, &vm->sa_bo, NULL);
radeon_sa_bo_free(rdev, &vm->sa_bo, vm->fence);
vm->pt = NULL;

list_for_each_entry(bo_va, &vm->va, vm_list) {
Expand All @@ -538,9 +521,11 @@ void radeon_vm_manager_fini(struct radeon_device *rdev)
return;

mutex_lock(&rdev->vm_manager.lock);
/* unbind all active vm */
/* free all allocated page tables */
list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) {
radeon_vm_unbind_locked(rdev, vm);
mutex_lock(&vm->mutex);
radeon_vm_free_pt(rdev, vm);
mutex_unlock(&vm->mutex);
}
for (i = 0; i < RADEON_NUM_VM; ++i) {
radeon_fence_unref(&rdev->vm_manager.active[i]);
Expand All @@ -553,36 +538,19 @@ void radeon_vm_manager_fini(struct radeon_device *rdev)
rdev->vm_manager.enabled = false;
}

/* global mutex must be locked */
/**
* radeon_vm_unbind - locked version of unbind
*
* @rdev: radeon_device pointer
* @vm: vm to unbind
*
* Locked version that wraps radeon_vm_unbind_locked (cayman+).
*/
void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm)
{
mutex_lock(&vm->mutex);
radeon_vm_unbind_locked(rdev, vm);
mutex_unlock(&vm->mutex);
}

/* global and local mutex must be locked */
/**
* radeon_vm_bind - bind a page table to a VMID
* radeon_vm_alloc_pt - allocates a page table for a VM
*
* @rdev: radeon_device pointer
* @vm: vm to bind
*
* Bind the requested vm (cayman+).
* Suballocate memory for the page table, allocate a VMID
* and bind the page table to it, and finally start to populate
* the page table.
* Allocate a page table for the requested vm (cayman+).
* Also starts to populate the page table.
* Returns 0 for success, error for failure.
*
* Global and local mutex must be locked!
*/
int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm)
int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
{
struct radeon_vm *vm_evict;
int r;
Expand All @@ -602,14 +570,20 @@ int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm)
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo,
RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8),
RADEON_GPU_PAGE_SIZE, false);
if (r) {
if (r == -ENOMEM) {
if (list_empty(&rdev->vm_manager.lru_vm)) {
return r;
}
vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list);
radeon_vm_unbind(rdev, vm_evict);
mutex_lock(&vm_evict->mutex);
radeon_vm_free_pt(rdev, vm_evict);
mutex_unlock(&vm_evict->mutex);
goto retry;

} else if (r) {
return r;
}

vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo);
memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
Expand Down Expand Up @@ -758,7 +732,7 @@ int radeon_vm_bo_add(struct radeon_device *rdev,
if (last_pfn > vm->last_pfn) {
/* grow va space 32M by 32M */
unsigned align = ((32 << 20) >> 12) - 1;
radeon_vm_unbind_locked(rdev, vm);
radeon_vm_free_pt(rdev, vm);
vm->last_pfn = (last_pfn + align) & ~align;
}
mutex_unlock(&rdev->vm_manager.lock);
Expand Down Expand Up @@ -886,7 +860,6 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
return 0;
}

/* object have to be reserved */
/**
* radeon_vm_bo_rmv - remove a bo to a specific vm
*
Expand All @@ -898,36 +871,22 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
* Remove @bo from the list of bos associated with the vm and
* remove the ptes for @bo in the page table.
* Returns 0 for success.
*
* Object have to be reserved!
*/
int radeon_vm_bo_rmv(struct radeon_device *rdev,
struct radeon_vm *vm,
struct radeon_bo *bo)
{
struct radeon_bo_va *bo_va;
int r;

bo_va = radeon_bo_va(bo, vm);
if (bo_va == NULL)
return 0;

/* wait for va use to end */
while (bo_va->fence) {
r = radeon_fence_wait(bo_va->fence, false);
if (r) {
DRM_ERROR("error while waiting for fence: %d\n", r);
}
if (r == -EDEADLK) {
r = radeon_gpu_reset(rdev);
if (!r)
continue;
}
break;
}
radeon_fence_unref(&bo_va->fence);

mutex_lock(&rdev->vm_manager.lock);
mutex_lock(&vm->mutex);
radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
radeon_vm_free_pt(rdev, vm);
mutex_unlock(&rdev->vm_manager.lock);
list_del(&bo_va->vm_list);
mutex_unlock(&vm->mutex);
Expand Down Expand Up @@ -1010,7 +969,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)

mutex_lock(&rdev->vm_manager.lock);
mutex_lock(&vm->mutex);
radeon_vm_unbind_locked(rdev, vm);
radeon_vm_free_pt(rdev, vm);
mutex_unlock(&rdev->vm_manager.lock);

/* remove all bo at this point non are busy any more because unbind
Expand All @@ -1021,7 +980,6 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
list_del_init(&bo_va->bo_list);
list_del_init(&bo_va->vm_list);
radeon_fence_unref(&bo_va->fence);
radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
kfree(bo_va);
}
Expand All @@ -1033,10 +991,11 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
r = radeon_bo_reserve(bo_va->bo, false);
if (!r) {
list_del_init(&bo_va->bo_list);
radeon_fence_unref(&bo_va->fence);
radeon_bo_unreserve(bo_va->bo);
kfree(bo_va);
}
}
radeon_fence_unref(&vm->fence);
radeon_fence_unref(&vm->last_flush);
mutex_unlock(&vm->mutex);
}
20 changes: 8 additions & 12 deletions drivers/gpu/drm/radeon/radeon_sa.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
{
struct radeon_fence *fences[RADEON_NUM_RINGS];
unsigned tries[RADEON_NUM_RINGS];
int i, r = -ENOMEM;
int i, r;

BUG_ON(align > RADEON_GPU_PAGE_SIZE);
BUG_ON(size > sa_manager->size);
Expand All @@ -331,7 +331,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
INIT_LIST_HEAD(&(*sa_bo)->flist);

spin_lock(&sa_manager->wq.lock);
while(1) {
do {
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
fences[i] = NULL;
tries[i] = 0;
Expand All @@ -349,26 +349,22 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
/* see if we can skip over some allocations */
} while (radeon_sa_bo_next_hole(sa_manager, fences, tries));

if (!block) {
break;
}

spin_unlock(&sa_manager->wq.lock);
r = radeon_fence_wait_any(rdev, fences, false);
spin_lock(&sa_manager->wq.lock);
/* if we have nothing to wait for block */
if (r == -ENOENT) {
if (r == -ENOENT && block) {
r = wait_event_interruptible_locked(
sa_manager->wq,
radeon_sa_event(sa_manager, size, align)
);

} else if (r == -ENOENT) {
r = -ENOMEM;
}
if (r) {
goto out_err;
}
};

out_err:
} while (!r);

spin_unlock(&sa_manager->wq.lock);
kfree(*sa_bo);
*sa_bo = NULL;
Expand Down

0 comments on commit ddf03f5

Please sign in to comment.