[PATCH] drm/radeon: fence virtual address and free it once idle v3

Christian König deathsimple at vodafone.de
Mon Aug 6 09:06:00 PDT 2012


On 04.08.2012 11:07, Christian König wrote:
> On 03.08.2012 23:26, j.glisse at gmail.com wrote:
>> From: Jerome Glisse <jglisse at redhat.com>
>>
>> Virtual address need to be fenced to know when we can safely remove it.
>> This patch also properly clear the pagetable. Previously it was
>> serouisly broken.
>>
>> Kernel 3.5/3.4 need a similar patch but adapted for difference in 
>> mutex locking.
>>
>> v2: For to update pagetable when unbinding bo (don't bailout if
>>      bo_va->valid is true).
>> v3: Add kernel 3.5/3.4 comment.
>>
>> Signed-off-by: Jerome Glisse <jglisse at redhat.com>
> It should fix the problem, going to test it as soon as I find some 
> 5min spare in my vacation. Till then it is:
>
> Reviewed-by: Christian König <christian.koenig at amd.com>
>
> In the future I would really like to make the updating of the PTE also 
> async, that should save us allot of problems here.

Had time today to test that a bit more. Found two minor notes in the 
patch, see below.

>
>
>> ---
>>   drivers/gpu/drm/radeon/radeon.h        |    1 +
>>   drivers/gpu/drm/radeon/radeon_cs.c     |   32 
>> +++++++++++++++++++++++++++++---
>>   drivers/gpu/drm/radeon/radeon_gart.c   |   24 ++++++++++++++++++++++--
>>   drivers/gpu/drm/radeon/radeon_gem.c    |   13 ++-----------
>>   drivers/gpu/drm/radeon/radeon_object.c |    6 +-----
>>   5 files changed, 55 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/radeon/radeon.h 
>> b/drivers/gpu/drm/radeon/radeon.h
>> index 5431af2..8d75c65 100644
>> --- a/drivers/gpu/drm/radeon/radeon.h
>> +++ b/drivers/gpu/drm/radeon/radeon.h
>> @@ -300,6 +300,7 @@ struct radeon_bo_va {
>>       uint64_t            soffset;
>>       uint64_t            eoffset;
>>       uint32_t            flags;
>> +    struct radeon_fence        *fence;
>>       bool                valid;
>>   };
>>   diff --git a/drivers/gpu/drm/radeon/radeon_cs.c 
>> b/drivers/gpu/drm/radeon/radeon_cs.c
>> index 8a4c49e..995f3ab 100644
>> --- a/drivers/gpu/drm/radeon/radeon_cs.c
>> +++ b/drivers/gpu/drm/radeon/radeon_cs.c
>> @@ -278,6 +278,30 @@ 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;

>> +    int r;
"r" is unused here, please remove.

>> +
>> +    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);
>> +    }

>> +    return 0;
The function doesn't return an error value, so this should just be a 
"return" without value.

>> +}
>> +
>>   /**
>>    * cs_parser_fini() - clean parser states
>>    * @parser:    parser structure holding parsing context.
>> @@ -290,11 +314,14 @@ static void radeon_cs_parser_fini(struct 
>> radeon_cs_parser *parser, int error)
>>   {
>>       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,
>>                           parser->ib.fence);
>> -    else
>> +    } else {
>>           ttm_eu_backoff_reservation(&parser->validated);
>> +    }
>>         if (parser->relocs != NULL) {
>>           for (i = 0; i < parser->nrelocs; i++) {
>> @@ -388,7 +415,6 @@ static int radeon_cs_ib_vm_chunk(struct 
>> radeon_device *rdev,
>>         if (parser->chunk_ib_idx == -1)
>>           return 0;
>> -
>>       if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
>>           return 0;
>>   diff --git a/drivers/gpu/drm/radeon/radeon_gart.c 
>> b/drivers/gpu/drm/radeon/radeon_gart.c
>> index b372005..9912182 100644
>> --- a/drivers/gpu/drm/radeon/radeon_gart.c
>> +++ b/drivers/gpu/drm/radeon/radeon_gart.c
>> @@ -814,7 +814,7 @@ int radeon_vm_bo_update_pte(struct radeon_device 
>> *rdev,
>>           return -EINVAL;
>>       }
>>   -    if (bo_va->valid)
>> +    if (bo_va->valid && mem)
>>           return 0;
>>         ngpu_pages = radeon_bo_ngpu_pages(bo);
>> @@ -859,11 +859,27 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
>>                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);
>> @@ -952,12 +968,15 @@ void radeon_vm_fini(struct radeon_device *rdev, 
>> struct radeon_vm *vm)
>>       radeon_vm_unbind_locked(rdev, vm);
>>       mutex_unlock(&rdev->vm_manager.lock);
>>   -    /* remove all bo */
>> +    /* remove all bo at this point non are busy any more because unbind
>> +     * waited for the last vm fence to signal
>> +     */
>>       r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
>>       if (!r) {
>>           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);
>>       }
>> @@ -969,6 +988,7 @@ 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);
>>           }
>> diff --git a/drivers/gpu/drm/radeon/radeon_gem.c 
>> b/drivers/gpu/drm/radeon/radeon_gem.c
>> index 84d0452..1b57b00 100644
>> --- a/drivers/gpu/drm/radeon/radeon_gem.c
>> +++ b/drivers/gpu/drm/radeon/radeon_gem.c
>> @@ -134,25 +134,16 @@ void radeon_gem_object_close(struct 
>> drm_gem_object *obj,
>>       struct radeon_device *rdev = rbo->rdev;
>>       struct radeon_fpriv *fpriv = file_priv->driver_priv;
>>       struct radeon_vm *vm = &fpriv->vm;
>> -    struct radeon_bo_va *bo_va, *tmp;
>>         if (rdev->family < CHIP_CAYMAN) {
>>           return;
>>       }
>>         if (radeon_bo_reserve(rbo, false)) {
>> +        dev_err(rdev->dev, "leaking bo va because we fail to reserve 
>> bo\n");
>>           return;
>>       }
>> -    list_for_each_entry_safe(bo_va, tmp, &rbo->va, bo_list) {
>> -        if (bo_va->vm == vm) {
>> -            /* remove from this vm address space */
>> -            mutex_lock(&vm->mutex);
>> -            list_del(&bo_va->vm_list);
>> -            mutex_unlock(&vm->mutex);
>> -            list_del(&bo_va->bo_list);
>> -            kfree(bo_va);
>> -        }
>> -    }
>> +    radeon_vm_bo_rmv(rdev, vm, rbo);
>>       radeon_bo_unreserve(rbo);
>>   }
>>   diff --git a/drivers/gpu/drm/radeon/radeon_object.c 
>> b/drivers/gpu/drm/radeon/radeon_object.c
>> index 1f1a4c8..1cb014b 100644
>> --- a/drivers/gpu/drm/radeon/radeon_object.c
>> +++ b/drivers/gpu/drm/radeon/radeon_object.c
>> @@ -52,11 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo)
>>         list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) {
>>           /* remove from all vm address space */
>> -        mutex_lock(&bo_va->vm->mutex);
>> -        list_del(&bo_va->vm_list);
>> -        mutex_unlock(&bo_va->vm->mutex);
>> -        list_del(&bo_va->bo_list);
>> -        kfree(bo_va);
>> +        radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo);
>>       }
>>   }
>

Additional to that patch we still need a minor fix to mesa (just move 
freeing the VM range after closing the handle). Going to send that in 
the next minute to the mesa-dev list.

Otherwise the patch indeed fixes the problem, but also isn't the best 
idea for performance.

Cheers,
Christian.



More information about the dri-devel mailing list