WAIT_EVENT currently provides the per-file queue, matching, and lifetime infrastructure, but no producer creates records when a user queue fence completes.
Add an IRQ-safe helper which appends a WAIT_EVENT record using the queue pointer as the internal routing key. The record takes a queue reference before it is published and releases it through the existing record cleanup paths. The producer does not translate the queue pointer back to a queue ID. Instead, the WAIT_EVENT ioctl adds the queue ID supplied by the waiter to the matched record immediately before returning it to userspace. This keeps queue IDs at the UAPI boundary while retaining queue-pointer-based matching internally. Call the helper from amdgpu_userq_process_fence_irq(), next to the existing EVENTFD notification. This reuses the established doorbell-to-queue lookup and does not add another queue lookup or change the GFX interrupt handling. Changes since v9: - Keep queue pointers for internal event matching. - Populate queue_id in returned metadata at the WAIT_EVENT ioctl boundary. - Clarify the producer and ioctl matching flow in the kerneldoc. Signed-off-by: Srinivasan Shanmugam <[email protected]> Reviewed-by: Alex Deucher <[email protected]> Acked-by: Christian König <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 6 ++ .../gpu/drm/amd/amdgpu/amdgpu_wait_event.c | 82 ++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index db97cd42e81a..edf6c3e91900 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -279,6 +279,7 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) struct xarray *xa = &adev->userq_doorbell_xa; struct amdgpu_usermode_queue *queue; struct amdgpu_eventfd_mgr *eventfd_mgr; + struct amdgpu_wait_event_mgr *wait_event_mgr; unsigned long flags; int r; @@ -301,6 +302,11 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) amdgpu_eventfd_signal(eventfd_mgr, DRM_AMDGPU_EVENT_TYPE_USERQ_EOP, queue); + + wait_event_mgr = amdgpu_userq_wait_event_mgr(queue->userq_mgr); + amdgpu_wait_event_add(wait_event_mgr, + DRM_AMDGPU_EVENT_TYPE_USERQ_EOP, + queue); } xa_unlock_irqrestore(xa, flags); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_wait_event.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_wait_event.c index 7060828be08d..794a57526076 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_wait_event.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_wait_event.c @@ -80,6 +80,35 @@ static bool amdgpu_wait_event_valid_type(u32 event_type) } } +/** + * amdgpu_wait_event_set_queue_id - populate queue-scoped event metadata + * @rec: matched WAIT_EVENT record being returned + * @queue_id: userspace USERQ queue handle + * + * Store the queue handle in the common record header and in the + * event-specific metadata for queue-scoped events. + */ +static void +amdgpu_wait_event_set_queue_id(struct amdgpu_wait_event_record *rec, + u32 queue_id) +{ + rec->data.queue_id = queue_id; + + switch (rec->data.event_type) { + case DRM_AMDGPU_EVENT_TYPE_USERQ_EOP: + rec->data.u.queue.queue_id = queue_id; + break; + case DRM_AMDGPU_EVENT_TYPE_QUEUE_RESET: + rec->data.u.reset.queue_id = queue_id; + break; + case DRM_AMDGPU_EVENT_TYPE_SCRATCH: + rec->data.u.scratch.queue_id = queue_id; + break; + default: + break; + } +} + /** * amdgpu_wait_event_record_free - release a pending event record * @rec: record to release @@ -251,6 +280,48 @@ void amdgpu_wait_event_mgr_init(struct amdgpu_wait_event_mgr *mgr) mgr->dead = false; } +/** + * amdgpu_wait_event_add - append a queue-scoped WAIT_EVENT record + * @mgr: per-file WAIT_EVENT manager + * @event_type: kernel-defined AMDGPU event type + * @queue: queue which generated the event + * + * This helper can be called from interrupt context. Allocate the record + * with GFP_ATOMIC and take a queue reference before publishing it on the + * manager's pending list. + * + * The queue pointer is retained as the internal routing key. queue_id is + * copied from the producing queue only as metadata returned to userspace. + */ +void amdgpu_wait_event_add(struct amdgpu_wait_event_mgr *mgr, + u32 event_type, + struct amdgpu_usermode_queue *queue) +{ + struct amdgpu_wait_event_record *rec; + unsigned long flags; + + rec = kzalloc(sizeof(*rec), GFP_ATOMIC); + if (!rec) + return; + + kref_get(&queue->refcount); + rec->queue = queue; + rec->data.event_type = event_type; + rec->data.seqno = atomic64_inc_return(&mgr->seqno); + + spin_lock_irqsave(&mgr->lock, flags); + if (mgr->dead) { + spin_unlock_irqrestore(&mgr->lock, flags); + amdgpu_wait_event_record_free(rec); + return; + } + + list_add_tail(&rec->node, &mgr->pending); + spin_unlock_irqrestore(&mgr->lock, flags); + + wake_up_interruptible(&mgr->wq); +} + /** * amdgpu_wait_event_mgr_fini - finalize a per-file WAIT_EVENT manager * @mgr: manager to finalize @@ -333,7 +404,13 @@ void amdgpu_wait_event_remove_queue(struct amdgpu_wait_event_mgr *mgr, * * deadline_ns is an absolute CLOCK_MONOTONIC deadline. The remaining wait * interval is recomputed from the original deadline after every wakeup so - * that spurious wakeups cannot extend the requested deadline. + * that interrupted or spurious wakeups cannot extend the requested + * deadline. + * + * For queue-scoped events, queue_id is resolved to a queue pointer before + * waiting. Pending records are matched using queue pointer equality. After + * a record is matched, the request queue_id is written to the returned + * metadata. * * Return: * Zero on success or a negative error code. @@ -395,6 +472,9 @@ int amdgpu_wait_event_drm_ioctl(struct drm_device *dev, void *data, } } + if (queue) + amdgpu_wait_event_set_queue_id(rec, args->queue_id); + if (copy_to_user(u64_to_user_ptr(args->out_ptr), &rec->data, sizeof(rec->data))) ret = -EFAULT; -- 2.34.1
