diff options
author | Christian König <deathsimple@vodafone.de> | 2012-09-11 16:10:04 +0200 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-09-20 13:10:42 -0400 |
commit | e971bd5e45764ff76df0ff110a19bf6b924f84d6 (patch) | |
tree | ddbb71c68d5cd1d3d525ba815b5357ef73194c02 /drivers/gpu/drm/radeon/radeon_gart.c | |
parent | d59f70216b7166f03fa732964deafc6453d62eb6 (diff) | |
download | linux-e971bd5e45764ff76df0ff110a19bf6b924f84d6.tar.gz |
drm/radeon: rework the VM code a bit more (v2)
Roughly based on how nouveau is handling it. Instead of
adding the bo_va when the address is set add the bo_va
when the handle is opened, but set the address to zero
until userspace tells us where to place it.
This fixes another bunch of problems with glamor.
v2: agd5f: fix build after dropping patch 7/8.
Signed-off-by: Christian König <deathsimple@vodafone.de>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_gart.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_gart.c | 147 |
1 files changed, 95 insertions, 52 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2c594910064d..2f28ff34c085 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -693,51 +693,83 @@ struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, * @rdev: radeon_device pointer * @vm: requested vm * @bo: radeon buffer object - * @offset: requested offset of the buffer in the VM address space - * @flags: attributes of pages (read/write/valid/etc.) * * Add @bo into the requested vm (cayman+). - * Add @bo to the list of bos associated with the vm and validate - * the offset requested within the vm address space. - * Returns 0 for success, error for failure. + * Add @bo to the list of bos associated with the vm + * Returns newly added bo_va or NULL for failure * * Object has to be reserved! */ -int radeon_vm_bo_add(struct radeon_device *rdev, - struct radeon_vm *vm, - struct radeon_bo *bo, - uint64_t offset, - uint32_t flags) +struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, + struct radeon_vm *vm, + struct radeon_bo *bo) { - struct radeon_bo_va *bo_va, *tmp; - struct list_head *head; - uint64_t size = radeon_bo_size(bo), last_offset = 0; - unsigned last_pfn; + struct radeon_bo_va *bo_va; bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); if (bo_va == NULL) { - return -ENOMEM; + return NULL; } bo_va->vm = vm; bo_va->bo = bo; - bo_va->soffset = offset; - bo_va->eoffset = offset + size; - bo_va->flags = flags; + bo_va->soffset = 0; + bo_va->eoffset = 0; + bo_va->flags = 0; bo_va->valid = false; + bo_va->ref_count = 1; INIT_LIST_HEAD(&bo_va->bo_list); INIT_LIST_HEAD(&bo_va->vm_list); - /* make sure object fit at this offset */ - if (bo_va->soffset >= bo_va->eoffset) { - kfree(bo_va); - return -EINVAL; - } - last_pfn = bo_va->eoffset / RADEON_GPU_PAGE_SIZE; - if (last_pfn > rdev->vm_manager.max_pfn) { - kfree(bo_va); - dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", - last_pfn, rdev->vm_manager.max_pfn); - return -EINVAL; + mutex_lock(&vm->mutex); + list_add(&bo_va->vm_list, &vm->va); + list_add_tail(&bo_va->bo_list, &bo->va); + mutex_unlock(&vm->mutex); + + return bo_va; +} + +/** + * radeon_vm_bo_set_addr - set bos virtual address inside a vm + * + * @rdev: radeon_device pointer + * @bo_va: bo_va to store the address + * @soffset: requested offset of the buffer in the VM address space + * @flags: attributes of pages (read/write/valid/etc.) + * + * Set offset of @bo_va (cayman+). + * Validate and set the offset requested within the vm address space. + * Returns 0 for success, error for failure. + * + * Object has to be reserved! + */ +int radeon_vm_bo_set_addr(struct radeon_device *rdev, + struct radeon_bo_va *bo_va, + uint64_t soffset, + uint32_t flags) +{ + uint64_t size = radeon_bo_size(bo_va->bo); + uint64_t eoffset, last_offset = 0; + struct radeon_vm *vm = bo_va->vm; + struct radeon_bo_va *tmp; + struct list_head *head; + unsigned last_pfn; + + if (soffset) { + /* make sure object fit at this offset */ + eoffset = soffset + size; + if (soffset >= eoffset) { + return -EINVAL; + } + + last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; + if (last_pfn > rdev->vm_manager.max_pfn) { + dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", + last_pfn, rdev->vm_manager.max_pfn); + return -EINVAL; + } + + } else { + eoffset = last_pfn = 0; } mutex_lock(&vm->mutex); @@ -758,24 +790,33 @@ int radeon_vm_bo_add(struct radeon_device *rdev, head = &vm->va; last_offset = 0; list_for_each_entry(tmp, &vm->va, vm_list) { - if (bo_va->soffset >= last_offset && bo_va->eoffset <= tmp->soffset) { + if (bo_va == tmp) { + /* skip over currently modified bo */ + continue; + } + + if (soffset >= last_offset && eoffset <= tmp->soffset) { /* bo can be added before this one */ break; } - if (bo_va->eoffset > tmp->soffset && bo_va->soffset < tmp->eoffset) { + if (eoffset > tmp->soffset && soffset < tmp->eoffset) { /* bo and tmp overlap, invalid offset */ dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", - bo, (unsigned)bo_va->soffset, tmp->bo, + bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, (unsigned)tmp->soffset, (unsigned)tmp->eoffset); - kfree(bo_va); mutex_unlock(&vm->mutex); return -EINVAL; } last_offset = tmp->eoffset; head = &tmp->vm_list; } - list_add(&bo_va->vm_list, head); - list_add_tail(&bo_va->bo_list, &bo->va); + + bo_va->soffset = soffset; + bo_va->eoffset = eoffset; + bo_va->flags = flags; + bo_va->valid = false; + list_move(&bo_va->vm_list, head); + mutex_unlock(&vm->mutex); return 0; } @@ -855,6 +896,12 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, return -EINVAL; } + if (!bo_va->soffset) { + dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", + bo, vm); + return -EINVAL; + } + if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL)) return 0; @@ -921,33 +968,26 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, * radeon_vm_bo_rmv - remove a bo to a specific vm * * @rdev: radeon_device pointer - * @vm: requested vm - * @bo: radeon buffer object + * @bo_va: requested bo_va * - * Remove @bo from the requested vm (cayman+). - * Remove @bo from the list of bos associated with the vm and - * remove the ptes for @bo in the page table. + * Remove @bo_va->bo from the requested vm (cayman+). + * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and + * remove the ptes for @bo_va 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) { - struct radeon_bo_va *bo_va; int r; - bo_va = radeon_vm_bo_find(vm, bo); - if (bo_va == NULL) - return 0; - mutex_lock(&rdev->vm_manager.lock); - mutex_lock(&vm->mutex); - r = radeon_vm_bo_update_pte(rdev, vm, bo, NULL); + mutex_lock(&bo_va->vm->mutex); + r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); mutex_unlock(&rdev->vm_manager.lock); list_del(&bo_va->vm_list); - mutex_unlock(&vm->mutex); + mutex_unlock(&bo_va->vm->mutex); list_del(&bo_va->bo_list); kfree(bo_va); @@ -987,6 +1027,7 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, */ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) { + struct radeon_bo_va *bo_va; int r; vm->id = 0; @@ -1006,8 +1047,10 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) /* map the ib pool buffer at 0 in virtual address space, set * read only */ - r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, RADEON_VA_IB_OFFSET, - RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); + bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); + r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, + RADEON_VM_PAGE_READABLE | + RADEON_VM_PAGE_SNOOPED); return r; } |