drm/radeon: rework VM page table handling
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>
This commit is contained in:
parent
ee60e29f1d
commit
ddf03f5cdd
@ -301,7 +301,6 @@ struct radeon_bo_va {
|
|||||||
uint64_t soffset;
|
uint64_t soffset;
|
||||||
uint64_t eoffset;
|
uint64_t eoffset;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
struct radeon_fence *fence;
|
|
||||||
bool valid;
|
bool valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1832,8 +1831,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev);
|
|||||||
void radeon_vm_manager_fini(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);
|
int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);
|
||||||
void radeon_vm_fini(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);
|
int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm);
|
||||||
void radeon_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
|
|
||||||
struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
|
struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
|
||||||
struct radeon_vm *vm, int ring);
|
struct radeon_vm *vm, int ring);
|
||||||
void radeon_vm_fence(struct radeon_device *rdev,
|
void radeon_vm_fence(struct radeon_device *rdev,
|
||||||
|
@ -286,30 +286,6 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
|
|||||||
return 0;
|
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
|
* cs_parser_fini() - clean parser states
|
||||||
* @parser: parser structure holding parsing context.
|
* @parser: parser structure holding parsing context.
|
||||||
@ -323,8 +299,6 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
|
|||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
if (!error) {
|
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,
|
ttm_eu_fence_buffer_objects(&parser->validated,
|
||||||
parser->ib.fence);
|
parser->ib.fence);
|
||||||
} else {
|
} else {
|
||||||
@ -475,7 +449,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
|
|||||||
|
|
||||||
mutex_lock(&rdev->vm_manager.lock);
|
mutex_lock(&rdev->vm_manager.lock);
|
||||||
mutex_lock(&vm->mutex);
|
mutex_lock(&vm->mutex);
|
||||||
r = radeon_vm_bind(rdev, vm);
|
r = radeon_vm_alloc_pt(rdev, vm);
|
||||||
if (r) {
|
if (r) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -478,43 +478,26 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
|
|||||||
return 0;
|
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
|
* @rdev: radeon_device pointer
|
||||||
* @vm: vm to unbind
|
* @vm: vm to unbind
|
||||||
*
|
*
|
||||||
* Unbind the requested vm (cayman+).
|
* Free the page table of a specific vm (cayman+).
|
||||||
* Wait for use of the VM to finish, then unbind the page table,
|
*
|
||||||
* and free the page table memory.
|
* 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_vm *vm)
|
||||||
{
|
{
|
||||||
struct radeon_bo_va *bo_va;
|
struct radeon_bo_va *bo_va;
|
||||||
|
|
||||||
/* wait for vm use to end */
|
if (!vm->sa_bo)
|
||||||
while (vm->fence) {
|
return;
|
||||||
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);
|
|
||||||
|
|
||||||
/* hw unbind */
|
|
||||||
list_del_init(&vm->list);
|
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;
|
vm->pt = NULL;
|
||||||
|
|
||||||
list_for_each_entry(bo_va, &vm->va, vm_list) {
|
list_for_each_entry(bo_va, &vm->va, vm_list) {
|
||||||
@ -538,9 +521,11 @@ void radeon_vm_manager_fini(struct radeon_device *rdev)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&rdev->vm_manager.lock);
|
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) {
|
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) {
|
for (i = 0; i < RADEON_NUM_VM; ++i) {
|
||||||
radeon_fence_unref(&rdev->vm_manager.active[i]);
|
radeon_fence_unref(&rdev->vm_manager.active[i]);
|
||||||
@ -553,36 +538,19 @@ void radeon_vm_manager_fini(struct radeon_device *rdev)
|
|||||||
rdev->vm_manager.enabled = false;
|
rdev->vm_manager.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global mutex must be locked */
|
|
||||||
/**
|
/**
|
||||||
* radeon_vm_unbind - locked version of unbind
|
* radeon_vm_alloc_pt - allocates a page table for a VM
|
||||||
*
|
|
||||||
* @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
|
|
||||||
*
|
*
|
||||||
* @rdev: radeon_device pointer
|
* @rdev: radeon_device pointer
|
||||||
* @vm: vm to bind
|
* @vm: vm to bind
|
||||||
*
|
*
|
||||||
* Bind the requested vm (cayman+).
|
* Allocate a page table for the requested vm (cayman+).
|
||||||
* Suballocate memory for the page table, allocate a VMID
|
* Also starts to populate the page table.
|
||||||
* and bind the page table to it, and finally start to populate
|
|
||||||
* the page table.
|
|
||||||
* Returns 0 for success, error for failure.
|
* 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;
|
struct radeon_vm *vm_evict;
|
||||||
int r;
|
int r;
|
||||||
@ -602,14 +570,20 @@ retry:
|
|||||||
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo,
|
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_ALIGN(vm->last_pfn * 8),
|
||||||
RADEON_GPU_PAGE_SIZE, false);
|
RADEON_GPU_PAGE_SIZE, false);
|
||||||
if (r) {
|
if (r == -ENOMEM) {
|
||||||
if (list_empty(&rdev->vm_manager.lru_vm)) {
|
if (list_empty(&rdev->vm_manager.lru_vm)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list);
|
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;
|
goto retry;
|
||||||
|
|
||||||
|
} else if (r) {
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
|
vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
|
||||||
vm->pt_gpu_addr = radeon_sa_bo_gpu_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));
|
memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
|
||||||
@ -758,7 +732,7 @@ int radeon_vm_bo_add(struct radeon_device *rdev,
|
|||||||
if (last_pfn > vm->last_pfn) {
|
if (last_pfn > vm->last_pfn) {
|
||||||
/* grow va space 32M by 32M */
|
/* grow va space 32M by 32M */
|
||||||
unsigned align = ((32 << 20) >> 12) - 1;
|
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;
|
vm->last_pfn = (last_pfn + align) & ~align;
|
||||||
}
|
}
|
||||||
mutex_unlock(&rdev->vm_manager.lock);
|
mutex_unlock(&rdev->vm_manager.lock);
|
||||||
@ -886,7 +860,6 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* object have to be reserved */
|
|
||||||
/**
|
/**
|
||||||
* radeon_vm_bo_rmv - remove a bo to a specific vm
|
* radeon_vm_bo_rmv - remove a bo to a specific vm
|
||||||
*
|
*
|
||||||
@ -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 @bo from the list of bos associated with the vm and
|
||||||
* remove the ptes for @bo in the page table.
|
* remove the ptes for @bo in the page table.
|
||||||
* Returns 0 for success.
|
* Returns 0 for success.
|
||||||
|
*
|
||||||
|
* Object have to be reserved!
|
||||||
*/
|
*/
|
||||||
int radeon_vm_bo_rmv(struct radeon_device *rdev,
|
int radeon_vm_bo_rmv(struct radeon_device *rdev,
|
||||||
struct radeon_vm *vm,
|
struct radeon_vm *vm,
|
||||||
struct radeon_bo *bo)
|
struct radeon_bo *bo)
|
||||||
{
|
{
|
||||||
struct radeon_bo_va *bo_va;
|
struct radeon_bo_va *bo_va;
|
||||||
int r;
|
|
||||||
|
|
||||||
bo_va = radeon_bo_va(bo, vm);
|
bo_va = radeon_bo_va(bo, vm);
|
||||||
if (bo_va == NULL)
|
if (bo_va == NULL)
|
||||||
return 0;
|
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(&rdev->vm_manager.lock);
|
||||||
mutex_lock(&vm->mutex);
|
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);
|
mutex_unlock(&rdev->vm_manager.lock);
|
||||||
list_del(&bo_va->vm_list);
|
list_del(&bo_va->vm_list);
|
||||||
mutex_unlock(&vm->mutex);
|
mutex_unlock(&vm->mutex);
|
||||||
@ -1010,7 +969,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
|
|||||||
|
|
||||||
mutex_lock(&rdev->vm_manager.lock);
|
mutex_lock(&rdev->vm_manager.lock);
|
||||||
mutex_lock(&vm->mutex);
|
mutex_lock(&vm->mutex);
|
||||||
radeon_vm_unbind_locked(rdev, vm);
|
radeon_vm_free_pt(rdev, vm);
|
||||||
mutex_unlock(&rdev->vm_manager.lock);
|
mutex_unlock(&rdev->vm_manager.lock);
|
||||||
|
|
||||||
/* remove all bo at this point non are busy any more because unbind
|
/* remove all bo at this point non are busy any more because unbind
|
||||||
@ -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);
|
bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
|
||||||
list_del_init(&bo_va->bo_list);
|
list_del_init(&bo_va->bo_list);
|
||||||
list_del_init(&bo_va->vm_list);
|
list_del_init(&bo_va->vm_list);
|
||||||
radeon_fence_unref(&bo_va->fence);
|
|
||||||
radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
|
radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
|
||||||
kfree(bo_va);
|
kfree(bo_va);
|
||||||
}
|
}
|
||||||
@ -1033,10 +991,11 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
|
|||||||
r = radeon_bo_reserve(bo_va->bo, false);
|
r = radeon_bo_reserve(bo_va->bo, false);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
list_del_init(&bo_va->bo_list);
|
list_del_init(&bo_va->bo_list);
|
||||||
radeon_fence_unref(&bo_va->fence);
|
|
||||||
radeon_bo_unreserve(bo_va->bo);
|
radeon_bo_unreserve(bo_va->bo);
|
||||||
kfree(bo_va);
|
kfree(bo_va);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
radeon_fence_unref(&vm->fence);
|
||||||
|
radeon_fence_unref(&vm->last_flush);
|
||||||
mutex_unlock(&vm->mutex);
|
mutex_unlock(&vm->mutex);
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
|
|||||||
{
|
{
|
||||||
struct radeon_fence *fences[RADEON_NUM_RINGS];
|
struct radeon_fence *fences[RADEON_NUM_RINGS];
|
||||||
unsigned tries[RADEON_NUM_RINGS];
|
unsigned tries[RADEON_NUM_RINGS];
|
||||||
int i, r = -ENOMEM;
|
int i, r;
|
||||||
|
|
||||||
BUG_ON(align > RADEON_GPU_PAGE_SIZE);
|
BUG_ON(align > RADEON_GPU_PAGE_SIZE);
|
||||||
BUG_ON(size > sa_manager->size);
|
BUG_ON(size > sa_manager->size);
|
||||||
@ -331,7 +331,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
|
|||||||
INIT_LIST_HEAD(&(*sa_bo)->flist);
|
INIT_LIST_HEAD(&(*sa_bo)->flist);
|
||||||
|
|
||||||
spin_lock(&sa_manager->wq.lock);
|
spin_lock(&sa_manager->wq.lock);
|
||||||
while(1) {
|
do {
|
||||||
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
|
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
|
||||||
fences[i] = NULL;
|
fences[i] = NULL;
|
||||||
tries[i] = 0;
|
tries[i] = 0;
|
||||||
@ -349,26 +349,22 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
|
|||||||
/* see if we can skip over some allocations */
|
/* see if we can skip over some allocations */
|
||||||
} while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
|
} while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
|
||||||
|
|
||||||
if (!block) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&sa_manager->wq.lock);
|
spin_unlock(&sa_manager->wq.lock);
|
||||||
r = radeon_fence_wait_any(rdev, fences, false);
|
r = radeon_fence_wait_any(rdev, fences, false);
|
||||||
spin_lock(&sa_manager->wq.lock);
|
spin_lock(&sa_manager->wq.lock);
|
||||||
/* if we have nothing to wait for block */
|
/* if we have nothing to wait for block */
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT && block) {
|
||||||
r = wait_event_interruptible_locked(
|
r = wait_event_interruptible_locked(
|
||||||
sa_manager->wq,
|
sa_manager->wq,
|
||||||
radeon_sa_event(sa_manager, size, align)
|
radeon_sa_event(sa_manager, size, align)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
if (r) {
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
out_err:
|
} else if (r == -ENOENT) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (!r);
|
||||||
|
|
||||||
spin_unlock(&sa_manager->wq.lock);
|
spin_unlock(&sa_manager->wq.lock);
|
||||||
kfree(*sa_bo);
|
kfree(*sa_bo);
|
||||||
*sa_bo = NULL;
|
*sa_bo = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user