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