Re: [PATCH v2 1/2] drm/amdkfd: Add helper svm_range_update_checkpoint_timestamp

Felix Kuehling <[email protected]> Mon, 27 Jul 2026 17:45:08 -0400
Newsgroups org.freedesktop.lists.amd-gfx
Organization AMD Inc.
Message-ID <[email protected]>
On 2026-07-27 15:39, Philip Yang wrote:
> Extract svm_range_update_checkpoint_timestamp() from
> svm_range_unmap_from_cpu(). The next patch calls it when the app sets
> the no-access attribute.
>
> Change checkpoint_ts in svm_range_list from uint64_t to atomic64_t so
> svm_range_restore_pages() can read it from the page fault handler
> without holding the svms lock.
>
> No functional change, preparation for the next patch.
>
> Signed-off-by: Philip Yang <[email protected]>
> ---
>   drivers/gpu/drm/amd/amdkfd/kfd_priv.h |  2 +-
>   drivers/gpu/drm/amd/amdkfd/kfd_svm.c  | 83 +++++++++++++++------------
>   2 files changed, 48 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> index 88191a4c1657..bcb929002839 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> @@ -895,7 +895,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 30ad10bbd47e..c10d4edc8813 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,
> @@ -2556,7 +2598,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;
> @@ -2576,38 +2617,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;
>   
> @@ -3117,8 +3127,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]))) {

You lose atomicity here by reading the checkpoint twice. It would be 
better to read it into a local variable once only and then using the 
same value twice.

With that fixed, the patch is

Reviewed-by: Felix Kuehling <[email protected]>


>   			pr_debug("draining retry fault, drop fault 0x%llx\n", addr);
>   			if (write_locked)
>   				mmap_write_downgrade(mm);
> @@ -3128,7 +3139,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);
>   		}
>   	}
>