Reviewed-by: Felix Kuehling <Felix.Kuehling at amd.com> On 2017-09-02 07:22 AM, Christian König wrote: > From: Christian König <christian.koenig at amd.com> > > Move calling put_page into the unpopulate callback. Otherwise we mess up the pages > reference count when it is unbound multiple times. > > Signed-off-by: Christian König <christian.koenig at amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 ++---- > drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 14 +++++++++++++- > 3 files changed, 16 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 21cab36..4dc9744 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -1802,6 +1802,7 @@ void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes, > void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain); > bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); > int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages); > +void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages); > int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, > uint32_t flags); > bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > index 48e18cc..c3202c8 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > @@ -471,10 +471,8 @@ static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, > > /* Check if we have user pages and nobody bound the BO already */ > if (lobj->user_pages && bo->tbo.ttm->state != tt_bound) { > - size_t size = sizeof(struct page *); > - > - size *= bo->tbo.ttm->num_pages; > - memcpy(bo->tbo.ttm->pages, lobj->user_pages, size); > + amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm, > + lobj->user_pages); > binding_userptr = true; > } > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > index ac14c18..07c3f11 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > @@ -664,6 +664,18 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages) > return r; > } > > +void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages) > +{ > + unsigned i; > + > + for (i = 0; i < ttm->num_pages; ++i) { > + if (ttm->pages[i]) > + put_page(ttm->pages[i]); > + > + ttm->pages[i] = pages ? pages[i] : NULL; > + } > +} > + > static void amdgpu_trace_dma_map(struct ttm_tt *ttm) > { > struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev); > @@ -738,7 +750,6 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm) > set_page_dirty(page); > > mark_page_accessed(page); > - put_page(page); > } > > amdgpu_trace_dma_unmap(ttm); > @@ -971,6 +982,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) > bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); > > if (gtt && gtt->userptr) { > + amdgpu_ttm_tt_set_user_pages(ttm, NULL); > kfree(ttm->sg); > ttm->page_flags &= ~TTM_PAGE_FLAG_SG; > return;