drm/amdgpu: use new HMM APIs and helpers
HMM provides new APIs and helps in kernel 5.2-rc1 to simplify driver path. The old hmm APIs are deprecated and will be removed in future. Below are changes in driver: 1. Change hmm_vma_fault to hmm_range_register and hmm_range_fault which supports range with multiple vmas, remove the multiple vmas handle path and data structure. 2. Change hmm_vma_range_done to hmm_range_unregister. 3. Use default flags to avoid pre-fill pfn arrays. 4. Use new hmm_device_ helpers. Signed-off-by: Philip Yang <Philip.Yang@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
8252562d52
commit
66c45500bf
2 changed files with 68 additions and 85 deletions
drivers/gpu/drm/amd/amdgpu
|
@ -519,7 +519,6 @@ void amdgpu_hmm_init_range(struct hmm_range *range)
|
||||||
range->flags = hmm_range_flags;
|
range->flags = hmm_range_flags;
|
||||||
range->values = hmm_range_values;
|
range->values = hmm_range_values;
|
||||||
range->pfn_shift = PAGE_SHIFT;
|
range->pfn_shift = PAGE_SHIFT;
|
||||||
range->pfns = NULL;
|
|
||||||
INIT_LIST_HEAD(&range->list);
|
INIT_LIST_HEAD(&range->list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -711,8 +711,7 @@ struct amdgpu_ttm_tt {
|
||||||
struct task_struct *usertask;
|
struct task_struct *usertask;
|
||||||
uint32_t userflags;
|
uint32_t userflags;
|
||||||
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
||||||
struct hmm_range *ranges;
|
struct hmm_range *range;
|
||||||
int nr_ranges;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -725,57 +724,36 @@ struct amdgpu_ttm_tt {
|
||||||
*/
|
*/
|
||||||
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
||||||
|
|
||||||
/* Support Userptr pages cross max 16 vmas */
|
#define MAX_RETRY_HMM_RANGE_FAULT 16
|
||||||
#define MAX_NR_VMAS (16)
|
|
||||||
|
|
||||||
int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
|
int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
|
||||||
{
|
{
|
||||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||||
struct mm_struct *mm = gtt->usertask->mm;
|
struct mm_struct *mm = gtt->usertask->mm;
|
||||||
unsigned long start = gtt->userptr;
|
unsigned long start = gtt->userptr;
|
||||||
unsigned long end = start + ttm->num_pages * PAGE_SIZE;
|
struct vm_area_struct *vma;
|
||||||
struct vm_area_struct *vma = NULL, *vmas[MAX_NR_VMAS];
|
struct hmm_range *range;
|
||||||
struct hmm_range *ranges;
|
unsigned long i;
|
||||||
unsigned long nr_pages, i;
|
uint64_t *pfns;
|
||||||
uint64_t *pfns, f;
|
int retry = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (!mm) /* Happens during process shutdown */
|
if (!mm) /* Happens during process shutdown */
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
down_read(&mm->mmap_sem);
|
vma = find_vma(mm, start);
|
||||||
|
if (unlikely(!vma || start < vma->vm_start)) {
|
||||||
/* user pages may cross multiple VMAs */
|
r = -EFAULT;
|
||||||
gtt->nr_ranges = 0;
|
goto out;
|
||||||
do {
|
}
|
||||||
unsigned long vm_start;
|
|
||||||
|
|
||||||
if (gtt->nr_ranges >= MAX_NR_VMAS) {
|
|
||||||
DRM_ERROR("Too many VMAs in userptr range\n");
|
|
||||||
r = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_start = vma ? vma->vm_end : start;
|
|
||||||
vma = find_vma(mm, vm_start);
|
|
||||||
if (unlikely(!vma || vm_start < vma->vm_start)) {
|
|
||||||
r = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
vmas[gtt->nr_ranges++] = vma;
|
|
||||||
} while (end > vma->vm_end);
|
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("0x%lx nr_ranges %d pages 0x%lx\n",
|
|
||||||
start, gtt->nr_ranges, ttm->num_pages);
|
|
||||||
|
|
||||||
if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
|
if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
|
||||||
vmas[0]->vm_file)) {
|
vma->vm_file)) {
|
||||||
r = -EPERM;
|
r = -EPERM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ranges = kvmalloc_array(gtt->nr_ranges, sizeof(*ranges), GFP_KERNEL);
|
range = kzalloc(sizeof(*range), GFP_KERNEL);
|
||||||
if (unlikely(!ranges)) {
|
if (unlikely(!range)) {
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -786,61 +764,67 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
|
||||||
goto out_free_ranges;
|
goto out_free_ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < gtt->nr_ranges; i++)
|
amdgpu_hmm_init_range(range);
|
||||||
amdgpu_hmm_init_range(&ranges[i]);
|
range->default_flags = range->flags[HMM_PFN_VALID];
|
||||||
|
range->default_flags |= amdgpu_ttm_tt_is_readonly(ttm) ?
|
||||||
|
0 : range->flags[HMM_PFN_WRITE];
|
||||||
|
range->pfn_flags_mask = 0;
|
||||||
|
range->pfns = pfns;
|
||||||
|
hmm_range_register(range, mm, start,
|
||||||
|
start + ttm->num_pages * PAGE_SIZE, PAGE_SHIFT);
|
||||||
|
|
||||||
f = ranges[0].flags[HMM_PFN_VALID];
|
retry:
|
||||||
f |= amdgpu_ttm_tt_is_readonly(ttm) ?
|
/*
|
||||||
0 : ranges[0].flags[HMM_PFN_WRITE];
|
* Just wait for range to be valid, safe to ignore return value as we
|
||||||
memset64(pfns, f, ttm->num_pages);
|
* will use the return value of hmm_range_fault() below under the
|
||||||
|
* mmap_sem to ascertain the validity of the range.
|
||||||
|
*/
|
||||||
|
hmm_range_wait_until_valid(range, HMM_RANGE_DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
for (nr_pages = 0, i = 0; i < gtt->nr_ranges; i++) {
|
down_read(&mm->mmap_sem);
|
||||||
ranges[i].vma = vmas[i];
|
|
||||||
ranges[i].start = max(start, vmas[i]->vm_start);
|
|
||||||
ranges[i].end = min(end, vmas[i]->vm_end);
|
|
||||||
ranges[i].pfns = pfns + nr_pages;
|
|
||||||
nr_pages += (ranges[i].end - ranges[i].start) / PAGE_SIZE;
|
|
||||||
|
|
||||||
r = hmm_vma_fault(&ranges[i], true);
|
r = hmm_range_fault(range, true);
|
||||||
if (unlikely(r))
|
if (unlikely(r < 0)) {
|
||||||
break;
|
if (likely(r == -EAGAIN)) {
|
||||||
}
|
/*
|
||||||
if (unlikely(r)) {
|
* return -EAGAIN, mmap_sem is dropped
|
||||||
while (i--)
|
*/
|
||||||
hmm_vma_range_done(&ranges[i]);
|
if (retry++ < MAX_RETRY_HMM_RANGE_FAULT)
|
||||||
|
goto retry;
|
||||||
|
else
|
||||||
|
pr_err("Retry hmm fault too many times\n");
|
||||||
|
}
|
||||||
|
|
||||||
goto out_free_pfns;
|
goto out_up_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
up_read(&mm->mmap_sem);
|
up_read(&mm->mmap_sem);
|
||||||
|
|
||||||
for (i = 0; i < ttm->num_pages; i++) {
|
for (i = 0; i < ttm->num_pages; i++) {
|
||||||
pages[i] = hmm_pfn_to_page(&ranges[0], pfns[i]);
|
pages[i] = hmm_device_entry_to_page(range, pfns[i]);
|
||||||
if (!pages[i]) {
|
if (unlikely(!pages[i])) {
|
||||||
pr_err("Page fault failed for pfn[%lu] = 0x%llx\n",
|
pr_err("Page fault failed for pfn[%lu] = 0x%llx\n",
|
||||||
i, pfns[i]);
|
i, pfns[i]);
|
||||||
goto out_invalid_pfn;
|
r = -ENOMEM;
|
||||||
|
|
||||||
|
goto out_free_pfns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gtt->ranges = ranges;
|
|
||||||
|
gtt->range = range;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_up_read:
|
||||||
|
if (likely(r != -EAGAIN))
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
out_free_pfns:
|
out_free_pfns:
|
||||||
|
hmm_range_unregister(range);
|
||||||
kvfree(pfns);
|
kvfree(pfns);
|
||||||
out_free_ranges:
|
out_free_ranges:
|
||||||
kvfree(ranges);
|
kfree(range);
|
||||||
out:
|
out:
|
||||||
up_read(&mm->mmap_sem);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
out_invalid_pfn:
|
|
||||||
for (i = 0; i < gtt->nr_ranges; i++)
|
|
||||||
hmm_vma_range_done(&ranges[i]);
|
|
||||||
kvfree(pfns);
|
|
||||||
kvfree(ranges);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -853,23 +837,23 @@ bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm)
|
||||||
{
|
{
|
||||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||||
bool r = false;
|
bool r = false;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!gtt || !gtt->userptr)
|
if (!gtt || !gtt->userptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("user_pages_done 0x%llx nr_ranges %d pages 0x%lx\n",
|
DRM_DEBUG_DRIVER("user_pages_done 0x%llx pages 0x%lx\n",
|
||||||
gtt->userptr, gtt->nr_ranges, ttm->num_pages);
|
gtt->userptr, ttm->num_pages);
|
||||||
|
|
||||||
WARN_ONCE(!gtt->ranges || !gtt->ranges[0].pfns,
|
WARN_ONCE(!gtt->range || !gtt->range->pfns,
|
||||||
"No user pages to check\n");
|
"No user pages to check\n");
|
||||||
|
|
||||||
if (gtt->ranges) {
|
if (gtt->range) {
|
||||||
for (i = 0; i < gtt->nr_ranges; i++)
|
r = hmm_range_valid(gtt->range);
|
||||||
r |= hmm_vma_range_done(>t->ranges[i]);
|
hmm_range_unregister(gtt->range);
|
||||||
kvfree(gtt->ranges[0].pfns);
|
|
||||||
kvfree(gtt->ranges);
|
kvfree(gtt->range->pfns);
|
||||||
gtt->ranges = NULL;
|
kfree(gtt->range);
|
||||||
|
gtt->range = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -953,9 +937,9 @@ static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
|
||||||
sg_free_table(ttm->sg);
|
sg_free_table(ttm->sg);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
#if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
|
||||||
if (gtt->ranges &&
|
if (gtt->range &&
|
||||||
ttm->pages[0] == hmm_pfn_to_page(>t->ranges[0],
|
ttm->pages[0] == hmm_device_entry_to_page(gtt->range,
|
||||||
gtt->ranges[0].pfns[0]))
|
gtt->range->pfns[0]))
|
||||||
WARN_ONCE(1, "Missing get_user_page_done\n");
|
WARN_ONCE(1, "Missing get_user_page_done\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue