]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
drm/radeon: fence virtual address and free it once idle v4
authorJerome Glisse <jglisse@redhat.com>
Mon, 6 Aug 2012 16:32:21 +0000 (12:32 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Oct 2012 17:39:40 +0000 (10:39 -0700)
commit e43b5ec05afdc232be25aa481315035c1888d389 upstream.

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.
v4: Fix compilation warnings.

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_object.c

index fefcca55c1eb8bb76c7611cc0f38e5f04fe47765..01d2a8727456103cfac00370369382fb386da560 100644 (file)
@@ -323,6 +323,7 @@ struct radeon_bo_va {
        uint64_t                        soffset;
        uint64_t                        eoffset;
        uint32_t                        flags;
+       struct radeon_fence             *fence;
        bool                            valid;
 };
 
index 17238f40c4d5556e0fbadb04ea11dbf84fd8dd19..c84eb1a7205bc7955134672fcac975387ab37a94 100644 (file)
@@ -294,6 +294,28 @@ 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.
@@ -306,11 +328,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++) {
@@ -407,7 +432,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;
 
index 84b648a7ddd8cf697fc07fd00a1e2eed39ff46bd..f651f22a02dfccaf19eb6dd414e0f717777a1e34 100644 (file)
@@ -564,7 +564,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);
@@ -597,11 +597,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);
+
        radeon_mutex_lock(&rdev->cs_mutex);
        mutex_lock(&vm->mutex);
        radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
@@ -661,12 +677,15 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
        radeon_vm_unbind_locked(rdev, vm);
        radeon_mutex_unlock(&rdev->cs_mutex);
 
-       /* 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);
        }
@@ -678,6 +697,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);
                }
index 21ec9f5653cedc94e729e521e8cf62e4b14c2884..12207d928f633330d6da51f296b14ad92338ad5b 100644 (file)
@@ -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);
 }
 
index 830f1a7b486f2b3181968b76408b3f1175698639..1b2289f03b3e9a2de0b3a25c401cb44578f06110 100644 (file)
@@ -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);
        }
 }