Commit 12f4b58a authored by Oak Zeng's avatar Oak Zeng Committed by Thomas Hellström

drm/xe: Use hmm_range_fault to populate user pages

This is an effort to unify hmmptr (aka system allocator)
and userptr code. hmm_range_fault is used to populate
a virtual address range for both hmmptr and userptr,
instead of hmmptr using hmm_range_fault and userptr
using get_user_pages_fast.

This also aligns with AMD gpu driver's behavior. In
long term, we plan to put some common helpers in this
area to drm layer so it can be re-used by different
vendors.

-v1
use the function with parameter to confirm whether lock is
acquired by the caller or needs to be acquired in hmm_range_fault.
Reviewed-by: default avatarMatthew Brost <matthew.brost@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: default avatarOak Zeng <oak.zeng@intel.com>
Signed-off-by: default avatarHimal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Signed-off-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240412095237.1048599-3-himal.prasad.ghimiray@intel.com
parent 81e058a3
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "xe_sync.h" #include "xe_sync.h"
#include "xe_trace.h" #include "xe_trace.h"
#include "xe_wa.h" #include "xe_wa.h"
#include "xe_hmm.h"
static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm) static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
{ {
...@@ -66,113 +67,14 @@ int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma) ...@@ -66,113 +67,14 @@ int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma)
int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma) int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
{ {
struct xe_userptr *userptr = &uvma->userptr;
struct xe_vma *vma = &uvma->vma; struct xe_vma *vma = &uvma->vma;
struct xe_vm *vm = xe_vma_vm(vma); struct xe_vm *vm = xe_vma_vm(vma);
struct xe_device *xe = vm->xe; struct xe_device *xe = vm->xe;
const unsigned long num_pages = xe_vma_size(vma) >> PAGE_SHIFT;
struct page **pages;
bool in_kthread = !current->mm;
unsigned long notifier_seq;
int pinned, ret, i;
bool read_only = xe_vma_read_only(vma);
lockdep_assert_held(&vm->lock); lockdep_assert_held(&vm->lock);
xe_assert(xe, xe_vma_is_userptr(vma)); xe_assert(xe, xe_vma_is_userptr(vma));
retry:
if (vma->gpuva.flags & XE_VMA_DESTROYED)
return 0;
notifier_seq = mmu_interval_read_begin(&userptr->notifier);
if (notifier_seq == userptr->notifier_seq)
return 0;
pages = kvmalloc_array(num_pages, sizeof(*pages), GFP_KERNEL);
if (!pages)
return -ENOMEM;
if (userptr->sg) {
dma_unmap_sgtable(xe->drm.dev,
userptr->sg,
read_only ? DMA_TO_DEVICE :
DMA_BIDIRECTIONAL, 0);
sg_free_table(userptr->sg);
userptr->sg = NULL;
}
pinned = ret = 0;
if (in_kthread) {
if (!mmget_not_zero(userptr->notifier.mm)) {
ret = -EFAULT;
goto mm_closed;
}
kthread_use_mm(userptr->notifier.mm);
}
while (pinned < num_pages) {
ret = get_user_pages_fast(xe_vma_userptr(vma) +
pinned * PAGE_SIZE,
num_pages - pinned,
read_only ? 0 : FOLL_WRITE,
&pages[pinned]);
if (ret < 0)
break;
pinned += ret;
ret = 0;
}
if (in_kthread) {
kthread_unuse_mm(userptr->notifier.mm);
mmput(userptr->notifier.mm);
}
mm_closed:
if (ret)
goto out;
ret = sg_alloc_table_from_pages_segment(&userptr->sgt, pages,
pinned, 0,
(u64)pinned << PAGE_SHIFT,
xe_sg_segment_size(xe->drm.dev),
GFP_KERNEL);
if (ret) {
userptr->sg = NULL;
goto out;
}
userptr->sg = &userptr->sgt;
ret = dma_map_sgtable(xe->drm.dev, userptr->sg,
read_only ? DMA_TO_DEVICE :
DMA_BIDIRECTIONAL,
DMA_ATTR_SKIP_CPU_SYNC |
DMA_ATTR_NO_KERNEL_MAPPING);
if (ret) {
sg_free_table(userptr->sg);
userptr->sg = NULL;
goto out;
}
for (i = 0; i < pinned; ++i) {
if (!read_only) {
lock_page(pages[i]);
set_page_dirty(pages[i]);
unlock_page(pages[i]);
}
mark_page_accessed(pages[i]); return xe_hmm_userptr_populate_range(uvma, false);
}
out:
release_pages(pages, pinned);
kvfree(pages);
if (!(ret < 0)) {
userptr->notifier_seq = notifier_seq;
if (xe_vma_userptr_check_repin(uvma) == -EAGAIN)
goto retry;
}
return ret < 0 ? ret : 0;
} }
static bool preempt_fences_waiting(struct xe_vm *vm) static bool preempt_fences_waiting(struct xe_vm *vm)
...@@ -956,8 +858,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm, ...@@ -956,8 +858,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
static void xe_vma_destroy_late(struct xe_vma *vma) static void xe_vma_destroy_late(struct xe_vma *vma)
{ {
struct xe_vm *vm = xe_vma_vm(vma); struct xe_vm *vm = xe_vma_vm(vma);
struct xe_device *xe = vm->xe;
bool read_only = xe_vma_read_only(vma);
if (vma->ufence) { if (vma->ufence) {
xe_sync_ufence_put(vma->ufence); xe_sync_ufence_put(vma->ufence);
...@@ -965,16 +865,11 @@ static void xe_vma_destroy_late(struct xe_vma *vma) ...@@ -965,16 +865,11 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
} }
if (xe_vma_is_userptr(vma)) { if (xe_vma_is_userptr(vma)) {
struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr; struct xe_userptr_vma *uvma = to_userptr_vma(vma);
struct xe_userptr *userptr = &uvma->userptr;
if (userptr->sg) { if (userptr->sg)
dma_unmap_sgtable(xe->drm.dev, xe_hmm_userptr_free_sg(uvma);
userptr->sg,
read_only ? DMA_TO_DEVICE :
DMA_BIDIRECTIONAL, 0);
sg_free_table(userptr->sg);
userptr->sg = NULL;
}
/* /*
* Since userptr pages are not pinned, we can't remove * Since userptr pages are not pinned, we can't remove
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment