On 2/16/26 16:49, Srinivasan Shanmugam wrote:
> Add a per-drm_file eventfd registry to amdgpu and wire up the new
> render-node IOCTLs:
>
> DRM_IOCTL_AMDGPU_EVENTFD_BIND
> DRM_IOCTL_AMDGPU_EVENTFD_UNBIND
>
> This allows userspace to bind an eventfd to an event_id on a per-file
> basis. The mapping is stored in an xarray protected by a mutex inside
> amdgpu_fpriv.
>
> Each event_id maps to a struct amdgpu_eventfd_entry containing the
> associated eventfd_ctx. Bind replaces any existing binding for the same
> event_id. Unbind removes the mapping and drops the eventfd reference.
>
> The registry is initialized during driver open and fully cleaned up
> during DRM release to ensure proper lifetime handling and to avoid
> leaking eventfd references. Entries are freed via RCU so future IRQ-side
> users can do lockless lookups.
You should probably encapsulate all this in an eventfd_mgr object and not put
so much code into amdgpu_kms.c
I suggest to just put the full eventfd handling into amdgpu_eventfd.[ch] and
then have both event_mgr as well as event_id object in there.
RCU sounds good, but is probably not necessary at all. Just use the IRQ safe
xarray lock variants.
Regards,
Christian.
>
> Cc: Harish Kasiviswanathan <[email protected]>
> Cc: Felix Kuehling <[email protected]>
> Cc: Alex Deucher <[email protected]>
> Cc: Christian König <[email protected]>
> Signed-off-by: Srinivasan Shanmugam <[email protected]>
> Change-Id: I78635bba4772843138a51a6152a3fa621cb07353
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 20 ++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 116 ++++++++++++++++++++++++
> 3 files changed, 139 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 0f6e9cdbe7d8..2baeb0b20df1 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -44,6 +44,8 @@
> #include <linux/hashtable.h>
> #include <linux/dma-fence.h>
> #include <linux/pci.h>
> +#include <linux/xarray.h>
> +#include <linux/rcupdate.h>
>
> #include <drm/ttm/ttm_bo.h>
> #include <drm/ttm/ttm_placement.h>
> @@ -452,8 +454,26 @@ struct amdgpu_fpriv {
>
> /** GPU partition selection */
> uint32_t xcp_id;
> +
> + /* eventfd registry for KFD-event unification (per drm_file) */
> + struct mutex eventfd_lock;
> + struct xarray eventfd_xa; /* key: event_id (u32) -> struct
> amdgpu_eventfd_entry* */
> +};
> +
> +struct amdgpu_eventfd_entry {
> + struct rcu_head rcu;
> + struct eventfd_ctx *ctx;
> };
>
> +struct drm_device;
> +struct drm_file;
> +
> +int amdgpu_eventfd_bind_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv);
> +int amdgpu_eventfd_unbind_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv);
> +void amdgpu_eventfd_registry_fini(struct amdgpu_fpriv *fpriv);
> +
> 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 03814a23eb54..98e2fa78c787 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -2955,6 +2955,7 @@ static int amdgpu_drm_release(struct inode *inode,
> struct file *filp)
> fpriv->evf_mgr.fd_closing = true;
> amdgpu_eviction_fence_destroy(&fpriv->evf_mgr);
> amdgpu_userq_mgr_fini(&fpriv->userq_mgr);
> + amdgpu_eventfd_registry_fini(fpriv);
> drm_dev_exit(idx);
> }
>
> @@ -3062,6 +3063,8 @@ 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_BIND, amdgpu_eventfd_bind_ioctl,
> DRM_RENDER_ALLOW),
> + DRM_IOCTL_DEF_DRV(AMDGPU_EVENTFD_UNBIND, amdgpu_eventfd_unbind_ioctl,
> DRM_RENDER_ALLOW),
> };
>
> static const struct drm_driver amdgpu_kms_driver = {
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> index f69332eed051..43da5bc36b7c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
> @@ -39,6 +39,10 @@
> #include <linux/uaccess.h>
> #include <linux/pci.h>
> #include <linux/pm_runtime.h>
> +#include <linux/eventfd.h>
> +#include <linux/rcupdate.h>
> +#include <linux/eventfd.h>
> +#include <linux/slab.h>
> #include "amdgpu_amdkfd.h"
> #include "amdgpu_gem.h"
> #include "amdgpu_display.h"
> @@ -634,6 +638,113 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
> return 0;
> }
>
> +static void amdgpu_eventfd_entry_free_rcu(struct rcu_head *rcu)
> +{
> + struct amdgpu_eventfd_entry *e =
> + container_of(rcu, struct amdgpu_eventfd_entry, rcu);
> +
> + if (e->ctx)
> + eventfd_ctx_put(e->ctx);
> + kfree(e);
> +}
> +
> +void amdgpu_eventfd_registry_fini(struct amdgpu_fpriv *fpriv)
> +{
> + unsigned long index;
> + struct amdgpu_eventfd_entry *e;
> +
> + if (!fpriv)
> + return;
> +
> + /*
> + * Serialize with bind/unbind via eventfd_lock,
> + * and use xa_lock to safely erase while iterating.
> + */
> + mutex_lock(&fpriv->eventfd_lock);
> +
> + xa_lock(&fpriv->eventfd_xa);
> + xa_for_each(&fpriv->eventfd_xa, index, e) {
> + __xa_erase(&fpriv->eventfd_xa, index);
> + call_rcu(&e->rcu, amdgpu_eventfd_entry_free_rcu);
> + }
> + xa_unlock(&fpriv->eventfd_xa);
> +
> + mutex_unlock(&fpriv->eventfd_lock);
> +
> + /* Wait for any RCU readers before destroying the xarray. */
> + synchronize_rcu();
> + xa_destroy(&fpriv->eventfd_xa);
> +}
> +
> +int amdgpu_eventfd_bind_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct amdgpu_device *adev = drm_to_adev(dev);
> + struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
> + struct drm_amdgpu_eventfd_bind *args = data;
> + struct amdgpu_eventfd_entry *e, *old;
> + struct eventfd_ctx *ctx;
> +
> + if (!fpriv || !adev)
> + return -ENODEV;
> + if (args->flags)
> + return -EINVAL;
> + if (args->eventfd < 0)
> + return -EINVAL;
> +
> + ctx = eventfd_ctx_fdget(args->eventfd);
> + if (IS_ERR(ctx))
> + return PTR_ERR(ctx);
> +
> + e = kzalloc(sizeof(*e), GFP_KERNEL);
> + if (!e) {
> + eventfd_ctx_put(ctx);
> + return -ENOMEM;
> + }
> + e->ctx = ctx;
> +
> + mutex_lock(&fpriv->eventfd_lock);
> + old = xa_store(&fpriv->eventfd_xa, args->event_id, e, GFP_KERNEL);
> + mutex_unlock(&fpriv->eventfd_lock);
> +
> + if (xa_is_err(old)) {
> + int ret = xa_err(old);
> +
> + eventfd_ctx_put(ctx);
> + kfree(e);
> + return ret;
> + }
> +
> + /* Replace existing binding for same event_id. */
> + if (old)
> + call_rcu(&old->rcu, amdgpu_eventfd_entry_free_rcu);
> +
> + return 0;
> +}
> +
> +int amdgpu_eventfd_unbind_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *file_priv)
> +{
> + struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
> + struct drm_amdgpu_eventfd_unbind *args = data;
> + struct amdgpu_eventfd_entry *e;
> +
> + if (!fpriv)
> + return -ENODEV;
> + if (args->flags)
> + return -EINVAL;
> +
> + mutex_lock(&fpriv->eventfd_lock);
> + e = xa_erase(&fpriv->eventfd_xa, args->event_id);
> + mutex_unlock(&fpriv->eventfd_lock);
> +
> + if (!e)
> + return -ENOENT;
> +
> + call_rcu(&e->rcu, amdgpu_eventfd_entry_free_rcu);
> + return 0;
> +}
> +
> /*
> * Userspace get information ioctl
> */
> @@ -1469,6 +1580,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev,
> struct drm_file *file_priv)
> goto out_suspend;
> }
>
> + mutex_init(&fpriv->eventfd_lock);
> + xa_init(&fpriv->eventfd_xa);
> pasid = amdgpu_pasid_alloc(16);
> if (pasid < 0) {
> dev_warn(adev->dev, "No more PASIDs available!");
> @@ -1538,6 +1651,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev,
> struct drm_file *file_priv)
> if (pasid)
> amdgpu_pasid_free(pasid);
>
> + xa_destroy(&fpriv->eventfd_xa);
> kfree(fpriv);
>
> out_suspend:
> @@ -1568,6 +1682,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
> if (!fpriv)
> return;
>
> + amdgpu_eventfd_registry_fini(fpriv);
> +
> pm_runtime_get_sync(dev->dev);
>
> if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_UVD) != NULL)