Re: [PATCH 2/2] drm/amdkfd: Drain retry faults before SVM range no-access unmap
Philip Yang <[email protected]> Mon, 27 Jul 2026 14:32:21 -0400
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
On 2026-06-17 13:04, Kuehling, Felix wrote: > > On 2026-06-16 17:16, Philip Yang wrote: >> When svm_range_needs_unmap() unmaps a range, retry faults queued in the >> soft IH ring before set_attr no-access was called must be dropped, since >> those faults arrived before the app chose to revoke GPU access and >> should >> not re-map the range. >> >> Extract and add helper svm_range_update_checkpoint_timestamp() from >> svm_range_unmap_from_cpu() so both callers share the same logic. >> >> Change checkpoint_ts in svm_range_list from uint64_t to atomic64_t so >> svm_range_restore_pages() can read it safely from the page fault handler >> without holding the svms lock. >> >> Signed-off-by: Philip Yang <[email protected]> >> Acked-by: Kent Russell <[email protected]> > > Looks good in general. Two small suggestions inline. > > >> --- >> drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 +- >> drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 85 +++++++++++++++------------ >> 2 files changed, 50 insertions(+), 37 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h >> b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h >> index f00c522fba74..d3dcc3b8d546 100644 >> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h >> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h >> @@ -893,7 +893,7 @@ struct svm_range_list { >> DECLARE_BITMAP(bitmap_supported, MAX_GPU_INSTANCE); >> struct task_struct *faulting_task; >> /* check point ts decides if page fault recovery need be >> dropped */ >> - uint64_t checkpoint_ts[MAX_GPU_INSTANCE]; >> + atomic64_t checkpoint_ts[MAX_GPU_INSTANCE]; >> /* Default granularity to use in buffer migration >> * and restoration of backing memory while handling >> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> index e039b6f2942f..acaa364244d0 100644 >> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> @@ -759,6 +759,48 @@ svm_range_check_attr(struct kfd_process *p, >> return 0; >> } >> +static void svm_range_update_checkpoint_timestamp(struct >> kfd_process *p) >> +{ >> + struct svm_range_list *svms; >> + int i; >> + >> + svms = &p->svms; >> + >> + /* calculate time stamps that are used to decide which page >> faults need be >> + * dropped or handled before unmap pages from gpu vm >> + */ >> + for_each_set_bit(i, svms->bitmap_supported, p->n_pdds) { >> + struct kfd_process_device *pdd; >> + struct amdgpu_device *adev; >> + struct amdgpu_ih_ring *ih; >> + uint32_t checkpoint_wptr; >> + >> + pdd = p->pdds[i]; >> + if (!pdd) >> + continue; >> + >> + adev = pdd->dev->adev; >> + >> + /* Check and drain ih1 ring if cam not available */ >> + if (!adev->irq.retry_cam_enabled && adev->irq.ih1.ring_size) { >> + ih = &adev->irq.ih1; >> + checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih); >> + if (ih->rptr != checkpoint_wptr) { >> + atomic64_set(&svms->checkpoint_ts[i], >> + amdgpu_ih_decode_iv_ts(adev, ih, >> checkpoint_wptr, -1)); >> + continue; >> + } >> + } >> + >> + /* check if dev->irq.ih_soft is not empty */ >> + ih = &adev->irq.ih_soft; >> + checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih); >> + if (ih->rptr != checkpoint_wptr) >> + atomic64_set(&svms->checkpoint_ts[i], >> + amdgpu_ih_decode_iv_ts(adev, ih, >> checkpoint_wptr, -1)); >> + } >> +} >> + >> static void >> svm_range_apply_attrs(struct kfd_process *p, struct svm_range *prange, >> uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs, >> @@ -784,6 +826,8 @@ svm_range_apply_attrs(struct kfd_process *p, >> struct svm_range *prange, >> gpuidx = kfd_process_gpuidx_from_gpuid(p, >> attrs[i].value); >> if (attrs[i].type == KFD_IOCTL_SVM_ATTR_NO_ACCESS) { >> + svm_range_update_checkpoint_timestamp(p); >> + > > I think we should only do this if we're actually unmapping something. > So maybe move this into svm_range_needs_unmap. yes, then this patch only extract and add helper function svm_range_update_checkpoint_timestamp, move this patch as the first patch. > > >> bitmap_clear(prange->bitmap_access, gpuidx, 1); >> bitmap_clear(prange->bitmap_aip, gpuidx, 1); >> bitmap_set(prange->bitmap_needs_unmap, gpuidx, 1); > > And maybe make "bitmap_needs_unmap" conditional on whether it's > currently mapped. (in the previous patch). add check if (test_bit(gpuidx, prange->bitmap_mapped)) condition in the previous patch. Will send v2 patch series. Regards, Philip > > Regards, > Felix > > >> @@ -2560,7 +2604,6 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, >> struct svm_range *prange, >> struct kfd_process *p; >> unsigned long s, l; >> bool unmap_parent; >> - uint32_t i; >> if (atomic_read(&prange->queue_refcount)) { >> int r; >> @@ -2580,38 +2623,7 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, >> struct svm_range *prange, >> pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx] [0x%lx 0x%lx]\n", >> svms, >> prange, prange->start, prange->last, start, last); >> - /* calculate time stamps that are used to decide which page >> faults need be >> - * dropped or handled before unmap pages from gpu vm >> - */ >> - for_each_set_bit(i, svms->bitmap_supported, p->n_pdds) { >> - struct kfd_process_device *pdd; >> - struct amdgpu_device *adev; >> - struct amdgpu_ih_ring *ih; >> - uint32_t checkpoint_wptr; >> - >> - pdd = p->pdds[i]; >> - if (!pdd) >> - continue; >> - >> - adev = pdd->dev->adev; >> - >> - /* Check and drain ih1 ring if cam not available */ >> - if (!adev->irq.retry_cam_enabled && adev->irq.ih1.ring_size) { >> - ih = &adev->irq.ih1; >> - checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih); >> - if (ih->rptr != checkpoint_wptr) { >> - svms->checkpoint_ts[i] = >> - amdgpu_ih_decode_iv_ts(adev, ih, >> checkpoint_wptr, -1); >> - continue; >> - } >> - } >> - >> - /* check if dev->irq.ih_soft is not empty */ >> - ih = &adev->irq.ih_soft; >> - checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih); >> - if (ih->rptr != checkpoint_wptr) >> - svms->checkpoint_ts[i] = amdgpu_ih_decode_iv_ts(adev, >> ih, checkpoint_wptr, -1); >> - } >> + svm_range_update_checkpoint_timestamp(p); >> unmap_parent = start <= prange->start && last >= prange->last; >> @@ -3121,8 +3133,9 @@ svm_range_restore_pages(struct amdgpu_device >> *adev, unsigned int pasid, >> mutex_lock(&svms->lock); >> /* check if this page fault time stamp is before >> svms->checkpoint_ts */ >> - if (svms->checkpoint_ts[gpuidx] != 0) { >> - if (amdgpu_ih_ts_after_or_equal(ts, >> svms->checkpoint_ts[gpuidx])) { >> + if (atomic64_read(&svms->checkpoint_ts[gpuidx]) != 0) { >> + if (amdgpu_ih_ts_after_or_equal(ts, >> + atomic64_read(&svms->checkpoint_ts[gpuidx]))) { >> pr_debug("draining retry fault, drop fault 0x%llx\n", >> addr); >> if (write_locked) >> mmap_write_downgrade(mm); >> @@ -3132,7 +3145,7 @@ svm_range_restore_pages(struct amdgpu_device >> *adev, unsigned int pasid, >> /* ts is after svms->checkpoint_ts now, reset >> svms->checkpoint_ts >> * to zero to avoid following ts wrap around give wrong >> comparing >> */ >> - svms->checkpoint_ts[gpuidx] = 0; >> + atomic64_set(&svms->checkpoint_ts[gpuidx], 0); >> } >> }