Exports a DMA buf fd of a given KFD buffer handle. This is intended for
the new upstreamable RDMA solution coming to UCX and libfabric.

The corresponding user mode change (Thunk API and kfdtest) is here:
https://github.com/RadeonOpenCompute/ROCT-Thunk-Interface/commits/fxkamd/dmabuf

Signed-off-by: Felix Kuehling <felix.kuehl...@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h    |  2 +
 .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c  | 45 ++++++++++++----
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c      | 54 +++++++++++++++++++
 include/uapi/linux/kfd_ioctl.h                | 14 ++++-
 4 files changed, 103 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 4cb14c2fe53f..0b8cfe8c72ea 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -294,6 +294,8 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct amdgpu_device 
*adev,
                                      uint64_t va, void *drm_priv,
                                      struct kgd_mem **mem, uint64_t *size,
                                      uint64_t *mmap_offset);
+int amdgpu_amdkfd_gpuvm_export_dmabuf(struct kgd_mem *mem,
+                                     struct dma_buf **dmabuf);
 int amdgpu_amdkfd_get_tile_config(struct amdgpu_device *adev,
                                struct tile_config *config);
 void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 2ac61a1e665e..d23fdebd2552 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -641,6 +641,21 @@ kfd_mem_attach_userptr(struct amdgpu_device *adev, struct 
kgd_mem *mem,
        return 0;
 }
 
+static int kfd_mem_export_dmabuf(struct kgd_mem *mem)
+{
+       if (!mem->dmabuf) {
+               struct dma_buf *ret = amdgpu_gem_prime_export(
+                       &mem->bo->tbo.base,
+                       mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE ?
+                               DRM_RDWR : 0);
+               if (IS_ERR(ret))
+                       return PTR_ERR(ret);
+               mem->dmabuf = ret;
+       }
+
+       return 0;
+}
+
 static int
 kfd_mem_attach_dmabuf(struct amdgpu_device *adev, struct kgd_mem *mem,
                      struct amdgpu_bo **bo)
@@ -648,16 +663,9 @@ kfd_mem_attach_dmabuf(struct amdgpu_device *adev, struct 
kgd_mem *mem,
        struct drm_gem_object *gobj;
        int ret;
 
-       if (!mem->dmabuf) {
-               mem->dmabuf = amdgpu_gem_prime_export(&mem->bo->tbo.base,
-                       mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE ?
-                               DRM_RDWR : 0);
-               if (IS_ERR(mem->dmabuf)) {
-                       ret = PTR_ERR(mem->dmabuf);
-                       mem->dmabuf = NULL;
-                       return ret;
-               }
-       }
+       ret = kfd_mem_export_dmabuf(mem);
+       if (ret)
+               return ret;
 
        gobj = amdgpu_gem_prime_import(adev_to_drm(adev), mem->dmabuf);
        if (IS_ERR(gobj))
@@ -2091,6 +2099,23 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct 
amdgpu_device *adev,
        return ret;
 }
 
+int amdgpu_amdkfd_gpuvm_export_dmabuf(struct kgd_mem *mem,
+                                     struct dma_buf **dma_buf)
+{
+       int ret;
+
+       mutex_lock(&mem->lock);
+       ret = kfd_mem_export_dmabuf(mem);
+       if (ret)
+               goto out;
+
+       get_dma_buf(mem->dmabuf);
+       *dma_buf = mem->dmabuf;
+out:
+       mutex_unlock(&mem->lock);
+       return ret;
+}
+
 /* Evict a userptr BO by stopping the queues if necessary
  *
  * Runs in MMU notifier, may be in RECLAIM_FS context. This means it
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index e1e2362841f8..6f5c5b533862 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1500,6 +1500,58 @@ static int kfd_ioctl_import_dmabuf(struct file *filep,
        return r;
 }
 
+static int kfd_ioctl_export_dmabuf(struct file *filep,
+                                  struct kfd_process *p, void *data)
+{
+       struct kfd_ioctl_export_dmabuf_args *args = data;
+       struct kfd_process_device *pdd;
+       struct dma_buf *dmabuf;
+       struct kfd_dev *dev;
+       void *mem;
+       int ret = 0;
+
+       dev = kfd_device_by_id(GET_GPU_ID(args->handle));
+       if (!dev)
+               return -EINVAL;
+
+       mutex_lock(&p->mutex);
+
+       pdd = kfd_get_process_device_data(dev, p);
+       if (!pdd) {
+               ret = -EINVAL;
+               goto err_unlock;
+       }
+
+       mem = kfd_process_device_translate_handle(pdd,
+                                               GET_IDR_HANDLE(args->handle));
+       if (!mem) {
+               ret = -EINVAL;
+               goto err_unlock;
+       }
+
+       ret = amdgpu_amdkfd_gpuvm_export_dmabuf(mem, &dmabuf);
+       mutex_unlock(&p->mutex);
+       if (ret)
+               goto err_out;
+
+       ret = dma_buf_fd(dmabuf, args->flags);
+       if (ret < 0) {
+               dma_buf_put(dmabuf);
+               goto err_out;
+       }
+       /* dma_buf_fd assigns the reference count to the fd, no need to
+        * put the reference here.
+        */
+       args->dmabuf_fd = ret;
+
+       return 0;
+
+err_unlock:
+       mutex_unlock(&p->mutex);
+err_out:
+       return ret;
+}
+
 /* Handle requests for watching SMI events */
 static int kfd_ioctl_smi_events(struct file *filep,
                                struct kfd_process *p, void *data)
@@ -2656,6 +2708,8 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
        AMDKFD_IOCTL_DEF(AMDKFD_IOC_CRIU_OP,
                        kfd_ioctl_criu, KFD_IOC_FLAG_CHECKPOINT_RESTORE),
 
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_EXPORT_DMABUF,
+                               kfd_ioctl_export_dmabuf, 0),
 };
 
 #define AMDKFD_CORE_IOCTL_COUNT        ARRAY_SIZE(amdkfd_ioctls)
diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h
index eb9ff85f8556..edf7b1648335 100644
--- a/include/uapi/linux/kfd_ioctl.h
+++ b/include/uapi/linux/kfd_ioctl.h
@@ -34,9 +34,10 @@
  * - 1.6 - Query clear flags in SVM get_attr API
  * - 1.7 - Checkpoint Restore (CRIU) API
  * - 1.8 - CRIU - Support for SDMA transfers with GTT BOs
+ * - 1.9 - Add DMA buf export ioctl
  */
 #define KFD_IOCTL_MAJOR_VERSION 1
-#define KFD_IOCTL_MINOR_VERSION 8
+#define KFD_IOCTL_MINOR_VERSION 9
 
 struct kfd_ioctl_get_version_args {
        __u32 major_version;    /* from KFD */
@@ -452,6 +453,12 @@ struct kfd_ioctl_import_dmabuf_args {
        __u32 dmabuf_fd;        /* to KFD */
 };
 
+struct kfd_ioctl_export_dmabuf_args {
+       __u64 handle;           /* to KFD */
+       __u32 flags;            /* to KFD */
+       __u32 dmabuf_fd;        /* from KFD */
+};
+
 /*
  * KFD SMI(System Management Interface) events
  */
@@ -824,7 +831,10 @@ struct kfd_ioctl_set_xnack_mode_args {
 #define AMDKFD_IOC_CRIU_OP                     \
                AMDKFD_IOWR(0x22, struct kfd_ioctl_criu_args)
 
+#define AMDKFD_IOC_EXPORT_DMABUF               \
+               AMDKFD_IOWR(0x23, struct kfd_ioctl_export_dmabuf_args)
+
 #define AMDKFD_COMMAND_START           0x01
-#define AMDKFD_COMMAND_END             0x23
+#define AMDKFD_COMMAND_END             0x24
 
 #endif
-- 
2.32.0

Reply via email to