Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: simplify eviction fence suspend/resume

The basic idea in this redesign is to add an eviction fence only in UQ
resume path. When userqueue is not present, keep ev_fence as NULL

Main changes are:
- do not create the eviction fence during evf_mgr_init, keeping
evf_mgr->ev_fence=NULL until UQ get active.
- do not replace the ev_fence in evf_resume path, but replace it only in
uq_resume path, so remove all the unnecessary code from ev_fence_resume.
- add a new helper function (amdgpu_userqueue_ensure_ev_fence) which
will do the following:
- flush any pending uq_resume work, so that it could create an
eviction_fence
- if there is no pending uq_resume_work, add a uq_resume work and
wait for it to execute so that we always have a valid ev_fence
- call this helper function from two places, to ensure we have a valid
ev_fence:
- when a new uq is created
- when a new uq completion fence is created

v2: Worked on review comments by Christian.
v3: Addressed few more review comments by Christian.
v4: Move mutex lock outside of the amdgpu_userqueue_suspend()
function (Christian).
v5: squash in build fix (Alex)

Cc: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Arvind Yadav <arvind.yadav@amd.com>
Signed-off-by: Shashank Sharma <shashank.sharma@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Shashank Sharma and committed by
Alex Deucher
a242a3e4 dd5a376c

+69 -111
+14 -64
drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
··· 87 87 } 88 88 89 89 /* Free old fence */ 90 - dma_fence_put(&old_ef->base); 90 + if (old_ef) 91 + dma_fence_put(&old_ef->base); 91 92 return 0; 92 93 93 94 free_err: ··· 102 101 struct amdgpu_eviction_fence_mgr *evf_mgr = work_to_evf_mgr(work, suspend_work.work); 103 102 struct amdgpu_fpriv *fpriv = evf_mgr_to_fpriv(evf_mgr); 104 103 struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr; 105 - struct amdgpu_vm *vm = &fpriv->vm; 106 - struct amdgpu_bo_va *bo_va; 107 - struct drm_exec exec; 108 - bool userq_active = amdgpu_userqueue_active(uq_mgr); 109 - int ret; 104 + struct amdgpu_eviction_fence *ev_fence; 110 105 106 + mutex_lock(&uq_mgr->userq_mutex); 107 + ev_fence = evf_mgr->ev_fence; 108 + if (!ev_fence) 109 + goto unlock; 111 110 112 - /* For userqueues, the fence replacement happens in resume path */ 113 - if (userq_active) { 114 - amdgpu_userqueue_suspend(uq_mgr); 115 - return; 116 - } 111 + amdgpu_userqueue_suspend(uq_mgr, ev_fence); 117 112 118 - /* Signal old eviction fence */ 119 - amdgpu_eviction_fence_signal(evf_mgr); 120 - 121 - /* Do not replace eviction fence is fd is getting closed */ 122 - if (evf_mgr->fd_closing) 123 - return; 124 - 125 - /* Prepare the objects to replace eviction fence */ 126 - drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); 127 - drm_exec_until_all_locked(&exec) { 128 - ret = amdgpu_vm_lock_pd(vm, &exec, 2); 129 - drm_exec_retry_on_contention(&exec); 130 - if (unlikely(ret)) 131 - goto unlock_drm; 132 - 133 - /* Lock the done list */ 134 - list_for_each_entry(bo_va, &vm->done, base.vm_status) { 135 - struct amdgpu_bo *bo = bo_va->base.bo; 136 - 137 - if (!bo) 138 - continue; 139 - 140 - if (vm != bo_va->base.vm) 141 - continue; 142 - 143 - ret = drm_exec_lock_obj(&exec, &bo->tbo.base); 144 - drm_exec_retry_on_contention(&exec); 145 - if (unlikely(ret)) 146 - goto unlock_drm; 147 - } 148 - } 149 - 150 - /* Replace old eviction fence with new one */ 151 - ret = amdgpu_eviction_fence_replace_fence(&fpriv->evf_mgr, &exec); 152 - if (ret) 153 - DRM_ERROR("Failed to replace eviction fence\n"); 154 - 155 - unlock_drm: 156 - drm_exec_fini(&exec); 113 + unlock: 114 + mutex_unlock(&uq_mgr->userq_mutex); 157 115 } 158 116 159 117 static bool amdgpu_eviction_fence_enable_signaling(struct dma_fence *f) ··· 137 177 .enable_signaling = amdgpu_eviction_fence_enable_signaling, 138 178 }; 139 179 140 - void amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr) 180 + void amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr, 181 + struct amdgpu_eviction_fence *ev_fence) 141 182 { 142 183 spin_lock(&evf_mgr->ev_fence_lock); 143 - dma_fence_signal(&evf_mgr->ev_fence->base); 184 + dma_fence_signal(&ev_fence->base); 144 185 spin_unlock(&evf_mgr->ev_fence_lock); 145 186 } 146 187 ··· 205 244 dma_resv_add_fence(resv, ef, DMA_RESV_USAGE_BOOKKEEP); 206 245 } 207 246 spin_unlock(&evf_mgr->ev_fence_lock); 247 + 208 248 return 0; 209 249 } 210 250 ··· 221 259 222 260 int amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr *evf_mgr) 223 261 { 224 - struct amdgpu_eviction_fence *ev_fence; 225 - 226 262 /* This needs to be done one time per open */ 227 263 atomic_set(&evf_mgr->ev_fence_seq, 0); 228 264 evf_mgr->ev_fence_ctx = dma_fence_context_alloc(1); 229 265 spin_lock_init(&evf_mgr->ev_fence_lock); 230 - 231 - ev_fence = amdgpu_eviction_fence_create(evf_mgr); 232 - if (!ev_fence) { 233 - DRM_ERROR("Failed to craete eviction fence\n"); 234 - return -ENOMEM; 235 - } 236 - 237 - spin_lock(&evf_mgr->ev_fence_lock); 238 - evf_mgr->ev_fence = ev_fence; 239 - spin_unlock(&evf_mgr->ev_fence_lock); 240 266 241 267 INIT_DELAYED_WORK(&evf_mgr->suspend_work, amdgpu_eviction_fence_suspend_worker); 242 268 return 0;
+2 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.h
··· 60 60 amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr *evf_mgr); 61 61 62 62 void 63 - amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr); 63 + amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr, 64 + struct amdgpu_eviction_fence *ev_fence); 64 65 65 66 int 66 67 amdgpu_eviction_fence_replace_fence(struct amdgpu_eviction_fence_mgr *evf_mgr,
+8 -16
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
··· 466 466 } 467 467 } 468 468 469 - /* Save the fence to wait for during suspend */ 470 - mutex_lock(&userq_mgr->userq_mutex); 471 - 472 469 /* Retrieve the user queue */ 473 470 queue = idr_find(&userq_mgr->userq_idr, args->queue_id); 474 471 if (!queue) { 475 472 r = -ENOENT; 476 - mutex_unlock(&userq_mgr->userq_mutex); 473 + goto put_gobj_write; 477 474 } 478 475 479 476 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, ··· 480 483 drm_exec_until_all_locked(&exec) { 481 484 r = drm_exec_prepare_array(&exec, gobj_read, num_read_bo_handles, 1); 482 485 drm_exec_retry_on_contention(&exec); 483 - if (r) { 484 - mutex_unlock(&userq_mgr->userq_mutex); 486 + if (r) 485 487 goto exec_fini; 486 - } 487 488 488 489 r = drm_exec_prepare_array(&exec, gobj_write, num_write_bo_handles, 1); 489 490 drm_exec_retry_on_contention(&exec); 490 - if (r) { 491 - mutex_unlock(&userq_mgr->userq_mutex); 491 + if (r) 492 492 goto exec_fini; 493 - } 494 493 } 495 494 496 495 r = amdgpu_userq_fence_read_wptr(queue, &wptr); 497 - if (r) { 498 - mutex_unlock(&userq_mgr->userq_mutex); 496 + if (r) 499 497 goto exec_fini; 500 - } 501 498 502 499 /* Create a new fence */ 503 500 r = amdgpu_userq_fence_create(queue, wptr, &fence); 504 - if (r) { 505 - mutex_unlock(&userq_mgr->userq_mutex); 501 + if (r) 506 502 goto exec_fini; 507 - } 503 + 504 + /* We are here means UQ is active, make sure the eviction fence is valid */ 505 + amdgpu_userqueue_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); 508 506 509 507 dma_fence_put(queue->last_fence); 510 508 queue->last_fence = dma_fence_get(fence);
+39 -29
drivers/gpu/drm/amd/amdgpu/amdgpu_userqueue.c
··· 101 101 return idr_find(&uq_mgr->userq_idr, qid); 102 102 } 103 103 104 + void 105 + amdgpu_userqueue_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr, 106 + struct amdgpu_eviction_fence_mgr *evf_mgr) 107 + { 108 + struct amdgpu_eviction_fence *ev_fence; 109 + 110 + retry: 111 + /* Flush any pending resume work to create ev_fence */ 112 + flush_delayed_work(&uq_mgr->resume_work); 113 + 114 + mutex_lock(&uq_mgr->userq_mutex); 115 + spin_lock(&evf_mgr->ev_fence_lock); 116 + ev_fence = evf_mgr->ev_fence; 117 + spin_unlock(&evf_mgr->ev_fence_lock); 118 + if (!ev_fence || dma_fence_is_signaled(&ev_fence->base)) { 119 + mutex_unlock(&uq_mgr->userq_mutex); 120 + /* 121 + * Looks like there was no pending resume work, 122 + * add one now to create a valid eviction fence 123 + */ 124 + schedule_delayed_work(&uq_mgr->resume_work, 0); 125 + goto retry; 126 + } 127 + } 128 + 104 129 int amdgpu_userqueue_create_object(struct amdgpu_userq_mgr *uq_mgr, 105 130 struct amdgpu_userq_obj *userq_obj, 106 131 int size) ··· 278 253 return -EINVAL; 279 254 } 280 255 281 - mutex_lock(&uq_mgr->userq_mutex); 256 + /* 257 + * There could be a situation that we are creating a new queue while 258 + * the other queues under this UQ_mgr are suspended. So if there is any 259 + * resume work pending, wait for it to get done. 260 + * 261 + * This will also make sure we have a valid eviction fence ready to be used. 262 + */ 263 + amdgpu_userqueue_ensure_ev_fence(&fpriv->userq_mgr, &fpriv->evf_mgr); 282 264 283 265 uq_funcs = adev->userq_funcs[args->in.ip_type]; 284 266 if (!uq_funcs) { ··· 340 308 341 309 unlock: 342 310 mutex_unlock(&uq_mgr->userq_mutex); 343 - if (!r) { 344 - /* 345 - * There could be a situation that we are creating a new queue while 346 - * the other queues under this UQ_mgr are suspended. So if there is any 347 - * resume work pending, wait for it to get done. 348 - */ 349 - flush_delayed_work(&uq_mgr->resume_work); 350 - } 351 311 352 312 return r; 353 313 } ··· 575 551 } 576 552 577 553 void 578 - amdgpu_userqueue_suspend(struct amdgpu_userq_mgr *uq_mgr) 554 + amdgpu_userqueue_suspend(struct amdgpu_userq_mgr *uq_mgr, 555 + struct amdgpu_eviction_fence *ev_fence) 579 556 { 580 557 int ret; 581 558 struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); 582 559 struct amdgpu_eviction_fence_mgr *evf_mgr = &fpriv->evf_mgr; 583 560 584 - 585 - mutex_lock(&uq_mgr->userq_mutex); 586 - 587 - /* Wait for any pending userqueue fence to signal */ 561 + /* Wait for any pending userqueue fence work to finish */ 588 562 ret = amdgpu_userqueue_wait_for_signal(uq_mgr); 589 563 if (ret) { 590 564 DRM_ERROR("Not suspending userqueue, timeout waiting for work\n"); 591 - goto unlock; 565 + return; 592 566 } 593 567 594 568 ret = amdgpu_userqueue_suspend_all(uq_mgr); 595 569 if (ret) { 596 570 DRM_ERROR("Failed to evict userqueue\n"); 597 - goto unlock; 571 + return; 598 572 } 599 573 600 574 /* Signal current eviction fence */ 601 - amdgpu_eviction_fence_signal(evf_mgr); 575 + amdgpu_eviction_fence_signal(evf_mgr, ev_fence); 602 576 603 577 if (evf_mgr->fd_closing) { 604 - mutex_unlock(&uq_mgr->userq_mutex); 605 578 cancel_delayed_work(&uq_mgr->resume_work); 606 579 return; 607 580 } 608 581 609 582 /* Schedule a resume work */ 610 583 schedule_delayed_work(&uq_mgr->resume_work, 0); 611 - 612 - unlock: 613 - mutex_unlock(&uq_mgr->userq_mutex); 614 584 } 615 585 616 586 int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct amdgpu_device *adev) 617 587 { 618 - struct amdgpu_fpriv *fpriv; 619 - 620 588 mutex_init(&userq_mgr->userq_mutex); 621 589 idr_init_base(&userq_mgr->userq_idr, 1); 622 590 userq_mgr->adev = adev; 623 - 624 - fpriv = uq_mgr_to_fpriv(userq_mgr); 625 - if (!fpriv->evf_mgr.ev_fence) { 626 - DRM_ERROR("Eviction fence not initialized yet\n"); 627 - return -EINVAL; 628 - } 629 591 630 592 INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userqueue_resume_worker); 631 593 return 0;
+6 -1
drivers/gpu/drm/amd/include/amdgpu_userqueue.h
··· 24 24 25 25 #ifndef AMDGPU_USERQUEUE_H_ 26 26 #define AMDGPU_USERQUEUE_H_ 27 + #include "amdgpu_eviction_fence.h" 27 28 28 29 #define AMDGPU_MAX_USERQ_COUNT 512 29 30 ··· 91 90 void amdgpu_userqueue_destroy_object(struct amdgpu_userq_mgr *uq_mgr, 92 91 struct amdgpu_userq_obj *userq_obj); 93 92 94 - void amdgpu_userqueue_suspend(struct amdgpu_userq_mgr *uq_mgr); 93 + void amdgpu_userqueue_suspend(struct amdgpu_userq_mgr *uq_mgr, 94 + struct amdgpu_eviction_fence *ev_fence); 95 95 96 96 int amdgpu_userqueue_active(struct amdgpu_userq_mgr *uq_mgr); 97 + 98 + void amdgpu_userqueue_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr, 99 + struct amdgpu_eviction_fence_mgr *evf_mgr); 97 100 #endif