diff options
author | Philip Yang <Philip.Yang@amd.com> | 2018-12-13 15:35:28 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2019-03-19 16:03:45 -0400 |
commit | 915d3eecfa23693bac9e54cdacf84fb4efdcc5c4 (patch) | |
tree | fbc7161be3e5cf431dff24a7e48d4a393de3d920 /drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | |
parent | 8dd69e69f42397c9b17764a951c44480b340858e (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.c | 138 |
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, | |||
755 | error_validate: | 719 | error_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 | 722 | out: | |
759 | error_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 | ||
1339 | out: | 1300 | out: |
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 | ||