The current EVENTFD UAPI uses a userspace-defined event identifier.

For render-node event notifications, userspace should subscribe to
kernel-defined event types instead, allowing the kernel to define event
semantics and signaling sources.

Add a shared AMDGPU EVENTFD event type enum and update the EVENTFD UAPI
to use event_type instead of event_id.

Value 0 is reserved and rejected by the existing event_type validation.

queue_id remains part of the UAPI and is used to distinguish
queue-scoped subscriptions from GPU/device-scoped subscriptions.

Eventfd signaling remains notification-only.

v10: (per Christian)
- Add a comment clarifying that the flags field is currently unused,
  reserved for future UAPI extensions, and must be zero.
- Introduce event_type directly in the EVENTFD UAPI.
- Remove the INVALID event type; value 0 remains rejected by validation.
- Squash the event_id to event_type rename into the original UAPI patch.

v11: (per Christian)
- Keep the event_id to event_type rename in this patch so that later
  patches focus only on queue reference handling.
- Move queue reference conversion and queue-scoped EVENTFD handling
  into the subsequent patch to reduce noise in this change.

Cc: Alex Deucher <[email protected]>
Cc: Christian König <[email protected]>
Signed-off-by: Srinivasan Shanmugam <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h         |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c     |   1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.c | 107 +++++++++-----------
 drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.h |  17 ++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c     |  37 +++++++
 include/uapi/drm/amdgpu_drm.h               |  43 ++++++++
 6 files changed, 145 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index a75c68195df9..54bc31ee795a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -460,6 +460,11 @@ struct amdgpu_fpriv {
        struct amdgpu_eventfd_mgr       eventfd_mgr;
 };
 
+struct drm_device;
+struct drm_file;
+
+int amdgpu_eventfd_ioctl(struct drm_device *dev, void *data, struct drm_file 
*file_priv);
+
 int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv);
 
 /*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 1781c0c3d010..aaa4dd57099f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -3076,6 +3076,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_SIGNAL, amdgpu_userq_signal_ioctl, 
DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_WAIT, amdgpu_userq_wait_ioctl, 
DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(AMDGPU_GEM_LIST_HANDLES, 
amdgpu_gem_list_handles_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(AMDGPU_EVENTFD, amdgpu_eventfd_ioctl, 
DRM_RENDER_ALLOW),
 };
 
 static const struct drm_driver amdgpu_kms_driver = {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.c
index 4955ee942a1c..c777d563f1b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.c
@@ -24,14 +24,10 @@
 /*
  * Render-node eventfd subscription infrastructure.
  *
- * This module provides a simple event notification mechanism for render-node
- * clients using Linux eventfd objects.
+ * EVENTFD is notification-only. It wakes userspace when a GPU event happens.
+ * Event metadata/details are expected to be consumed separately through the
+ * corresponding wait/event path.
  *
- * Userspace can bind an eventfd to a userspace-defined event_id. When the
- * driver signals that event_id, all eventfds bound to it are notified.
- *
- * This mechanism is intended to support lightweight GPU event notifications
- * without polling from userspace.
  */
 
 #include <linux/slab.h>
@@ -42,19 +38,19 @@
 #define AMDGPU_EVENTFD_MAX_BINDS 4096
 
 /**
- * amdgpu_eventfd_id_alloc - allocate an event id container
- * @event_id: userspace-defined event identifier
+ * amdgpu_eventfd_id_alloc - allocate an event type container
+ * @event_type: kernel-defined AMDGPU event type
  *
- * Each event_id represents a notification category. Multiple eventfds can
- * be bound to the same event_id.
+ * Each event type represents a notification category. Multiple eventfds
+ * can be bound to the same event type.
  *
  * This function allocates the container which stores the list of eventfds
- * associated with that event_id.
+ * associated with that event type.
  *
  * Return:
  * Pointer to the newly allocated structure or NULL on failure.
  */
-static struct amdgpu_eventfd_id *amdgpu_eventfd_id_alloc(u32 event_id)
+static struct amdgpu_eventfd_id *amdgpu_eventfd_id_alloc(u32 event_type)
 {
        struct amdgpu_eventfd_id *id;
 
@@ -62,43 +58,41 @@ static struct amdgpu_eventfd_id 
*amdgpu_eventfd_id_alloc(u32 event_id)
        if (!id)
                return NULL;
 
-       id->event_id = event_id;
+       id->event_type = event_type;
        INIT_HLIST_HEAD(&id->entries);
        id->n_entries = 0;
+
        return id;
 }
 
 /**
- * amdgpu_eventfd_id_get_or_create - find or create an event_id entry
+ * amdgpu_eventfd_id_get_or_create - lookup or create an event type
  * @mgr: eventfd manager
- * @event_id: event identifier
- *
- * This helper returns the container associated with the given event_id.
- * If it does not exist, it will create one.
+ * @event_type: kernel-defined AMDGPU event type
  *
- * The function is designed to be callable without holding any locks.
- * Memory allocation is done outside the xarray lock to avoid blocking
- * inside critical sections.
+ * Find the container associated with the specified event type. If none
+ * exists, allocate and insert a new one.
  *
  * Return:
- * Pointer to the event_id structure or NULL on failure.
+ * Existing event type container or a newly allocated one.
  */
 static struct amdgpu_eventfd_id *
-amdgpu_eventfd_id_get_or_create(struct amdgpu_eventfd_mgr *mgr, u32 event_id)
+amdgpu_eventfd_id_get_or_create(struct amdgpu_eventfd_mgr *mgr,
+                               u32 event_type)
 {
        struct amdgpu_eventfd_id *id;
        struct amdgpu_eventfd_id *new_id;
-       XA_STATE(xas, &mgr->ids, event_id);
+       XA_STATE(xas, &mgr->ids, event_type);
        unsigned long flags;
        int r;
 
        xa_lock_irqsave(&mgr->ids, flags);
-       id = xa_load(&mgr->ids, event_id);
+       id = xa_load(&mgr->ids, event_type);
        xa_unlock_irqrestore(&mgr->ids, flags);
        if (id)
                return id;
 
-       new_id = amdgpu_eventfd_id_alloc(event_id);
+       new_id = amdgpu_eventfd_id_alloc(event_type);
        if (!new_id)
                return NULL;
 
@@ -140,7 +134,7 @@ amdgpu_eventfd_id_get_or_create(struct amdgpu_eventfd_mgr 
*mgr, u32 event_id)
  *
  *   event_id -> list of eventfds
  *
- * The xarray provides efficient lookup of event_id containers.
+ * The xarray provides efficient lookup of event type containers.
  */
 void amdgpu_eventfd_mgr_init(struct amdgpu_eventfd_mgr *mgr)
 {
@@ -186,23 +180,19 @@ void amdgpu_eventfd_mgr_fini(struct amdgpu_eventfd_mgr 
*mgr)
 }
 
 /**
- * amdgpu_eventfd_bind - bind eventfd to an event_id
+ * amdgpu_eventfd_bind - bind an eventfd to an event type
  * @mgr: eventfd manager
- * @event_id: userspace event identifier
+ * @event_type: kernel-defined AMDGPU event type
  * @eventfd: eventfd file descriptor
  *
- * This function allows userspace to subscribe to notifications for a
- * specific event_id.
- *
- * Multiple eventfds can be bound to the same event_id.
- *
- * Duplicate bindings of the same eventfd are treated as success and do
- * not create additional entries.
+ * Register an eventfd subscription for the specified event type.
+ * Duplicate subscriptions are treated as success.
  *
  * Return:
- * 0 on success, negative error code on failure.
+ * 0 on success or a negative error code.
  */
-int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, u32 event_id, int 
eventfd)
+int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr,
+                       u32 event_type, int eventfd)
 {
        struct amdgpu_eventfd_id *id;
        struct amdgpu_eventfd_entry *e = NULL, *it;
@@ -211,7 +201,7 @@ int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, u32 
event_id, int eventf
        bool dup = false;
        int r = 0; /* duplicate binds are treated as success */
 
-       if (!mgr || !event_id || eventfd < 0)
+       if (!mgr || !event_type || eventfd < 0)
                return -EINVAL;
 
        /*
@@ -229,7 +219,7 @@ int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, u32 
event_id, int eventf
                return PTR_ERR(ctx);
        }
 
-       id = amdgpu_eventfd_id_get_or_create(mgr, event_id);
+       id = amdgpu_eventfd_id_get_or_create(mgr, event_type);
        if (!id) {
                r = -ENOMEM;
                goto out_put_ctx;
@@ -259,7 +249,7 @@ int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, u32 
event_id, int eventf
 
        /*
         * Re-check duplicate under lock to close the race with another bind()
-        * for the same (event_id, ctx).
+        * for the same event_type and eventfd context.
         */
        xa_lock_irqsave(&mgr->ids, flags);
        hlist_for_each_entry(it, &id->entries, hnode) {
@@ -291,17 +281,18 @@ int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id, int eventf
 }
 
 /**
- * amdgpu_eventfd_unbind - remove eventfd binding
+ * amdgpu_eventfd_unbind - remove an eventfd subscription
  * @mgr: eventfd manager
- * @event_id: event identifier
+ * @event_type: kernel-defined AMDGPU event type
  * @eventfd: eventfd file descriptor
  *
- * Removes an existing binding between an event_id and an eventfd.
+ * Remove an existing subscription for the specified event type.
  *
  * Return:
- * 0 if removed, -ENOENT if binding does not exist.
+ * 0 on success or a negative error code.
  */
-int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, u32 event_id, int 
eventfd)
+int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr,
+                         u32 event_type, int eventfd)
 {
        struct amdgpu_eventfd_id *id;
        struct amdgpu_eventfd_entry *e;
@@ -310,7 +301,7 @@ int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id, int even
        unsigned long flags;
        bool removed = false;
 
-       if (!mgr || !event_id || eventfd < 0)
+       if (!mgr || !event_type || eventfd < 0)
                return -EINVAL;
 
        ctx = eventfd_ctx_fdget(eventfd);
@@ -319,7 +310,7 @@ int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id, int even
 
        xa_lock_irqsave(&mgr->ids, flags);
 
-       id = xa_load(&mgr->ids, event_id);
+       id = xa_load(&mgr->ids, event_type);
        if (!id)
                goto out_unlock;
 
@@ -337,7 +328,7 @@ int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id, int even
                atomic_dec(&mgr->bind_count);
 
                if (!id->n_entries) {
-                       __xa_erase(&mgr->ids, event_id);
+                       __xa_erase(&mgr->ids, event_type);
                        kfree(id);
                }
 
@@ -352,22 +343,22 @@ int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id, int even
 }
 
 /**
- * amdgpu_eventfd_signal - notify all eventfds bound to event_id
+ * amdgpu_eventfd_signal - signal all eventfds bound to an event type
  * @mgr: eventfd manager
- * @event_id: event identifier
+ * @event_type: kernel-defined AMDGPU event type
  *
- * This function is typically called from interrupt context.
+ * Notify all subscribers associated with the specified event type.
  *
- * All eventfds registered for the given event_id will be signaled.
- * Userspace processes waiting on those eventfds will wake up.
+ * Signaling is notification-only and does not carry additional payload.
  */
-void amdgpu_eventfd_signal(struct amdgpu_eventfd_mgr *mgr, u32 event_id)
+void amdgpu_eventfd_signal(struct amdgpu_eventfd_mgr *mgr,
+                          u32 event_type)
 {
        struct amdgpu_eventfd_id *id;
        struct amdgpu_eventfd_entry *e;
        unsigned long flags;
 
-       if (!mgr || !event_id)
+       if (!mgr || !event_type)
                return;
 
        /*
@@ -376,7 +367,7 @@ void amdgpu_eventfd_signal(struct amdgpu_eventfd_mgr *mgr, 
u32 event_id)
         */
        xa_lock_irqsave(&mgr->ids, flags);
 
-       id = xa_load(&mgr->ids, event_id);
+       id = xa_load(&mgr->ids, event_type);
        if (id) {
                hlist_for_each_entry(e, &id->entries, hnode)
                        eventfd_signal(e->ctx);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.h
index 248afb1f2f14..e13b86240afc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eventfd.h
@@ -28,9 +28,9 @@
 #ifndef __AMDGPU_EVENTFD_H__
 #define __AMDGPU_EVENTFD_H__
 
+#include <linux/atomic.h>
 #include <linux/eventfd.h>
 #include <linux/xarray.h>
-#include <linux/atomic.h>
 
 struct amdgpu_eventfd_entry {
        struct eventfd_ctx *ctx;
@@ -38,22 +38,25 @@ struct amdgpu_eventfd_entry {
 };
 
 struct amdgpu_eventfd_id {
-       u32 event_id;
+       u32 event_type;
        struct hlist_head entries;
        u32 n_entries;
 };
 
 struct amdgpu_eventfd_mgr {
-       struct xarray ids;          /* event_id -> struct amdgpu_eventfd_id* */
-       atomic_t bind_count;        /* total binds across all event_ids */
+       struct xarray ids;      /* event_type -> struct amdgpu_eventfd_id* */
+       atomic_t bind_count;    /* total binds across all event types */
 };
 
 void amdgpu_eventfd_mgr_init(struct amdgpu_eventfd_mgr *mgr);
 void amdgpu_eventfd_mgr_fini(struct amdgpu_eventfd_mgr *mgr);
 
-int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr, u32 event_id, int 
eventfd);
-int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr, u32 event_id, int 
eventfd);
+int amdgpu_eventfd_bind(struct amdgpu_eventfd_mgr *mgr,
+                       u32 event_type, int eventfd);
+int amdgpu_eventfd_unbind(struct amdgpu_eventfd_mgr *mgr,
+                         u32 event_type, int eventfd);
 
-void amdgpu_eventfd_signal(struct amdgpu_eventfd_mgr *mgr, u32 event_id);
+void amdgpu_eventfd_signal(struct amdgpu_eventfd_mgr *mgr,
+                          u32 event_type);
 
 #endif /* __AMDGPU_EVENTFD_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index f5719500527f..7cc54b7e3b81 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -634,6 +634,43 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
        return 0;
 }
 
+int amdgpu_eventfd_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
+       struct drm_amdgpu_eventfd *args = data;
+
+       if (!fpriv)
+               return -EINVAL;
+
+       /*
+        * flags are reserved for future UAPI extensions and must be zero.
+        */
+       if (args->flags || !args->event_type || args->eventfd < 0)
+               return -EINVAL;
+
+       /*
+        * Queue-scoped subscriptions are enabled by the later
+        * queue-reference routing patch. Until then, keep
+        * queue_id zero.
+        */
+       if (args->queue_id)
+               return -EINVAL;
+
+       switch (args->op) {
+       case DRM_AMDGPU_EVENTFD_OP_BIND:
+               return amdgpu_eventfd_bind(&fpriv->eventfd_mgr,
+                                          args->event_type,
+                                          args->eventfd);
+       case DRM_AMDGPU_EVENTFD_OP_UNBIND:
+               return amdgpu_eventfd_unbind(&fpriv->eventfd_mgr,
+                                            args->event_type,
+                                            args->eventfd);
+       default:
+               return -EINVAL;
+       }
+}
+
 /*
  * Userspace get information ioctl
  */
diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
index 9f3090db2f16..bf4fc61cf0c7 100644
--- a/include/uapi/drm/amdgpu_drm.h
+++ b/include/uapi/drm/amdgpu_drm.h
@@ -39,6 +39,7 @@ extern "C" {
 #endif
 
 #define DRM_AMDGPU_GEM_CREATE          0x00
+#define DRM_AMDGPU_EVENTFD             0x1A
 #define DRM_AMDGPU_GEM_MMAP            0x01
 #define DRM_AMDGPU_CTX                 0x02
 #define DRM_AMDGPU_BO_LIST             0x03
@@ -79,6 +80,8 @@ extern "C" {
 #define DRM_IOCTL_AMDGPU_USERQ_SIGNAL  DRM_IOWR(DRM_COMMAND_BASE + 
DRM_AMDGPU_USERQ_SIGNAL, struct drm_amdgpu_userq_signal)
 #define DRM_IOCTL_AMDGPU_USERQ_WAIT    DRM_IOWR(DRM_COMMAND_BASE + 
DRM_AMDGPU_USERQ_WAIT, struct drm_amdgpu_userq_wait)
 #define DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES DRM_IOWR(DRM_COMMAND_BASE + 
DRM_AMDGPU_GEM_LIST_HANDLES, struct drm_amdgpu_gem_list_handles)
+#define DRM_IOCTL_AMDGPU_EVENTFD \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_EVENTFD, struct 
drm_amdgpu_eventfd)
 
 /**
  * DOC: memory domains
@@ -204,6 +207,46 @@ union drm_amdgpu_gem_create {
        struct drm_amdgpu_gem_create_out        out;
 };
 
+enum drm_amdgpu_event_type {
+       DRM_AMDGPU_EVENT_TYPE_USERQ_EOP = 1,
+       DRM_AMDGPU_EVENT_TYPE_QUEUE_RESET = 2,
+       DRM_AMDGPU_EVENT_TYPE_MEMORY_EXCEPTION = 3,
+       DRM_AMDGPU_EVENT_TYPE_SCRATCH = 4,
+       DRM_AMDGPU_EVENT_TYPE_GPU_RESET = 5,
+};
+
+enum drm_amdgpu_eventfd_op {
+       DRM_AMDGPU_EVENTFD_OP_BIND = 0,
+       DRM_AMDGPU_EVENTFD_OP_UNBIND = 1,
+};
+
+/**
+ * struct drm_amdgpu_eventfd - bind or unbind an eventfd to an AMDGPU event
+ * @op: operation type, see &enum drm_amdgpu_eventfd_op
+ * @event_type: kernel-defined AMDGPU event type
+ * @eventfd: eventfd file descriptor
+ * @queue_id: queue identifier for queue-scoped subscriptions, or 0 for
+ *           device/GPU-scoped subscriptions
+ * @flags: must be 0
+ *
+ * This ioctl lets userspace register or unregister eventfd notifications
+ * for a render-node event.
+ *
+ * Eventfd signaling is notification-only.
+ *
+ * USERQ_EOP, QUEUE_RESET, and SCRATCH are queue-scoped events.
+ * Userspace specifies @queue_id when registering these subscriptions.
+ *
+ * MEMORY_EXCEPTION is currently GPU-scoped and requires @queue_id = 0.
+ */
+struct drm_amdgpu_eventfd {
+       __u32 op;
+       __u32 event_type;
+       __s32 eventfd;
+       __u32 queue_id;
+       __u32 flags;
+};
+
 /** Opcode to create new residency list.  */
 #define AMDGPU_BO_LIST_OP_CREATE       0
 /** Opcode to destroy previously created residency list */
-- 
2.34.1

Reply via email to