[PATCH v2 14/15] drm/amdgpu: Use mmu_range_notifier instead of hmm_mirror
Jason Gunthorpe
jgg at mellanox.com
Fri Nov 1 15:12:27 UTC 2019
On Fri, Nov 01, 2019 at 02:44:51PM +0000, Yang, Philip wrote:
>
>
> On 2019-10-29 3:25 p.m., Jason Gunthorpe wrote:
> > On Tue, Oct 29, 2019 at 07:22:37PM +0000, Yang, Philip wrote:
> >> Hi Jason,
> >>
> >> I did quick test after merging amd-staging-drm-next with the
> >> mmu_notifier branch, which includes this set changes. The test result
> >> has different failures, app stuck intermittently, GUI no display etc. I
> >> am understanding the changes and will try to figure out the cause.
> >
> > Thanks! I'm not surprised by this given how difficult this patch was
> > to make. Let me know if I can assist in any way
> >
> > Please ensure to run with lockdep enabled.. Your symptops sounds sort
> > of like deadlocking?
> >
> Hi Jason,
>
> Attached patch fix several issues in amdgpu driver, maybe you can squash
> this into patch 14. With this is done, patch 12, 13, 14 is Reviewed-by
> and Tested-by Philip Yang <philip.yang at amd.com>
Wow, this is great thanks! Can you clarify what the problems you found
were? Was the bug the 'return !r' below?
I'll also add your signed off by
Here are some remarks:
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
> index cb718a064eb4..c8bbd06f1009 100644
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
> @@ -67,21 +67,15 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_range_notifier *mrn,
> struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
> long r;
>
> - /*
> - * FIXME: Must hold some lock shared with
> - * amdgpu_ttm_tt_get_user_pages_done()
> - */
> - mmu_range_set_seq(mrn, cur_seq);
> + mutex_lock(&adev->notifier_lock);
>
> - /* FIXME: Is this necessary? */
> - if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, range->start,
> - range->end))
> - return true;
> + mmu_range_set_seq(mrn, cur_seq);
>
> - if (!mmu_notifier_range_blockable(range))
> + if (!mmu_notifier_range_blockable(range)) {
> + mutex_unlock(&adev->notifier_lock);
> return false;
This test for range_blockable should be before mutex_lock, I can move
it up
Also, do you know if notifier_lock is held while calling
amdgpu_ttm_tt_get_user_pages_done()? Can we add a 'lock assert held'
to amdgpu_ttm_tt_get_user_pages_done()?
> @@ -854,12 +853,20 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
> r = -EPERM;
> goto out_unlock;
> }
> + up_read(&mm->mmap_sem);
> + timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
> +
> +retry:
> + range->notifier_seq = mmu_range_read_begin(&bo->notifier);
>
> + down_read(&mm->mmap_sem);
> r = hmm_range_fault(range, 0);
> up_read(&mm->mmap_sem);
> -
> - if (unlikely(r < 0))
> + if (unlikely(r <= 0)) {
> + if ((r == 0 || r == -EBUSY) && !time_after(jiffies, timeout))
> + goto retry;
> goto out_free_pfns;
> + }
This isn't really right, a retry loop like this needs to go all the
way to mmu_range_read_retry() and done under the notifier_lock. ie
mmu_range_read_retry() can fail just as likely as hmm_range_fault()
can, and drivers are supposed to retry in both cases, with a single
timeout.
AFAICT it is a major bug that many places ignore the return code of
amdgpu_ttm_tt_get_user_pages_done() ???
However, this is all pre-existing bugs, so I'm OK go ahead with this
patch as modified. I advise AMD to make a followup patch ..
I'll add a FIXME note to this effect.
> for (i = 0; i < ttm->num_pages; i++) {
> pages[i] = hmm_device_entry_to_page(range, range->pfns[i]);
> @@ -916,7 +923,7 @@ bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
> gtt->range = NULL;
> }
>
> - return r;
> + return !r;
Ah is this the major error? hmm_range_valid() is inverted vs
mmu_range_read_retry()?
> }
> #endif
>
> @@ -997,10 +1004,18 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
> sg_free_table(ttm->sg);
>
> #if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
> - if (gtt->range &&
> - ttm->pages[0] == hmm_device_entry_to_page(gtt->range,
> - gtt->range->pfns[0]))
> - WARN_ONCE(1, "Missing get_user_page_done\n");
> + if (gtt->range) {
> + unsigned long i;
> +
> + for (i = 0; i < ttm->num_pages; i++) {
> + if (ttm->pages[i] !=
> + hmm_device_entry_to_page(gtt->range,
> + gtt->range->pfns[i]))
> + break;
> + }
> +
> + WARN((i == ttm->num_pages), "Missing get_user_page_done\n");
> + }
Is this related/necessary? I can put it in another patch if it is just
debugging improvement? Please advise
Thanks a lot,
Jason
More information about the amd-gfx
mailing list