Re: [PATCH] drm/amdkfd: don't repeat a SVM migration that collected no pages
"Kuehling, Felix" <[email protected]> Thu, 6 Aug 2026 10:54:57 -0400
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
On 2026-08-06 10:31, William Palacek wrote:
> svm_range_restore_pages() migrates the faulting granule to best_loc
> whenever prange->actual_loc or best_loc is set, without checking whether
> that window already lives there.
>
> When it does, MIGRATE_VMA_SELECT_SYSTEM has nothing to collect and
> migrate_vma_setup() returns cpages == 0. By then it has already issued
> MMU_NOTIFY_MIGRATE, which svm_range_cpu_invalidate_pagetables() turns
> into svm_range_unmap_from_gpus() for that window, so the mapping the
> fault needed is torn down to service a migration that moves nothing and
> the fault is re-armed rather than resolved. Under XNACK on an
> oversubscribed range this becomes a loop: svm_range_restore_pages() and
> svm_migrate_to_vram() are entered thousands of times per second,
> svm_migrate_copy_to_vram() is never reached, and the per process
> migration counters stop advancing while the GPU stays busy.
Why doesn't it get to svm_range_validate_and_map and resolve the fault?
Regards,
Felix
>
> The notification cannot be filtered by pgmap owner, as it is what
> invalidates the PTEs for pages that really do move. Avoid starting a
> migration that cannot move anything instead. Per window residency is not
> cheaply available beforehand, so record the window of a migration that
> collected nothing and do not repeat it there until a short backoff
> expires.
>
> Fixes: a546a2768440 ("drm/amdkfd: Use partial migrations/mapping for GPU/CPU page faults in SVM")
> Signed-off-by: William Palacek <[email protected]>
> ---
> drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 23 +++++++++++++++++++++++
> drivers/gpu/drm/amd/amdkfd/kfd_svm.h | 4 ++++
> 2 files changed, 27 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> index fa4054d51f60..b946ae95ff12 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> @@ -50,6 +50,11 @@
> * page table is updated.
> */
> #define AMDGPU_SVM_RANGE_RETRY_FAULT_PENDING (2UL * NSEC_PER_MSEC)
> +
> +/* Long enough that a retry fault storm cannot re-arm a migration which
> + * has already been found to have nothing to collect.
> + */
> +#define AMDGPU_SVM_RANGE_NOOP_MIGRATE_BACKOFF (100UL * NSEC_PER_MSEC)
> #if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
> #define dynamic_svm_range_dump(svms) \
> _dynamic_func_call_no_desc("svm_range_dump", svm_range_debug_dump, svms)
> @@ -3221,8 +3226,25 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
> last = min_t(unsigned long, ALIGN(addr + 1, size) - 1, prange->last);
> if (prange->actual_loc != 0 || best_loc != 0) {
> if (best_loc) {
> + uint64_t vram_pages = prange->vram_pages;
> +
> + /* migrate_vma_setup() unmaps the window before it knows
> + * whether it can collect anything, so a migration that
> + * collects nothing re-arms this fault instead of
> + * resolving it.
> + */
> + if (start == prange->noop_migrate_start &&
> + ktime_before(timestamp,
> + ktime_add_ns(prange->noop_migrate_timestamp,
> + AMDGPU_SVM_RANGE_NOOP_MIGRATE_BACKOFF)))
> + goto skip_migrate;
> +
> r = svm_migrate_to_vram(prange, best_loc, start, last,
> mm, KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU);
> + if (!r && prange->vram_pages == vram_pages) {
> + prange->noop_migrate_start = start;
> + prange->noop_migrate_timestamp = ktime_get_boottime();
> + }
> if (r) {
> pr_debug("svm_migrate_to_vram failed (%d) at %llx, falling back to system memory\n",
> r, addr);
> @@ -3248,6 +3270,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
> }
> }
>
> +skip_migrate:
> r = svm_range_validate_and_map(mm, start, last, prange, gpuidx, false,
> false, false);
> if (r)
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
> index c7d7adae4476..508a086195ac 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
> @@ -93,6 +93,8 @@ struct svm_work_list_item {
> * @granularity:migration granularity, log2 num pages
> * @invalid: not 0 means cpu page table is invalidated
> * @validate_timestamp: system timestamp when range is validated
> + * @noop_migrate_start: start of the last migration that collected no pages
> + * @noop_migrate_timestamp: system timestamp of that migration
> * @notifier: register mmu interval notifier
> * @work_item: deferred work item information
> * @deferred_list: list header used to add range to deferred list
> @@ -131,6 +133,8 @@ struct svm_range {
> uint8_t granularity;
> atomic_t invalid;
> ktime_t validate_timestamp;
> + unsigned long noop_migrate_start;
> + ktime_t noop_migrate_timestamp;
> struct mmu_interval_notifier notifier;
> struct svm_work_list_item work_item;
> struct list_head deferred_list;