aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
diff options
context:
space:
mode:
authorPhilip Yang <Philip.Yang@amd.com>2018-12-13 15:35:28 -0500
committerAlex Deucher <alexander.deucher@amd.com>2019-03-19 16:03:45 -0400
commit915d3eecfa23693bac9e54cdacf84fb4efdcc5c4 (patch)
treefbc7161be3e5cf431dff24a7e48d4a393de3d920 /drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
parent8dd69e69f42397c9b17764a951c44480b340858e (diff)
drm/amdgpu: replace get_user_pages with HMM mirror helpers
Use HMM helper function hmm_vma_fault() to get physical pages backing userptr and start CPU page table update track of those pages. Then use hmm_vma_range_done() to check if those pages are updated before amdgpu_cs_submit for gfx or before user queues are resumed for kfd. If userptr pages are updated, for gfx, amdgpu_cs_ioctl will restart from scratch, for kfd, restore worker is rescheduled to retry. HMM simplify the CPU page table concurrent update check, so remove guptasklock, mmu_invalidations, last_set_pages fields from amdgpu_ttm_tt struct. HMM does not pin the page (increase page ref count), so remove related operations like release_pages(), put_page(), mark_page_dirty(). Signed-off-by: Philip Yang <Philip.Yang@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c138
1 files changed, 50 insertions, 88 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 52a5e4fdc95b..545302d0955f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -52,7 +52,6 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
52 p->uf_entry.tv.bo = &bo->tbo; 52 p->uf_entry.tv.bo = &bo->tbo;
53 /* One for TTM and one for the CS job */ 53 /* One for TTM and one for the CS job */
54 p->uf_entry.tv.num_shared = 2; 54 p->uf_entry.tv.num_shared = 2;
55 p->uf_entry.user_pages = NULL;
56 55
57 drm_gem_object_put_unlocked(gobj); 56 drm_gem_object_put_unlocked(gobj);
58 57
@@ -540,14 +539,14 @@ static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
540 if (usermm && usermm != current->mm) 539 if (usermm && usermm != current->mm)
541 return -EPERM; 540 return -EPERM;
542 541
543 /* Check if we have user pages and nobody bound the BO already */ 542 if (amdgpu_ttm_tt_is_userptr(bo->tbo.ttm) &&
544 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm) && 543 lobj->user_invalidated && lobj->user_pages) {
545 lobj->user_pages) {
546 amdgpu_bo_placement_from_domain(bo, 544 amdgpu_bo_placement_from_domain(bo,
547 AMDGPU_GEM_DOMAIN_CPU); 545 AMDGPU_GEM_DOMAIN_CPU);
548 r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 546 r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
549 if (r) 547 if (r)
550 return r; 548 return r;
549
551 amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm, 550 amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm,
552 lobj->user_pages); 551 lobj->user_pages);
553 binding_userptr = true; 552 binding_userptr = true;
@@ -578,7 +577,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
578 struct amdgpu_bo *gds; 577 struct amdgpu_bo *gds;
579 struct amdgpu_bo *gws; 578 struct amdgpu_bo *gws;
580 struct amdgpu_bo *oa; 579 struct amdgpu_bo *oa;
581 unsigned tries = 10;
582 int r; 580 int r;
583 581
584 INIT_LIST_HEAD(&p->validated); 582 INIT_LIST_HEAD(&p->validated);
@@ -614,79 +612,45 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
614 if (p->uf_entry.tv.bo && !ttm_to_amdgpu_bo(p->uf_entry.tv.bo)->parent) 612 if (p->uf_entry.tv.bo && !ttm_to_amdgpu_bo(p->uf_entry.tv.bo)->parent)
615 list_add(&p->uf_entry.tv.head, &p->validated); 613 list_add(&p->uf_entry.tv.head, &p->validated);
616 614
617 while (1) { 615 /* Get userptr backing pages. If pages are updated after registered
618 struct list_head need_pages; 616 * in amdgpu_gem_userptr_ioctl(), amdgpu_cs_list_validate() will do
619 617 * amdgpu_ttm_backend_bind() to flush and invalidate new pages
620 r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, 618 */
621 &duplicates); 619 amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
622 if (unlikely(r != 0)) { 620 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
623 if (r != -ERESTARTSYS) 621 bool userpage_invalidated = false;
624 DRM_ERROR("ttm_eu_reserve_buffers failed.\n"); 622 int i;
625 goto error_free_pages; 623
626 } 624 e->user_pages = kvmalloc_array(bo->tbo.ttm->num_pages,
627 625 sizeof(struct page *),
628 INIT_LIST_HEAD(&need_pages); 626 GFP_KERNEL | __GFP_ZERO);
629 amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { 627 if (!e->user_pages) {
630 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); 628 DRM_ERROR("calloc failure\n");
631 629 return -ENOMEM;
632 if (amdgpu_ttm_tt_userptr_invalidated(bo->tbo.ttm,
633 &e->user_invalidated) && e->user_pages) {
634
635 /* We acquired a page array, but somebody
636 * invalidated it. Free it and try again
637 */
638 release_pages(e->user_pages,
639 bo->tbo.ttm->num_pages);
640 kvfree(e->user_pages);
641 e->user_pages = NULL;
642 }
643
644 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm) &&
645 !e->user_pages) {
646 list_del(&e->tv.head);
647 list_add(&e->tv.head, &need_pages);
648
649 amdgpu_bo_unreserve(bo);
650 }
651 } 630 }
652 631
653 if (list_empty(&need_pages)) 632 r = amdgpu_ttm_tt_get_user_pages(bo->tbo.ttm, e->user_pages);
654 break; 633 if (r) {
655 634 kvfree(e->user_pages);
656 /* Unreserve everything again. */ 635 e->user_pages = NULL;
657 ttm_eu_backoff_reservation(&p->ticket, &p->validated); 636 return r;
658
659 /* We tried too many times, just abort */
660 if (!--tries) {
661 r = -EDEADLK;
662 DRM_ERROR("deadlock in %s\n", __func__);
663 goto error_free_pages;
664 } 637 }
665 638
666 /* Fill the page arrays for all userptrs. */ 639 for (i = 0; i < bo->tbo.ttm->num_pages; i++) {
667 list_for_each_entry(e, &need_pages, tv.head) { 640 if (bo->tbo.ttm->pages[i] != e->user_pages[i]) {
668 struct ttm_tt *ttm = e->tv.bo->ttm; 641 userpage_invalidated = true;
669 642 break;
670 e->user_pages = kvmalloc_array(ttm->num_pages,
671 sizeof(struct page*),
672 GFP_KERNEL | __GFP_ZERO);
673 if (!e->user_pages) {
674 r = -ENOMEM;
675 DRM_ERROR("calloc failure in %s\n", __func__);
676 goto error_free_pages;
677 }
678
679 r = amdgpu_ttm_tt_get_user_pages(ttm, e->user_pages);
680 if (r) {
681 DRM_ERROR("amdgpu_ttm_tt_get_user_pages failed.\n");
682 kvfree(e->user_pages);
683 e->user_pages = NULL;
684 goto error_free_pages;
685 } 643 }
686 } 644 }
645 e->user_invalidated = userpage_invalidated;
646 }
687 647
688 /* And try again. */ 648 r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true,
689 list_splice(&need_pages, &p->validated); 649 &duplicates);
650 if (unlikely(r != 0)) {
651 if (r != -ERESTARTSYS)
652 DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
653 goto out;
690 } 654 }
691 655
692 amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, 656 amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold,
@@ -755,17 +719,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
755error_validate: 719error_validate:
756 if (r) 720 if (r)
757 ttm_eu_backoff_reservation(&p->ticket, &p->validated); 721 ttm_eu_backoff_reservation(&p->ticket, &p->validated);
758 722out:
759error_free_pages:
760
761 amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
762 if (!e->user_pages)
763 continue;
764
765 release_pages(e->user_pages, e->tv.bo->ttm->num_pages);
766 kvfree(e->user_pages);
767 }
768
769 return r; 723 return r;
770} 724}
771 725
@@ -1224,7 +1178,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
1224 struct amdgpu_bo_list_entry *e; 1178 struct amdgpu_bo_list_entry *e;
1225 struct amdgpu_job *job; 1179 struct amdgpu_job *job;
1226 uint64_t seq; 1180 uint64_t seq;
1227
1228 int r; 1181 int r;
1229 1182
1230 job = p->job; 1183 job = p->job;
@@ -1234,15 +1187,23 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
1234 if (r) 1187 if (r)
1235 goto error_unlock; 1188 goto error_unlock;
1236 1189
1237 /* No memory allocation is allowed while holding the mn lock */ 1190 /* No memory allocation is allowed while holding the mn lock.
1191 * p->mn is hold until amdgpu_cs_submit is finished and fence is added
1192 * to BOs.
1193 */
1238 amdgpu_mn_lock(p->mn); 1194 amdgpu_mn_lock(p->mn);
1195
1196 /* If userptr are invalidated after amdgpu_cs_parser_bos(), return
1197 * -EAGAIN, drmIoctl in libdrm will restart the amdgpu_cs_ioctl.
1198 */
1239 amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { 1199 amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
1240 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); 1200 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
1241 1201
1242 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm)) { 1202 r |= !amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
1243 r = -ERESTARTSYS; 1203 }
1244 goto error_abort; 1204 if (r) {
1245 } 1205 r = -EAGAIN;
1206 goto error_abort;
1246 } 1207 }
1247 1208
1248 job->owner = p->filp; 1209 job->owner = p->filp;
@@ -1338,6 +1299,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
1338 1299
1339out: 1300out:
1340 amdgpu_cs_parser_fini(&parser, r, reserved_buffers); 1301 amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
1302
1341 return r; 1303 return r;
1342} 1304}
1343 1305