On 30/06/2026 14:02, Christian König wrote:
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.

Hm, why, what do you have in mind? It is the same pattern as in list handles by the way.

+       }
+
+       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.

I was lazy and copy pasted from struct drm_amdgpu_gem_list_handles. :) Will fix.

Regards,

Tvrtko


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