[PATCH 3/3] drm/amdkfd: block THP for non-replayable SVM ranges

From: Yitao Jiang

Date: Thu Jun 25 2026 - 07:01:31 EST


KFD SVM ranges on processes without XNACK, and ranges requested as
GPU_ALWAYS_MAPPED, cannot rely on replayable GPU faults after a CPU THP
remap of the registered VA range. Keep those ranges backed by base
pages while their interval notifier is active.

Opt those SVM interval notifiers into MMU_INTERVAL_NOTIFIER_BLOCK_THP
and update the flag when SVM attributes change. XNACK-enabled ranges
that can handle remaps through replayable faults remain eligible for
THP unless GPU_ALWAYS_MAPPED is requested.

Assisted-by: OpenAI-Codex:GPT-5.5
Signed-off-by: Yitao Jiang <jytscientist@xxxxxxxxxxx>
---
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 36 ++++++++++++++++++++++++----
1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 3841943da..0d0feba7b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -22,6 +22,7 @@
*/

#include <linux/types.h>
+#include <linux/mm.h>
#include <linux/sched/task.h>
#include <linux/dynamic_debug.h>
#include <drm/ttm/ttm_tt.h>
@@ -81,6 +82,26 @@ static const struct mmu_interval_notifier_ops svm_range_mn_ops = {
.invalidate = svm_range_cpu_invalidate_pagetables,
};

+static unsigned int
+svm_range_mn_flags(struct svm_range *prange)
+{
+ struct kfd_process *p = container_of(prange->svms, struct kfd_process,
+ svms);
+
+ if (!p->xnack_enabled ||
+ (prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED))
+ return MMU_INTERVAL_NOTIFIER_BLOCK_THP;
+
+ return 0;
+}
+
+static int
+svm_range_update_mn_flags_locked(struct svm_range *prange)
+{
+ return mmu_interval_notifier_set_flags_locked(&prange->notifier,
+ svm_range_mn_flags(prange));
+}
+
/**
* svm_range_unlink - unlink svm_range from lists and interval tree
* @prange: svm range structure to be removed
@@ -112,10 +133,11 @@ svm_range_add_notifier_locked(struct mm_struct *mm, struct svm_range *prange)
pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx]\n", prange->svms,
prange, prange->start, prange->last);

- mmu_interval_notifier_insert_locked(&prange->notifier, mm,
- prange->start << PAGE_SHIFT,
- prange->npages << PAGE_SHIFT,
- &svm_range_mn_ops);
+ mmu_interval_notifier_insert_locked_flags(&prange->notifier, mm,
+ prange->start << PAGE_SHIFT,
+ prange->npages << PAGE_SHIFT,
+ &svm_range_mn_ops,
+ svm_range_mn_flags(prange));
}

/**
@@ -3763,6 +3785,12 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
}
list_for_each_entry(prange, &update_list, update_list) {
svm_range_apply_attrs(p, prange, nattr, attrs, &update_mapping);
+ r = svm_range_update_mn_flags_locked(prange);
+ if (r) {
+ mutex_unlock(&svms->lock);
+ mmap_write_unlock(mm);
+ goto out;
+ }
/* TODO: unmap ranges from GPU that lost access */
}
update_mapping |= !p->xnack_enabled && !list_empty(&remap_list);
--
2.53.0