Re: [RFC 05/15] drm/xe: Implement xe_access_counter_handler

Matthew Brost
2026-04-03T02:06:24Z

On Wed, Mar 18, 2026 at 01:14:46PM +0530, Himal Prasad Ghimiray wrote:
> Enqueue access counter notifications to the appropriate queue based on
> ASID and schedule worker to process them.
>
> Signed-off-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
> ---
> drivers/gpu/drm/xe/xe_access_counter.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_access_counter.c b/drivers/gpu/drm/xe/xe_access_counter.c
> index cafcc42897f8..a2ce9dc45d05 100644
> --- a/drivers/gpu/drm/xe/xe_access_counter.c
> +++ b/drivers/gpu/drm/xe/xe_access_counter.c
> @@ -87,12 +87,29 @@ int xe_access_counter_init(struct xe_device *xe)
> * @xe: xe device
> * @ac: access counter notification
> *
> - * Process an access counter notification from the producer layer.
> + * Sink the access counter notification to a queue (i.e., a memory buffer) and
> + * queue a worker to service it.
> *
> * Return: 0 on success, negative error code on error
> */
> int xe_access_counter_handler(struct xe_device *xe, struct xe_access_counter *ac)
> {
> - /* Stub implementation - to be filled in */
> - return 0;
> + struct xe_usm_queue *ac_queue = xe->usm.ac_queue +
> + (ac->consumer.xe3.asid % XE_ACCESS_COUNTER_QUEUE_COUNT);

So again, let’s go with a single-queue [1], multiple-worker design.
Also, do not pick a worker based on ASID hashing, because once we move
to fine-grained locking [2], we can service access counters using
vm->lock in read mode.

Yes, BO-based migrations still need the VM dma-resv lock, so we would
serialize there, but given how BO migrations and binds are pipelined,
this ends up being a relatively small window unless we wait on the
migration under VM's dma-resv lock, which we don't need to do. SVM or
userptr (assuming we implement this eventually) access-counter migration
would remain pretty much fully parallel on the same VM.

Matt

[1] https://patchwork.freedesktop.org/patch/712591/?series=163429&rev=1#comment_1317960
[2] https://patchwork.freedesktop.org/patch/707294/?series=162167&rev=4

> + unsigned long flags;
> + bool full;
> +
> + spin_lock_irqsave(&ac_queue->lock, flags);
> + full = xe_usm_queue_full(ac_queue, sizeof(struct xe_access_counter));
> + if (!full) {
> + xe_usm_queue_push(ac_queue, ac, xe_access_counter_entry_size());
> + queue_work(xe->usm.pf_wq, &ac_queue->worker);
> + } else {
> + drm_warn(&xe->drm,
> + "AccessCounter Queue (%d) full, shouldn't be possible\n",
> + ac->consumer.xe3.asid % XE_ACCESS_COUNTER_QUEUE_COUNT);
> + }
> + spin_unlock_irqrestore(&ac_queue->lock, flags);
> +
> + return full ? -ENOSPC : 0;
> }
> --
> 2.34.1
>