[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260206062557.3718801-8-honglei1.huang@amd.com>
Date: Fri, 6 Feb 2026 14:25:56 +0800
From: Honglei Huang <honglei1.huang@....com>
To: <Felix.Kuehling@....com>, <alexander.deucher@....com>,
<christian.koenig@....com>, <Ray.Huang@....com>
CC: <dmitry.osipenko@...labora.com>, <Xinhui.Pan@....com>,
<airlied@...il.com>, <daniel@...ll.ch>, <amd-gfx@...ts.freedesktop.org>,
<dri-devel@...ts.freedesktop.org>, <linux-kernel@...r.kernel.org>,
<linux-mm@...ck.org>, <akpm@...ux-foundation.org>, <honghuan@....com>
Subject: [PATCH v3 7/8] drm/amdkfd: Unify userptr cleanup and update paths
From: Honglei Huang <honghuan@....com>
Refactor userptr management code to handle both single and batch
allocations uniformly.
This adds:
- cleanup_userptr_resources(): unified cleanup for single/batch
- discard_user_pages_batch(): discard pages for batch ranges
- amdgpu_amdkfd_update_user_pages_batch(): update pages for batch
- valid_user_pages_batch(): validate batch pages
Modified functions to support batch mode:
- update_invalid_user_pages(): uses batch update when applicable
- confirm_valid_user_pages_locked(): checks batch validity
- amdgpu_amdkfd_gpuvm_free_memory_of_gpu(): uses unified cleanup
Signed-off-by: Honglei Huang <honghuan@....com>
---
.../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 143 +++++++++++++++---
1 file changed, 126 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index bc075f5f1..bea365bdc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -2276,6 +2276,35 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu_batch(
return ret;
}
+static void cleanup_userptr_resources(struct kgd_mem *mem,
+ struct amdkfd_process_info *process_info)
+{
+ uint32_t i;
+
+ if (!amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm))
+ return;
+
+ if (mem->num_user_ranges > 0 && mem->user_ranges) {
+ for (i = 0; i < mem->num_user_ranges; i++)
+ interval_tree_remove(&mem->user_ranges[i].it_node,
+ &mem->user_ranges_itree);
+
+ if (mem->batch_notifier.mm) {
+ mmu_interval_notifier_remove(&mem->batch_notifier);
+ mem->batch_notifier.mm = NULL;
+ }
+
+ kvfree(mem->user_ranges);
+ mem->user_ranges = NULL;
+ mem->num_user_ranges = 0;
+ } else {
+ amdgpu_hmm_unregister(mem->bo);
+ mutex_lock(&process_info->notifier_lock);
+ amdgpu_ttm_tt_discard_user_pages(mem->bo->tbo.ttm, mem->range);
+ mutex_unlock(&process_info->notifier_lock);
+ }
+}
+
int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv,
uint64_t *size)
@@ -2317,12 +2346,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
mutex_unlock(&process_info->lock);
/* Cleanup user pages and MMU notifiers */
- if (amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm)) {
- amdgpu_hmm_unregister(mem->bo);
- mutex_lock(&process_info->notifier_lock);
- amdgpu_ttm_tt_discard_user_pages(mem->bo->tbo.ttm, mem->range);
- mutex_unlock(&process_info->notifier_lock);
- }
+ cleanup_userptr_resources(mem, process_info);
ret = reserve_bo_and_cond_vms(mem, NULL, BO_VM_ALL, &ctx);
if (unlikely(ret))
@@ -2909,6 +2933,44 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni,
return r;
}
+static void discard_user_pages_batch(struct amdgpu_bo *bo, struct kgd_mem *mem)
+{
+ uint32_t i;
+
+ for (i = 0; i < mem->num_user_ranges; i++) {
+ if (mem->user_ranges[i].invalid && mem->user_ranges[i].range) {
+ amdgpu_ttm_tt_discard_user_pages(bo->tbo.ttm,
+ mem->user_ranges[i].range);
+ mem->user_ranges[i].range = NULL;
+ }
+ }
+}
+
+static int amdgpu_amdkfd_update_user_pages_batch(struct mm_struct *mm,
+ struct amdgpu_bo *bo,
+ struct kgd_mem *mem)
+{
+ uint32_t i;
+ int ret = 0;
+
+ for (i = 0; i < mem->num_user_ranges; i++) {
+ if (!mem->user_ranges[i].invalid)
+ continue;
+
+ ret = get_user_pages_batch(
+ mm, mem, &mem->user_ranges[i],
+ &mem->user_ranges[i].range,
+ amdgpu_ttm_tt_is_readonly(bo->tbo.ttm));
+ if (ret) {
+ pr_debug("Failed %d to get user pages for range %u\n",
+ ret, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
/* Update invalid userptr BOs
*
* Moves invalidated (evicted) userptr BOs from userptr_valid_list to
@@ -2946,8 +3008,12 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
bo = mem->bo;
- amdgpu_ttm_tt_discard_user_pages(bo->tbo.ttm, mem->range);
- mem->range = NULL;
+ if (mem->num_user_ranges > 0 && mem->user_ranges)
+ discard_user_pages_batch(bo, mem);
+ else {
+ amdgpu_ttm_tt_discard_user_pages(bo->tbo.ttm, mem->range);
+ mem->range = NULL;
+ }
/* BO reservations and getting user pages (hmm_range_fault)
* must happen outside the notifier lock
@@ -2971,7 +3037,11 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
}
/* Get updated user pages */
- ret = amdgpu_ttm_tt_get_user_pages(bo, &mem->range);
+ if (mem->num_user_ranges > 0 && mem->user_ranges)
+ ret = amdgpu_amdkfd_update_user_pages_batch(mm, bo, mem);
+ else
+ ret = amdgpu_ttm_tt_get_user_pages(bo, &mem->range);
+
if (ret) {
pr_debug("Failed %d to get user pages\n", ret);
@@ -3005,7 +3075,10 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
ret = 0;
}
- amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm, mem->range);
+ if (mem->num_user_ranges == 0)
+ amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm, mem->range);
+ else
+ set_user_pages_batch(bo->tbo.ttm, mem->user_ranges, mem->num_user_ranges);
mutex_lock(&process_info->notifier_lock);
@@ -3019,6 +3092,14 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info,
/* set mem valid if mem has hmm range associated */
if (mem->range)
mem->invalid = 0;
+
+ if (mem->num_user_ranges > 0 && mem->user_ranges) {
+ uint32_t i;
+
+ for (i = 0; i < mem->num_user_ranges; i++)
+ mem->user_ranges[i].invalid = 0;
+ mem->invalid = 0;
+ }
}
unlock_out:
@@ -3126,6 +3207,29 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info)
return ret;
}
+static bool valid_user_pages_batch(struct kgd_mem *mem)
+{
+ uint32_t i;
+ bool all_valid = true;
+
+ if (!mem->user_ranges || mem->num_user_ranges == 0)
+ return true;
+
+ for (i = 0; i < mem->num_user_ranges; i++) {
+ if (!mem->user_ranges[i].range)
+ continue;
+
+ if (!amdgpu_ttm_tt_get_user_pages_done(mem->bo->tbo.ttm,
+ mem->user_ranges[i].range)) {
+ all_valid = false;
+ }
+
+ mem->user_ranges[i].range = NULL;
+ }
+
+ return all_valid;
+}
+
/* Confirm that all user pages are valid while holding the notifier lock
*
* Moves valid BOs from the userptr_inval_list back to userptr_val_list.
@@ -3140,15 +3244,20 @@ static int confirm_valid_user_pages_locked(struct amdkfd_process_info *process_i
validate_list) {
bool valid;
- /* keep mem without hmm range at userptr_inval_list */
- if (!mem->range)
- continue;
+ if (mem->num_user_ranges > 0 && mem->user_ranges)
+ valid = valid_user_pages_batch(mem);
+ else {
+ /* keep mem without hmm range at userptr_inval_list */
+ if (!mem->range)
+ continue;
- /* Only check mem with hmm range associated */
- valid = amdgpu_ttm_tt_get_user_pages_done(
- mem->bo->tbo.ttm, mem->range);
+ /* Only check mem with hmm range associated */
+ valid = amdgpu_ttm_tt_get_user_pages_done(
+ mem->bo->tbo.ttm, mem->range);
+
+ mem->range = NULL;
+ }
- mem->range = NULL;
if (!valid) {
WARN(!mem->invalid, "Invalid BO not marked invalid");
ret = -EAGAIN;
--
2.34.1
Powered by blists - more mailing lists