[PATCH v3 5/7] drm/amdgpu: Add a new ioctl for listing client contexts

Tvrtko Ursulin <[email protected]> Thu, 6 Aug 2026 14:47:10 +0100
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
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 | 102 ++++++++++++++++++++++++
 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, 136 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index d53259a5b82f..59ea6153f4a2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -717,6 +717,108 @@ 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 id, idx = 0, num = 0;
+	struct amdgpu_ctx *ctx;
+	int ret = 0;
+
+	if (args->padding)
+		return -EINVAL;
+
+	xa_for_each(&mgr->ctx_handles, id, ctx)
+		num++;
+
+	if (num == 0 || args->num_contexts < num) {
+		args->num_contexts = num;
+		return 0;
+	}
+
+	contexts = kvzalloc_objs(*contexts, num);
+	if (!contexts)
+		return -ENOMEM;
+
+	xa_lock(&mgr->ctx_handles);
+	xa_for_each(&mgr->ctx_handles, id, ctx) {
+		struct drm_amdgpu_gem_list_contexts_entry *context;
+		enum amd_dpm_forced_level level;
+
+		if (idx >= num) {
+			ret = -EAGAIN;
+			break;
+		}
+
+		kref_get(&ctx->refcount);
+		xa_unlock(&mgr->ctx_handles);
+
+		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);
+
+		idx++;
+		amdgpu_ctx_put(ctx);
+		xa_lock(&mgr->ctx_handles);
+	}
+	xa_unlock(&mgr->ctx_handles);
+
+	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 0ab380ca7e64..5f0abdfe0063 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -3104,6 +3104,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
 	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_PROC_OPTIONS, amdgpu_proc_options_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 9baa9a4b6b3d..27b32eed6f3a 100644
--- a/include/uapi/drm/amdgpu_drm.h
+++ b/include/uapi/drm/amdgpu_drm.h
@@ -59,6 +59,7 @@ extern "C" {
 #define DRM_AMDGPU_USERQ_WAIT		0x18
 #define DRM_AMDGPU_GEM_LIST_HANDLES	0x19
 #define DRM_AMDGPU_PROC_OPTIONS		0x1A
+#define DRM_AMDGPU_GEM_LIST_CONTEXTS	0x1B
 
 #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)
@@ -81,6 +82,7 @@ extern "C" {
 #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_PROC_OPTIONS	DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_PROC_OPTIONS, struct drm_amdgpu_proc_options)
+#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
@@ -875,6 +877,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) */
+	__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
-- 
2.54.0