On 27/05/2026 09:10, Christian König wrote:
On 5/26/26 18:06, Tvrtko Ursulin wrote:
Add a new flag (AMDGPU_GEM_LIST_HANDLES_FLAG_IS_USERPTR) to the
DRM_IOCTL_AMDGPU_GEM_LIST_CONTEXTS ioctl.

This is required to allow for checkpoint and restore of userptr objects.

The existing struct drm_amdgpu_gem_list_handles_entry is used with the
userptr creation flags places in alloc_flags, while the alignment field
contains the userspace address.

Signed-off-by: Tvrtko Ursulin <[email protected]>
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 18 +++++++----
  drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 40 +++++++++++++++++--------
  drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 19 +++++++++++-
  include/uapi/drm/amdgpu_drm.h           |  7 +++--
  4 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 0259d81e5157..5eb8433229b4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -1186,14 +1186,20 @@ int amdgpu_gem_list_handles_ioctl(struct drm_device 
*dev, void *data,
bo_entry = &bo_entries[bo_index]; - bo_entry->size = amdgpu_bo_size(bo);
-               bo_entry->alloc_flags = bo->flags & 
AMDGPU_GEM_CREATE_SETTABLE_MASK;
-               bo_entry->preferred_domains = bo->preferred_domains;
                bo_entry->gem_handle = id;
-               bo_entry->alignment = bo->tbo.page_alignment;
+               bo_entry->size = amdgpu_bo_size(bo);
+               if (amdgpu_ttm_tt_is_userptr(bo->tbo.ttm)) {
+                       bo_entry->flags = 
AMDGPU_GEM_LIST_HANDLES_FLAG_IS_USERPTR;
+                       bo_entry->alloc_flags = 
amdgpu_ttm_tt_get_userptr_flags(bo->tbo.ttm);
+                       bo_entry->alignment = 
amdgpu_ttm_tt_get_userptr_addr(bo->tbo.ttm);
+               } else {
+                       bo_entry->alloc_flags = bo->flags & 
AMDGPU_GEM_CREATE_SETTABLE_MASK;
+                       bo_entry->preferred_domains = bo->preferred_domains;
+                       bo_entry->alignment = bo->tbo.page_alignment;
- if (bo->tbo.base.import_attach)
-                       bo_entry->flags |= 
AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT;
+                       if (bo->tbo.base.import_attach)
+                               bo_entry->flags = 
AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT;
+               }
bo_index += 1;
        }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 3d2e00efc741..4023c84fe29d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -767,6 +767,33 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo,
        return r;
  }
+/*
+ * amdgpu_ttm_tt_is_userptr - Have the pages backing by userptr?
+ */
+bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
+{
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
+
+       if (gtt == NULL || !gtt->userptr)
+               return false;
+
+       return true;
+}
+
+u32 amdgpu_ttm_tt_get_userptr_flags(struct ttm_tt *ttm)
+{
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
+
+       return gtt->userflags;
+}
+
+u64 amdgpu_ttm_tt_get_userptr_addr(struct ttm_tt *ttm)
+{
+       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
+
+       return gtt->userptr;
+}
+
  #endif
/*
@@ -1374,19 +1401,6 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, 
unsigned long start,
        return true;
  }
-/*
- * amdgpu_ttm_tt_is_userptr - Have the pages backing by userptr?
- */
-bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
-{
-       struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
-
-       if (gtt == NULL || !gtt->userptr)
-               return false;
-
-       return true;
-}
-
  /*
   * amdgpu_ttm_tt_is_readonly - Is the ttm_tt object read only?
   */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index f2f23a42b3cc..8c0424577dea 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -211,12 +211,30 @@ uint64_t amdgpu_ttm_domain_start(struct amdgpu_device 
*adev, uint32_t type);
  #if IS_ENABLED(CONFIG_DRM_AMDGPU_USERPTR)
  int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo,
                                 struct amdgpu_hmm_range *range);
+bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm);
+u32 amdgpu_ttm_tt_get_userptr_flags(struct ttm_tt *ttm);
+u64 amdgpu_ttm_tt_get_userptr_addr(struct ttm_tt *ttm);
  #else
  static inline int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo,
                                               struct amdgpu_hmm_range *range)
  {
        return -EPERM;
  }
+
+static inline bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
+{
+       return false;
+}
+
+static inline u32 amdgpu_ttm_tt_get_userptr_flags(struct ttm_tt *ttm)
+{
+       return -1;
+}
+
+static inline u64 amdgpu_ttm_tt_get_userptr_addr(struct ttm_tt *ttm)
+{
+       return 0;
+}
  #endif
/**
@@ -251,7 +269,6 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, 
unsigned long start,
                                  unsigned long end, unsigned long *userptr);
  bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm,
                                       int *last_invalidated);
-bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm);
  bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
  uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource 
*mem);
  uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt 
*ttm,
diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
index 9f3090db2f16..3069560ac26e 100644
--- a/include/uapi/drm/amdgpu_drm.h
+++ b/include/uapi/drm/amdgpu_drm.h
@@ -836,6 +836,7 @@ struct drm_amdgpu_gem_op {
  };
#define AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT (1 << 0)
+#define AMDGPU_GEM_LIST_HANDLES_FLAG_IS_USERPTR        (1 << 1)
struct drm_amdgpu_gem_list_handles {
        /* User pointer to array of drm_amdgpu_gem_bo_info_entry */
@@ -851,7 +852,7 @@ struct drm_amdgpu_gem_list_handles_entry {
        /* gem handle of buffer object */
        __u32 gem_handle;
- /* Currently just one flag: IS_IMPORT */
+       /* AMDGPU_GEM_LIST_HANDLES_FLAG_* */
        __u32 flags;
/* Size of bo */
@@ -860,10 +861,10 @@ struct drm_amdgpu_gem_list_handles_entry {
        /* Preferred domains for GEM_CREATE */
        __u64 preferred_domains;
- /* GEM_CREATE flags for re-creation of buffer */
+       /* GEM_CREATE flags for re-creation of buffer or 
drm_amdgpu_gem_userptr.flags */
        __u64 alloc_flags;
- /* physical start_addr alignment in bytes for some HW requirements */
+       /* physical start_addr alignment in bytes for some HW requirements or 
drm_amdgpu_gem_userptr.addr */
        __u64 alignment;

Make that an union, e.g. union { __u64 alignment; __u64 userptr; }, apart looks 
pretty good to me.

Ack, marking as a TODO for a future respin, thank you!

Regards,

Tvrtko

Reply via email to