On 6/23/26 16:12, Tvrtko Ursulin wrote:
> Similar in principle to DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES, we need a new
> ioctl to list any contexts created by the client.
> 
> Lets add it as DRM_IOCTL_AMDGPU_GEM_LIST_CONTEXTS, and the respective uapi
> data structures.
> 
> Structures contain all information required to re-create the context,
> modulo the handle id replication, which will be handled in a following
> patch.
> 
> Signed-off-by: Tvrtko Ursulin <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 100 ++++++++++++++++++++++++
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c |   1 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h |   2 +
>  include/uapi/drm/amdgpu_drm.h           |  31 ++++++++
>  4 files changed, 134 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
> index ce35b415093d..b9bbf8677174 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
> @@ -768,6 +768,106 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
>       return r;
>  }
>  
> +/**
> + * amdgpu_gem_list_contexts_ioctl - get information about clients contexts
> + *
> + * @dev: drm device pointer
> + * @data: drm_amdgpu_gem_list_handles
> + * @filp: drm file pointer
> + *
> + * Returns:
> + * 0 for success, -errno for errors.
> + */
> +int amdgpu_gem_list_contexts_ioctl(struct drm_device *dev, void *data,
> +                                struct drm_file *filp)
> +{
> +     struct drm_amdgpu_gem_list_contexts *args = data;
> +     struct drm_amdgpu_gem_list_contexts_entry *contexts;
> +     struct amdgpu_fpriv *fpriv = filp->driver_priv;
> +     struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
> +     struct amdgpu_device *adev = mgr->adev;
> +     unsigned long num = 0, idx = 0;
> +     struct amdgpu_ctx *ctx;
> +     int ret = 0;
> +     u32 id;
> +
> +     if (args->padding)
> +             return -EINVAL;
> +
> +     mutex_lock(&mgr->lock);
> +     idr_for_each_entry(&mgr->ctx_handles, ctx, id)
> +             num++;
> +     mutex_unlock(&mgr->lock);
> +
> +     if (num == 0 || args->num_contexts < num) {
> +             args->num_contexts = num;
> +             return 0;

For the args->num_contexts < num case I would expect an error return.

> +     }
> +
> +     contexts = kvzalloc_objs(*contexts, num);
> +     if (!contexts)
> +             return -ENOMEM;
> +
> +     mutex_lock(&mgr->lock);
> +     idr_for_each_entry(&mgr->ctx_handles, ctx, id) {
> +             struct drm_amdgpu_gem_list_contexts_entry *context;
> +             enum amd_dpm_forced_level level;
> +
> +             if (idx >= num) {
> +                     ret = -EAGAIN;
> +                     break;
> +             }
> +
> +             context = &contexts[idx];
> +
> +             context->handle = id;
> +             context->init_priority = ctx->init_priority;
> +             context->override_priority = ctx->override_priority;
> +
> +             mutex_lock(&adev->pm.stable_pstate_ctx_lock);
> +             if (ctx == adev->pm.stable_pstate_ctx) {
> +                     level = amdgpu_dpm_get_performance_level(adev);
> +
> +                     switch (level) {
> +                     case AMD_DPM_FORCED_LEVEL_AUTO:
> +                             context->pstate_flags = 
> AMDGPU_CTX_STABLE_PSTATE_NONE;
> +                             break;
> +                     case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
> +                             context->pstate_flags = 
> AMDGPU_CTX_STABLE_PSTATE_STANDARD;
> +                             break;
> +                     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
> +                             context->pstate_flags = 
> AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK;
> +                             break;
> +                     case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
> +                             context->pstate_flags = 
> AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK;
> +                             break;
> +                     case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
> +                             context->pstate_flags = 
> AMDGPU_CTX_STABLE_PSTATE_PEAK;
> +                             break;
> +                     default:
> +                             ret = -EIO;
> +                             break;
> +                     };
> +
> +             }
> +             mutex_unlock(&adev->pm.stable_pstate_ctx_lock);

Looks good to me of hand, but Alex should probably take a look at this power 
stuff as well.

> +
> +             idx++;
> +     }
> +     mutex_unlock(&mgr->lock);
> +
> +     args->num_contexts = idx;
> +
> +     if (!ret)
> +             if (copy_to_user(u64_to_user_ptr(args->contexts), contexts,
> +                              num * sizeof(*contexts)))
> +                     ret = -EFAULT;
> +
> +     kvfree(contexts);
> +
> +     return ret;
> +}
> +
>  struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
>  {
>       struct amdgpu_ctx *ctx;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index bf4260269681..f61f0ddd3ccf 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_GEM_LIST_CONTEXTS, 
> amdgpu_gem_list_contexts_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
>  };
>  
>  static const struct drm_driver amdgpu_kms_driver = {
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> index b558336bc4c6..0e17d9fc665f 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> @@ -69,6 +69,8 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
>                       struct drm_file *filp);
>  int amdgpu_gem_list_handles_ioctl(struct drm_device *dev, void *data,
>                                 struct drm_file *filp);
> +int amdgpu_gem_list_contexts_ioctl(struct drm_device *dev, void *data,
> +                                struct drm_file *filp);
>  
>  int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
>                               struct drm_file *filp);
> diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
> index 24f2dffc0789..3191ae1a0549 100644
> --- a/include/uapi/drm/amdgpu_drm.h
> +++ b/include/uapi/drm/amdgpu_drm.h
> @@ -58,6 +58,7 @@ extern "C" {
>  #define DRM_AMDGPU_USERQ_SIGNAL              0x17
>  #define DRM_AMDGPU_USERQ_WAIT                0x18
>  #define DRM_AMDGPU_GEM_LIST_HANDLES  0x19
> +#define DRM_AMDGPU_GEM_LIST_CONTEXTS 0x20
>  
>  #define DRM_IOCTL_AMDGPU_GEM_CREATE  DRM_IOWR(DRM_COMMAND_BASE + 
> DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)
>  #define DRM_IOCTL_AMDGPU_GEM_MMAP    DRM_IOWR(DRM_COMMAND_BASE + 
> DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)
> @@ -79,6 +80,7 @@ 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_GEM_LIST_CONTEXTS DRM_IOWR(DRM_COMMAND_BASE + 
> DRM_AMDGPU_GEM_LIST_CONTEXTS, struct drm_amdgpu_gem_list_contexts)
>  
>  /**
>   * DOC: memory domains
> @@ -873,6 +875,35 @@ struct drm_amdgpu_gem_list_handles_entry {
>       };
>  };
>  
> +struct drm_amdgpu_gem_list_contexts {
> +     /* User pointer to array of drm_amdgpu_gem_list_contexts_entry */
> +     __u64 contexts;
> +
> +     /* Size of the contexts buffer / Number of contexts in the client (if 
> larger than size of buffer, must retry) */

That comment looks to long and needs to be broken into multiple lines.

Apart from that looks really good to me,
Christian.

> +     __u32 num_contexts;
> +
> +     __u32 padding;
> +};
> +
> +struct drm_amdgpu_gem_list_contexts_entry {
> +     /* gem context handle */
> +     __u32 handle;
> +
> +     /* AMDGPU_GEM_LIST_CONTEXTS_FLAG_* */
> +     __u32 flags;
> +
> +     /* context initial priority */
> +     __s32 init_priority;
> +
> +     /* context override priority */
> +     __s32 override_priority;
> +
> +     /* pstate flags */
> +     __u32 pstate_flags;
> +
> +     __u32 padding;
> +};
> +
>  #define AMDGPU_VA_OP_MAP                     1
>  #define AMDGPU_VA_OP_UNMAP                   2
>  #define AMDGPU_VA_OP_CLEAR                   3

Reply via email to