Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_amdkfd_gpuvm.c
index 8a707d8bbb1c3c57870aa3e38f5a85b708b6d18d..f92597c292fe5352e35bc6e6fa09865cff6ca292 100644 (file)
@@ -206,11 +206,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
                                        struct amdgpu_amdkfd_fence ***ef_list,
                                        unsigned int *ef_count)
 {
-       struct reservation_object_list *fobj;
-       struct reservation_object *resv;
-       unsigned int i = 0, j = 0, k = 0, shared_count;
-       unsigned int count = 0;
-       struct amdgpu_amdkfd_fence **fence_list;
+       struct reservation_object *resv = bo->tbo.resv;
+       struct reservation_object_list *old, *new;
+       unsigned int i, j, k;
 
        if (!ef && !ef_list)
                return -EINVAL;
@@ -220,76 +218,67 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
                *ef_count = 0;
        }
 
-       resv = bo->tbo.resv;
-       fobj = reservation_object_get_list(resv);
-
-       if (!fobj)
+       old = reservation_object_get_list(resv);
+       if (!old)
                return 0;
 
-       preempt_disable();
-       write_seqcount_begin(&resv->seq);
+       new = kmalloc(offsetof(typeof(*new), shared[old->shared_max]),
+                     GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
 
-       /* Go through all the shared fences in the resevation object. If
-        * ef is specified and it exists in the list, remove it and reduce the
-        * count. If ef is not specified, then get the count of eviction fences
-        * present.
+       /* Go through all the shared fences in the resevation object and sort
+        * the interesting ones to the end of the list.
         */
-       shared_count = fobj->shared_count;
-       for (i = 0; i < shared_count; ++i) {
+       for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) {
                struct dma_fence *f;
 
-               f = rcu_dereference_protected(fobj->shared[i],
+               f = rcu_dereference_protected(old->shared[i],
                                              reservation_object_held(resv));
 
-               if (ef) {
-                       if (f->context == ef->base.context) {
-                               dma_fence_put(f);
-                               fobj->shared_count--;
-                       } else {
-                               RCU_INIT_POINTER(fobj->shared[j++], f);
-                       }
-               } else if (to_amdgpu_amdkfd_fence(f))
-                       count++;
+               if ((ef && f->context == ef->base.context) ||
+                   (!ef && to_amdgpu_amdkfd_fence(f)))
+                       RCU_INIT_POINTER(new->shared[--j], f);
+               else
+                       RCU_INIT_POINTER(new->shared[k++], f);
        }
-       write_seqcount_end(&resv->seq);
-       preempt_enable();
-
-       if (ef || !count)
-               return 0;
-
-       /* Alloc memory for count number of eviction fence pointers. Fill the
-        * ef_list array and ef_count
-        */
-       fence_list = kcalloc(count, sizeof(struct amdgpu_amdkfd_fence *),
-                            GFP_KERNEL);
-       if (!fence_list)
-               return -ENOMEM;
+       new->shared_max = old->shared_max;
+       new->shared_count = k;
 
-       preempt_disable();
-       write_seqcount_begin(&resv->seq);
+       if (!ef) {
+               unsigned int count = old->shared_count - j;
 
-       j = 0;
-       for (i = 0; i < shared_count; ++i) {
-               struct dma_fence *f;
-               struct amdgpu_amdkfd_fence *efence;
-
-               f = rcu_dereference_protected(fobj->shared[i],
-                       reservation_object_held(resv));
+               /* Alloc memory for count number of eviction fence pointers.
+                * Fill the ef_list array and ef_count
+                */
+               *ef_list = kcalloc(count, sizeof(**ef_list), GFP_KERNEL);
+               *ef_count = count;
 
-               efence = to_amdgpu_amdkfd_fence(f);
-               if (efence) {
-                       fence_list[k++] = efence;
-                       fobj->shared_count--;
-               } else {
-                       RCU_INIT_POINTER(fobj->shared[j++], f);
+               if (!*ef_list) {
+                       kfree(new);
+                       return -ENOMEM;
                }
        }
 
+       /* Install the new fence list, seqcount provides the barriers */
+       preempt_disable();
+       write_seqcount_begin(&resv->seq);
+       RCU_INIT_POINTER(resv->fence, new);
        write_seqcount_end(&resv->seq);
        preempt_enable();
 
-       *ef_list = fence_list;
-       *ef_count = k;
+       /* Drop the references to the removed fences or move them to ef_list */
+       for (i = j, k = 0; i < old->shared_count; ++i) {
+               struct dma_fence *f;
+
+               f = rcu_dereference_protected(new->shared[i],
+                                             reservation_object_held(resv));
+               if (!ef)
+                       (*ef_list)[k++] = to_amdgpu_amdkfd_fence(f);
+               else
+                       dma_fence_put(f);
+       }
+       kfree_rcu(old, rcu);
 
        return 0;
 }