diff options
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 103 |
1 files changed, 46 insertions, 57 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 8a707d8bbb1c..f92597c292fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | |||
@@ -206,11 +206,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, | |||
206 | struct amdgpu_amdkfd_fence ***ef_list, | 206 | struct amdgpu_amdkfd_fence ***ef_list, |
207 | unsigned int *ef_count) | 207 | unsigned int *ef_count) |
208 | { | 208 | { |
209 | struct reservation_object_list *fobj; | 209 | struct reservation_object *resv = bo->tbo.resv; |
210 | struct reservation_object *resv; | 210 | struct reservation_object_list *old, *new; |
211 | unsigned int i = 0, j = 0, k = 0, shared_count; | 211 | unsigned int i, j, k; |
212 | unsigned int count = 0; | ||
213 | struct amdgpu_amdkfd_fence **fence_list; | ||
214 | 212 | ||
215 | if (!ef && !ef_list) | 213 | if (!ef && !ef_list) |
216 | return -EINVAL; | 214 | return -EINVAL; |
@@ -220,76 +218,67 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, | |||
220 | *ef_count = 0; | 218 | *ef_count = 0; |
221 | } | 219 | } |
222 | 220 | ||
223 | resv = bo->tbo.resv; | 221 | old = reservation_object_get_list(resv); |
224 | fobj = reservation_object_get_list(resv); | 222 | if (!old) |
225 | |||
226 | if (!fobj) | ||
227 | return 0; | 223 | return 0; |
228 | 224 | ||
229 | preempt_disable(); | 225 | new = kmalloc(offsetof(typeof(*new), shared[old->shared_max]), |
230 | write_seqcount_begin(&resv->seq); | 226 | GFP_KERNEL); |
227 | if (!new) | ||
228 | return -ENOMEM; | ||
231 | 229 | ||
232 | /* Go through all the shared fences in the resevation object. If | 230 | /* Go through all the shared fences in the resevation object and sort |
233 | * ef is specified and it exists in the list, remove it and reduce the | 231 | * the interesting ones to the end of the list. |
234 | * count. If ef is not specified, then get the count of eviction fences | ||
235 | * present. | ||
236 | */ | 232 | */ |
237 | shared_count = fobj->shared_count; | 233 | for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) { |
238 | for (i = 0; i < shared_count; ++i) { | ||
239 | struct dma_fence *f; | 234 | struct dma_fence *f; |
240 | 235 | ||
241 | f = rcu_dereference_protected(fobj->shared[i], | 236 | f = rcu_dereference_protected(old->shared[i], |
242 | reservation_object_held(resv)); | 237 | reservation_object_held(resv)); |
243 | 238 | ||
244 | if (ef) { | 239 | if ((ef && f->context == ef->base.context) || |
245 | if (f->context == ef->base.context) { | 240 | (!ef && to_amdgpu_amdkfd_fence(f))) |
246 | dma_fence_put(f); | 241 | RCU_INIT_POINTER(new->shared[--j], f); |
247 | fobj->shared_count--; | 242 | else |
248 | } else { | 243 | RCU_INIT_POINTER(new->shared[k++], f); |
249 | RCU_INIT_POINTER(fobj->shared[j++], f); | ||
250 | } | ||
251 | } else if (to_amdgpu_amdkfd_fence(f)) | ||
252 | count++; | ||
253 | } | 244 | } |
254 | write_seqcount_end(&resv->seq); | 245 | new->shared_max = old->shared_max; |
255 | preempt_enable(); | 246 | new->shared_count = k; |
256 | |||
257 | if (ef || !count) | ||
258 | return 0; | ||
259 | |||
260 | /* Alloc memory for count number of eviction fence pointers. Fill the | ||
261 | * ef_list array and ef_count | ||
262 | */ | ||
263 | fence_list = kcalloc(count, sizeof(struct amdgpu_amdkfd_fence *), | ||
264 | GFP_KERNEL); | ||
265 | if (!fence_list) | ||
266 | return -ENOMEM; | ||
267 | 247 | ||
268 | preempt_disable(); | 248 | if (!ef) { |
269 | write_seqcount_begin(&resv->seq); | 249 | unsigned int count = old->shared_count - j; |
270 | 250 | ||
271 | j = 0; | 251 | /* Alloc memory for count number of eviction fence pointers. |
272 | for (i = 0; i < shared_count; ++i) { | 252 | * Fill the ef_list array and ef_count |
273 | struct dma_fence *f; | 253 | */ |
274 | struct amdgpu_amdkfd_fence *efence; | 254 | *ef_list = kcalloc(count, sizeof(**ef_list), GFP_KERNEL); |
275 | 255 | *ef_count = count; | |
276 | f = rcu_dereference_protected(fobj->shared[i], | ||
277 | reservation_object_held(resv)); | ||
278 | 256 | ||
279 | efence = to_amdgpu_amdkfd_fence(f); | 257 | if (!*ef_list) { |
280 | if (efence) { | 258 | kfree(new); |
281 | fence_list[k++] = efence; | 259 | return -ENOMEM; |
282 | fobj->shared_count--; | ||
283 | } else { | ||
284 | RCU_INIT_POINTER(fobj->shared[j++], f); | ||
285 | } | 260 | } |
286 | } | 261 | } |
287 | 262 | ||
263 | /* Install the new fence list, seqcount provides the barriers */ | ||
264 | preempt_disable(); | ||
265 | write_seqcount_begin(&resv->seq); | ||
266 | RCU_INIT_POINTER(resv->fence, new); | ||
288 | write_seqcount_end(&resv->seq); | 267 | write_seqcount_end(&resv->seq); |
289 | preempt_enable(); | 268 | preempt_enable(); |
290 | 269 | ||
291 | *ef_list = fence_list; | 270 | /* Drop the references to the removed fences or move them to ef_list */ |
292 | *ef_count = k; | 271 | for (i = j, k = 0; i < old->shared_count; ++i) { |
272 | struct dma_fence *f; | ||
273 | |||
274 | f = rcu_dereference_protected(new->shared[i], | ||
275 | reservation_object_held(resv)); | ||
276 | if (!ef) | ||
277 | (*ef_list)[k++] = to_amdgpu_amdkfd_fence(f); | ||
278 | else | ||
279 | dma_fence_put(f); | ||
280 | } | ||
281 | kfree_rcu(old, rcu); | ||
293 | 282 | ||
294 | return 0; | 283 | return 0; |
295 | } | 284 | } |