[PATCH] drm/amdgpu: add ih waiter on process until checkpoint
Felix Kuehling
felix.kuehling at amd.com
Wed Mar 10 22:29:05 UTC 2021
On 2021-03-09 11:19 a.m., Jonathan Kim wrote:
> Add IH function to allow caller to wait until ring entries are processed
> until the checkpoint write pointer.
>
> This will be primarily used by HMM to drain pending page fault interrupts
> before memory unmap to prevent HMM from handling stale interrupts.
>
> v3: Scrap busy loop and change to wait_event.
>
> v2: Update title and description to clarify use.
> Add rptr/wptr wrap counter checks to guarantee ring entries are processed
> until the checkpoint.
>
> Suggested-by: Christian Koenig <christian.koenig at amd.com>
> Signed-off-by: Jonathan Kim <jonathan.kim at amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling at amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | 49 ++++++++++++++++++++++++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h | 5 +++
> 2 files changed, 54 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
> index dc852af4f3b7..1024065f1f03 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
> @@ -99,6 +99,8 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
> ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
> ih->rptr_cpu = &adev->wb.wb[rptr_offs];
> }
> +
> + init_waitqueue_head(&ih->wait_process);
> return 0;
> }
>
> @@ -160,6 +162,52 @@ void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
> }
> }
>
> +/* Waiter helper that checks current rptr matches or passes checkpoint wptr */
> +static bool amdgpu_ih_has_checkpoint_processed(struct amdgpu_device *adev,
> + struct amdgpu_ih_ring *ih,
> + uint32_t checkpoint_wptr,
> + uint32_t *prev_rptr)
> +{
> + uint32_t cur_rptr = ih->rptr | (*prev_rptr & ~ih->ptr_mask);
> +
> + /* rptr has wrapped. */
> + if (cur_rptr < *prev_rptr)
> + cur_rptr += ih->ptr_mask + 1;
> + *prev_rptr = cur_rptr;
> +
> + return cur_rptr >= checkpoint_wptr;
> +}
> +
> +/**
> + * amdgpu_ih_wait_on_checkpoint_process - wait to process IVs up to checkpoint
> + *
> + * @adev: amdgpu_device pointer
> + * @ih: ih ring to process
> + *
> + * Used to ensure ring has processed IVs up to the checkpoint write pointer.
> + */
> +int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
> + struct amdgpu_ih_ring *ih)
> +{
> + uint32_t checkpoint_wptr, rptr;
> +
> + if (!ih->enabled || adev->shutdown)
> + return -ENODEV;
> +
> + checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
> + /* Order wptr with rptr. */
> + rmb();
> + rptr = READ_ONCE(ih->rptr);
> +
> + /* wptr has wrapped. */
> + if (rptr > checkpoint_wptr)
> + checkpoint_wptr += ih->ptr_mask + 1;
> +
> + return wait_event_interruptible(ih->wait_process,
> + amdgpu_ih_has_checkpoint_processed(adev, ih,
> + checkpoint_wptr, &rptr));
> +}
> +
> /**
> * amdgpu_ih_process - interrupt handler
> *
> @@ -195,6 +243,7 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
> }
>
> amdgpu_ih_set_rptr(adev, ih);
> + wake_up_all(&ih->wait_process);
> atomic_set(&ih->lock, 0);
>
> /* make sure wptr hasn't changed while processing */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
> index 6ed4a85fc7c3..87ec6d20dbe0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
> @@ -66,6 +66,9 @@ struct amdgpu_ih_ring {
> unsigned rptr;
> atomic_t lock;
> struct amdgpu_ih_regs ih_regs;
> +
> + /* For waiting on IH processing at checkpoint. */
> + wait_queue_head_t wait_process;
> };
>
> /* provided by the ih block */
> @@ -87,6 +90,8 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
> void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
> void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
> unsigned int num_dw);
> +int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
> + struct amdgpu_ih_ring *ih);
> int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
> void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
> struct amdgpu_ih_ring *ih,
More information about the amd-gfx
mailing list