On 22.08.25 21:47, David Francis wrote: > Add new GEM_OP_IOCTL option GET_MAPPING_INFO, which > returns a list of mappings associated with a given bo, along with > their positions and offsets. > > Signed-off-by: David Francis <david.fran...@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 98 ++++++++++++++++++++++++- > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 5 ++ > include/uapi/drm/amdgpu_drm.h | 21 +++++- > 3 files changed, 120 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > index e6741d6c9a55..15d588f7acdf 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c > @@ -948,6 +948,70 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void > *data, > return r; > } > > +/** > + * amdgpu_gem_list_mappings - get information about a buffer's mappings > + * > + * @gobj: gem object > + * @args: gem_op arguments > + * @fpriv: drm file pointer > + * > + * num_entries is set as an input to the size of the user-allocated array of > + * drm_amdgpu_gem_vm_entry stored at args->value. > + * num_entries is sent back as output as the number of mappings the bo has. > + * If that number is larger than the size of the array, the ioctl must > + * be retried. > + * > + * Returns: > + * 0 for success, -errno for errors. > + */ > +static int amdgpu_gem_list_mappings(struct drm_gem_object *gobj, struct > amdgpu_fpriv *fpriv, > + struct drm_amdgpu_gem_op *args) > +{ > + struct amdgpu_vm *avm = &fpriv->vm; > + struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj); > + struct amdgpu_bo_va *bo_va = amdgpu_vm_bo_find(avm, bo); > + struct drm_amdgpu_gem_vm_entry *vm_entries; > + struct amdgpu_bo_va_mapping *mapping; > + int num_mappings = 0; > + int ret; > + > + if (args->padding) > + return -EINVAL; > + > + vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), > GFP_KERNEL); > + if (!vm_entries) > + return -ENOMEM; > + > + amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) { > + if (num_mappings < args->num_entries) { > + vm_entries[num_mappings].addr = mapping->start * > AMDGPU_GPU_PAGE_SIZE; > + vm_entries[num_mappings].size = (mapping->last - > mapping->start + 1) * AMDGPU_GPU_PAGE_SIZE; > + vm_entries[num_mappings].offset = mapping->offset; > + vm_entries[num_mappings].flags = mapping->flags; > + } > + num_mappings += 1; > + } > + > + amdgpu_vm_bo_va_for_each_invalid_mapping(bo_va, mapping) { > + if (num_mappings < args->num_entries) { > + vm_entries[num_mappings].addr = mapping->start * > AMDGPU_GPU_PAGE_SIZE; > + vm_entries[num_mappings].size = (mapping->last - > mapping->start + 1) * AMDGPU_GPU_PAGE_SIZE; > + vm_entries[num_mappings].offset = mapping->offset; > + vm_entries[num_mappings].flags = mapping->flags; > + } > + num_mappings += 1; > + } > + > + if (num_mappings > 0 && num_mappings <= args->num_entries) > + ret = copy_to_user(u64_to_user_ptr(args->value), vm_entries, > num_mappings * sizeof(*vm_entries)); > + > + args->num_entries = num_mappings; > + > + kvfree(vm_entries); > + > + return ret; > +} > + > int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, > struct drm_file *filp) > { > @@ -955,6 +1019,8 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void > *data, > struct drm_gem_object *gobj; > struct amdgpu_vm_bo_base *base; > struct amdgpu_bo *robj; > + struct drm_exec exec; > + struct amdgpu_fpriv *fpriv = filp->driver_priv; > int r; > > gobj = drm_gem_object_lookup(filp, args->handle); > @@ -963,9 +1029,27 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void > *data, > > robj = gem_to_amdgpu_bo(gobj); > > - r = amdgpu_bo_reserve(robj, false); > - if (unlikely(r)) > - goto out;
> + if (args->op == AMDGPU_GEM_OP_GET_MAPPING_INFO) { > + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | > + DRM_EXEC_IGNORE_DUPLICATES, 0); > + drm_exec_until_all_locked(&exec) { > + if (gobj) { > + r = drm_exec_lock_obj(&exec, gobj); > + drm_exec_retry_on_contention(&exec); > + if (r) > + goto out_exec; > + } > + > + r = amdgpu_vm_lock_pd(&fpriv->vm, &exec, 0); > + drm_exec_retry_on_contention(&exec); > + if (r) > + goto out_exec; > + } > + } else { > + r = amdgpu_bo_reserve(robj, false); > + if (unlikely(r)) > + goto out; > + } Just simplify that into: drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, gobj); drm_exec_retry_on_contention(&exec); if (r) goto out_exec; switch(args->op) { ... case AMDGPU_GEM_OP_GET_MAPPING_INFO: r = amdgpu_vm_lock_pd(&fpriv->vm, &exec, 0); drm_exec_retry_on_contention(&exec); if (r) goto out_exec; ... } Regards, Christian. > > switch (args->op) { > case AMDGPU_GEM_OP_GET_GEM_CREATE_INFO: { > @@ -1014,6 +1098,10 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void > *data, > > amdgpu_bo_unreserve(robj); > break; > + case AMDGPU_GEM_OP_GET_MAPPING_INFO: > + r = amdgpu_gem_list_mappings(gobj, fpriv, args); > + drm_exec_fini(&exec); > + break; > default: > amdgpu_bo_unreserve(robj); > r = -EINVAL; > @@ -1022,6 +1110,10 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void > *data, > out: > drm_gem_object_put(gobj); > return r; > +out_exec: > + drm_exec_fini(&exec); > + drm_gem_object_put(gobj); > + return r; > } > > /** > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > index f9549f6b3d1f..5a63ae490b0e 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > @@ -668,4 +668,9 @@ void amdgpu_vm_tlb_fence_create(struct amdgpu_device > *adev, > struct amdgpu_vm *vm, > struct dma_fence **fence); > > +#define amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) \ > + list_for_each_entry(mapping, &bo_va->valids, list) > +#define amdgpu_vm_bo_va_for_each_invalid_mapping(bo_va, mapping) \ > + list_for_each_entry(mapping, &bo_va->invalids, list) > + > #endif > diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h > index e5d1c24cabcb..2e7a4e599e5b 100644 > --- a/include/uapi/drm/amdgpu_drm.h > +++ b/include/uapi/drm/amdgpu_drm.h > @@ -802,6 +802,21 @@ union drm_amdgpu_wait_fences { > > #define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO 0 > #define AMDGPU_GEM_OP_SET_PLACEMENT 1 > +#define AMDGPU_GEM_OP_GET_MAPPING_INFO 2 > + > +struct drm_amdgpu_gem_vm_entry { > + /* Start of mapping (in bytes) */ > + __u64 addr; > + > + /* Size of mapping (in bytes) */ > + __u64 size; > + > + /* Mapping offset */ > + __u64 offset; > + > + /* flags needed to recreate mapping */ > + __u64 flags; > +}; > > /* Sets or returns a value associated with a buffer. */ > struct drm_amdgpu_gem_op { > @@ -809,8 +824,12 @@ struct drm_amdgpu_gem_op { > __u32 handle; > /** AMDGPU_GEM_OP_* */ > __u32 op; > - /** Input or return value */ > + /** Input or return value. For MAPPING_INFO op: pointer to array of > struct drm_amdgpu_gem_vm_entry */ > __u64 value; > + /** For MAPPING_INFO op: number of mappings (in/out) */ > + __u32 num_entries; > + > + __u32 padding; > }; > > #define AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT (1 << 0)