diff options
Diffstat (limited to 'meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/1561-drm-amdkfd-initial-implementation-of-handle-based-IP.patch')
-rw-r--r-- | meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/1561-drm-amdkfd-initial-implementation-of-handle-based-IP.patch | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/1561-drm-amdkfd-initial-implementation-of-handle-based-IP.patch b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/1561-drm-amdkfd-initial-implementation-of-handle-based-IP.patch new file mode 100644 index 00000000..ca0a437f --- /dev/null +++ b/meta-v1000/recipes-kernel/linux/linux-yocto-4.14.71/1561-drm-amdkfd-initial-implementation-of-handle-based-IP.patch @@ -0,0 +1,690 @@ +From 67115bb6b36683f65f4baf1c3e4c47b6799bd663 Mon Sep 17 00:00:00 2001 +From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com> +Date: Sun, 20 Nov 2016 10:14:05 -0500 +Subject: [PATCH 1561/4131] drm/amdkfd: initial implementation of handle based + IPC + +To implement IPC support for legacy compute APIs, we need a handle based +sharing interface. The interfaces are incompatible with DMABUF, which +would be preferable for enhanced security (explicit sharing, and no +extra code for handle management that increases the attack vectors). + +The handles are 128bit wide to prevent inter-process snooping. + +The buffer lifetime is refcounted. As long as one process maintains a +reference to the buffer, the handle and the memory will be valid. + +Change-Id: I9f9b8e149eb1c540f6b1ef6429e56bf9533f0a9a +Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com> +--- + drivers/gpu/drm/amd/amdkfd/Makefile | 2 +- + drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 87 +++++--- + drivers/gpu/drm/amd/amdkfd/kfd_ipc.c | 331 +++++++++++++++++++++++++++++++ + drivers/gpu/drm/amd/amdkfd/kfd_ipc.h | 52 +++++ + drivers/gpu/drm/amd/amdkfd/kfd_module.c | 4 + + drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 9 +- + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 10 +- + 7 files changed, 459 insertions(+), 36 deletions(-) + create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_ipc.c + create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_ipc.h + +diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile +index 8f3cbf6..84646ed 100644 +--- a/drivers/gpu/drm/amd/amdkfd/Makefile ++++ b/drivers/gpu/drm/amd/amdkfd/Makefile +@@ -17,7 +17,7 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ + kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \ + kfd_interrupt.o kfd_events.o cik_event_interrupt.o \ + kfd_dbgdev.o kfd_dbgmgr.o kfd_flat_memory.o kfd_crat.o kfd_rdma.o \ +- kfd_peerdirect.o ++ kfd_peerdirect.o kfd_ipc.o + + amdkfd-$(CONFIG_DEBUG_FS) += kfd_debugfs.o + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +index f28b1c3..e664471 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -37,6 +37,7 @@ + #include "kfd_priv.h" + #include "kfd_device_queue_manager.h" + #include "kfd_dbgmgr.h" ++#include "kfd_ipc.h" + #include "cik_regs.h" + + static long kfd_ioctl(struct file *, unsigned int, unsigned long); +@@ -1179,7 +1180,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, + + down_write(&p->lock); + idr_handle = kfd_process_device_create_obj_handle(pdd, mem, +- args->va_addr, args->size); ++ args->va_addr, args->size, NULL); + up_write(&p->lock); + if (idr_handle < 0) { + dev->kfd2kgd->free_memory_of_gpu(dev->kgd, +@@ -1320,7 +1321,7 @@ static int kfd_ioctl_alloc_memory_of_gpu_new(struct file *filep, + + down_write(&p->lock); + idr_handle = kfd_process_device_create_obj_handle(pdd, mem, +- args->va_addr, args->size); ++ args->va_addr, args->size, NULL); + up_write(&p->lock); + if (idr_handle < 0) { + dev->kfd2kgd->free_memory_of_gpu(dev->kgd, +@@ -1671,7 +1672,7 @@ static int kfd_ioctl_open_graphic_handle(struct file *filep, + * the corresponding interval tree. We need to know the size of + * the buffer through open_graphic_handle(). We use 1 for now.*/ + idr_handle = kfd_process_device_create_obj_handle(pdd, mem, +- args->va_addr, 1); ++ args->va_addr, 1, NULL); + up_write(&p->lock); + if (idr_handle < 0) { + /* FIXME: destroy_process_gpumem doesn't seem to be +@@ -1776,47 +1777,62 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep, + } + + static int kfd_ioctl_import_dmabuf(struct file *filep, +- struct kfd_process *p, void *data) ++ struct kfd_process *p, void *data) + { + struct kfd_ioctl_import_dmabuf_args *args = data; + struct kfd_dev *dev; +- struct kfd_process_device *pdd; +- void *mem; +- uint64_t size; +- int idr_handle; + int r; + + dev = kfd_device_by_id(args->gpu_id); +- if (!dev || !dev->kfd2kgd->import_dmabuf) ++ if (!dev) + return -EINVAL; + +- down_write(&p->lock); +- pdd = kfd_bind_process_to_device(dev, p); +- up_write(&p->lock); +- if (IS_ERR(pdd) < 0) +- return PTR_ERR(pdd); ++ r = kfd_ipc_import_dmabuf(dev, p, args->gpu_id, args->dmabuf_fd, ++ args->va_addr, &args->handle, NULL); ++ if (r) ++ dev_err(kfd_device, "Failed to import dmabuf\n"); ++ ++ return r; ++} ++ ++static int kfd_ioctl_ipc_export_handle(struct file *filep, ++ struct kfd_process *p, ++ void *data) ++{ ++ struct kfd_ioctl_ipc_export_handle_args *args = data; ++ struct kfd_dev *dev; ++ int r; + +- r = dev->kfd2kgd->import_dmabuf(dev->kgd, args->dmabuf_fd, +- args->va_addr, pdd->vm, +- (struct kgd_mem **)&mem, &size, +- NULL); ++ dev = kfd_device_by_id(args->gpu_id); ++ if (!dev) ++ return -EINVAL; ++ ++ r = kfd_ipc_export_as_handle(dev, p, args->handle, args->share_handle); + if (r) +- return r; ++ dev_err(kfd_device, "Failed to export IPC handle\n"); + +- down_write(&p->lock); +- idr_handle = kfd_process_device_create_obj_handle(pdd, mem, +- args->va_addr, size); +- up_write(&p->lock); +- if (idr_handle < 0) { +- dev->kfd2kgd->free_memory_of_gpu(dev->kgd, +- (struct kgd_mem *)mem, +- pdd->vm); +- return -EFAULT; +- } ++ return r; ++} + +- args->handle = MAKE_HANDLE(args->gpu_id, idr_handle); ++static int kfd_ioctl_ipc_import_handle(struct file *filep, ++ struct kfd_process *p, ++ void *data) ++{ ++ struct kfd_ioctl_ipc_import_handle_args *args = data; ++ struct kfd_dev *dev = NULL; ++ int r; + +- return 0; ++ dev = kfd_device_by_id(args->gpu_id); ++ if (!dev) ++ return -EINVAL; ++ ++ r = kfd_ipc_import_handle(dev, p, args->gpu_id, args->share_handle, ++ args->va_addr, &args->handle, ++ &args->mmap_offset); ++ if (r) ++ dev_err(kfd_device, "Failed to import IPC handle\n"); ++ ++ return r; + } + + static int kfd_ioctl_get_tile_config(struct file *filep, +@@ -1958,7 +1974,14 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { + kfd_ioctl_import_dmabuf, 0), + + AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_TILE_CONFIG, +- kfd_ioctl_get_tile_config, 0) ++ kfd_ioctl_get_tile_config, 0), ++ ++ AMDKFD_IOCTL_DEF(AMDKFD_IOC_IPC_IMPORT_HANDLE, ++ kfd_ioctl_ipc_import_handle, 0), ++ ++ AMDKFD_IOCTL_DEF(AMDKFD_IOC_IPC_EXPORT_HANDLE, ++ kfd_ioctl_ipc_export_handle, 0) ++ + }; + + #define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c +new file mode 100644 +index 0000000..edd2d43 +--- /dev/null ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c +@@ -0,0 +1,331 @@ ++/* ++ * Copyright 2014 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include <linux/dma-buf.h> ++#include <linux/assoc_array.h> ++#include <linux/slab.h> ++#include <linux/random.h> ++ ++#include "kfd_ipc.h" ++#include "kfd_priv.h" ++ ++/** ++ * The assoc_array data structure provides a non-intrusive ++ * key-value data store mechanism where the key can be ++ * arbitratily long (and value is just a void*). ++ * ++ * This provides us good control for managing IPC handle length ++ * in case we require extra entropy to discourage handle-guessing. ++ */ ++static struct assoc_array ipc_handles; ++ ++static unsigned long ipc_get_key_chunk(const void *index_key, int level) ++{ ++ unsigned long chunk; ++ int index = level/ASSOC_ARRAY_KEY_CHUNK_SIZE; ++ ++ /* no more data, but we can't fail */ ++ if (level > IPC_KEY_SIZE_BYTES*8) ++ return 0; ++ ++ chunk = ((unsigned long *)index_key)[index]; ++ return chunk; ++} ++ ++static unsigned long ipc_get_object_key_chunk(const void *object, int level) ++{ ++ const struct kfd_ipc_obj *obj = (const struct kfd_ipc_obj *)object; ++ ++ return ipc_get_key_chunk(&obj->key, level); ++} ++ ++static bool ipc_compare_object(const void *object, const void *index_key) ++{ ++ const struct kfd_ipc_obj *obj = (const struct kfd_ipc_obj *)object; ++ ++ return memcmp(obj->key, index_key, IPC_KEY_SIZE_BYTES) == 0; ++} ++ ++/* ++ * Compare the index keys of a pair of objects and determine the bit position ++ * at which they differ - if they differ. ++ */ ++static int ipc_diff_objects(const void *object, const void *index_key) ++{ ++ const struct kfd_ipc_obj *obj = (const struct kfd_ipc_obj *)object; ++ int i; ++ ++ /* naive linear byte search */ ++ for (i = 0; i < IPC_KEY_SIZE_BYTES; ++i) { ++ if (obj->key[i] != ((char *)index_key)[i]) ++ return i * 8; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Free an object after stripping the ipc flag off of the pointer. ++ */ ++static void ipc_free_object(void *object) ++{ ++} ++ ++/* ++ * Operations for ipc management by the index-tree routines. ++ */ ++static const struct assoc_array_ops ipc_assoc_array_ops = { ++ .get_key_chunk = ipc_get_key_chunk, ++ .get_object_key_chunk = ipc_get_object_key_chunk, ++ .compare_object = ipc_compare_object, ++ .diff_objects = ipc_diff_objects, ++ .free_object = ipc_free_object, ++}; ++ ++static void ipc_gen_key(void *buf) ++{ ++ uint32_t *key = (uint32_t *) buf; ++ ++ get_random_bytes(buf, IPC_KEY_SIZE_BYTES); ++ ++ /* last byte of the key is reserved */ ++ key[3] = (key[3] & ~0xFF) | 0x1; ++} ++ ++static int ipc_store_insert(void *val, void *key, struct kfd_ipc_obj **ipc_obj) ++{ ++ struct kfd_ipc_obj *obj; ++ struct assoc_array_edit *edit; ++ ++ obj = kmalloc(sizeof(struct kfd_ipc_obj), GFP_KERNEL); ++ if (!obj) ++ return -ENOMEM; ++ ++ /* The initial ref belongs to the allocator process. ++ * The IPC object store itself does not hold a ref since ++ * there is no specific moment in time where that ref should ++ * be dropped, except "when there are no more userspace processes ++ * holding a ref to the object". Therefore the removal from IPC ++ * storage happens at ipc_obj release time. ++ */ ++ kref_init(&obj->ref); ++ obj->data = val; ++ ipc_gen_key(obj->key); ++ ++ memcpy(key, obj->key, IPC_KEY_SIZE_BYTES); ++ ++ pr_debug("ipc: val::%p ref:%p\n", val, &obj->ref); ++ ++ edit = assoc_array_insert(&ipc_handles, ++ &ipc_assoc_array_ops, ++ obj->key, obj); ++ assoc_array_apply_edit(edit); ++ ++ if (ipc_obj) ++ *ipc_obj = obj; ++ ++ return 0; ++} ++ ++static int ipc_store_remove(void *key) ++{ ++ struct assoc_array_edit *edit; ++ ++ edit = assoc_array_delete(&ipc_handles, &ipc_assoc_array_ops, key); ++ assoc_array_apply_edit(edit); ++ return 0; ++} ++ ++static void ipc_obj_release(struct kref *r) ++{ ++ struct kfd_ipc_obj *obj; ++ ++ obj = container_of(r, struct kfd_ipc_obj, ref); ++ ++ ipc_store_remove(obj->key); ++ dma_buf_put(obj->data); ++ kfree(obj); ++} ++ ++void ipc_obj_get(struct kfd_ipc_obj *obj) ++{ ++ kref_get(&obj->ref); ++} ++ ++void ipc_obj_put(struct kfd_ipc_obj **obj) ++{ ++ kref_put(&(*obj)->ref, ipc_obj_release); ++ *obj = NULL; ++} ++ ++int kfd_ipc_init(void) ++{ ++ assoc_array_init(&ipc_handles); ++ return 0; ++} ++ ++static int kfd_import_dmabuf_create_kfd_bo(struct kfd_dev *dev, ++ struct kfd_process *p, ++ uint32_t gpu_id, int dmabuf_fd, ++ uint64_t va_addr, uint64_t *handle, ++ uint64_t *mmap_offset, ++ struct kfd_ipc_obj *ipc_obj) ++{ ++ int r; ++ void *mem; ++ uint64_t size; ++ int idr_handle; ++ struct kfd_process_device *pdd = NULL; ++ uint64_t kfd_mmap_flags = KFD_MMAP_TYPE_MAP_BO | ++ KFD_MMAP_GPU_ID(gpu_id); ++ ++ if (!handle) ++ return -EINVAL; ++ ++ if (!dev || !dev->kfd2kgd->import_dmabuf) ++ return -EINVAL; ++ ++ down_write(&p->lock); ++ pdd = kfd_bind_process_to_device(dev, p); ++ up_write(&p->lock); ++ if (IS_ERR(pdd) < 0) ++ return PTR_ERR(pdd); ++ ++ r = dev->kfd2kgd->import_dmabuf(dev->kgd, dmabuf_fd, ++ va_addr, pdd->vm, ++ (struct kgd_mem **)&mem, &size, ++ mmap_offset); ++ if (r) ++ return r; ++ ++ down_write(&p->lock); ++ idr_handle = kfd_process_device_create_obj_handle(pdd, mem, ++ va_addr, size, ++ ipc_obj); ++ up_write(&p->lock); ++ if (idr_handle < 0) { ++ dev->kfd2kgd->free_memory_of_gpu(dev->kgd, ++ (struct kgd_mem *)mem, ++ pdd->vm); ++ return -EFAULT; ++ } ++ ++ *handle = MAKE_HANDLE(gpu_id, idr_handle); ++ ++ if (mmap_offset) ++ *mmap_offset = (kfd_mmap_flags << PAGE_SHIFT) | *mmap_offset; ++ ++ return r; ++} ++ ++int kfd_ipc_import_dmabuf(struct kfd_dev *dev, ++ struct kfd_process *p, ++ uint32_t gpu_id, int dmabuf_fd, ++ uint64_t va_addr, uint64_t *handle, ++ uint64_t *mmap_offset) ++{ ++ return kfd_import_dmabuf_create_kfd_bo(dev, p, gpu_id, dmabuf_fd, ++ va_addr, handle, mmap_offset, ++ NULL); ++} ++ ++int kfd_ipc_import_handle(struct kfd_dev *dev, struct kfd_process *p, ++ uint32_t gpu_id, uint32_t *share_handle, ++ uint64_t va_addr, uint64_t *handle, ++ uint64_t *mmap_offset) ++{ ++ int r; ++ int dmabuf_fd; ++ struct kfd_ipc_obj *found; ++ ++ found = assoc_array_find(&ipc_handles, ++ &ipc_assoc_array_ops, ++ share_handle); ++ if (!found) ++ return -EINVAL; ++ ipc_obj_get(found); ++ ++ pr_debug("ipc: found ipc_dma_buf: %p\n", found->data); ++ ++ dmabuf_fd = dma_buf_fd(found->data, 0); ++ r = kfd_import_dmabuf_create_kfd_bo(dev, p, gpu_id, dmabuf_fd, ++ va_addr, handle, mmap_offset, ++ found); ++ if (r) ++ goto error_unref; ++ ++ return r; ++ ++error_unref: ++ ipc_obj_put(&found); ++ return r; ++} ++ ++int kfd_ipc_export_as_handle(struct kfd_dev *dev, struct kfd_process *p, ++ uint64_t handle, uint32_t *ipc_handle) ++{ ++ struct kfd_process_device *pdd = NULL; ++ struct kfd_ipc_obj *obj; ++ struct kfd_bo *kfd_bo = NULL; ++ int dmabuf_fd; ++ int r; ++ ++ if (!dev || !ipc_handle) ++ return -EINVAL; ++ ++ down_write(&p->lock); ++ pdd = kfd_bind_process_to_device(dev, p); ++ up_write(&p->lock); ++ ++ if (IS_ERR(pdd) < 0) { ++ pr_err("failed to get pdd\n"); ++ return PTR_ERR(pdd); ++ } ++ ++ down_write(&p->lock); ++ kfd_bo = kfd_process_device_find_bo(pdd, GET_IDR_HANDLE(handle)); ++ up_write(&p->lock); ++ ++ if (!kfd_bo) { ++ pr_err("failed to get bo"); ++ return -EINVAL; ++ } ++ if (kfd_bo->kfd_ipc_obj) { ++ memcpy(ipc_handle, kfd_bo->kfd_ipc_obj->key, ++ sizeof(kfd_bo->kfd_ipc_obj->key)); ++ return 0; ++ } ++ ++ r = dev->kfd2kgd->export_dmabuf(dev->kgd, pdd->vm, ++ (struct kgd_mem *)kfd_bo->mem, ++ &dmabuf_fd); ++ if (r) ++ goto err; ++ ++ r = ipc_store_insert(dma_buf_get(dmabuf_fd), ipc_handle, &obj); ++ if (r) ++ goto err; ++ ++ kfd_bo->kfd_ipc_obj = obj; ++err: ++ return r; ++} +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h +new file mode 100644 +index 0000000..52049d2 +--- /dev/null ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright 2014 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ */ ++ ++#ifndef KFD_IPC_H_ ++#define KFD_IPC_H_ ++ ++#include <linux/types.h> ++#include "kfd_priv.h" ++ ++#define IPC_KEY_SIZE_BYTES 16 ++ ++struct kfd_ipc_obj { ++ struct kref ref; ++ void *data; ++ char key[IPC_KEY_SIZE_BYTES]; ++}; ++ ++int kfd_ipc_import_handle(struct kfd_dev *dev, struct kfd_process *p, ++ uint32_t gpu_id, uint32_t *share_handle, ++ uint64_t va_addr, uint64_t *handle, ++ uint64_t *mmap_offset); ++int kfd_ipc_import_dmabuf(struct kfd_dev *kfd, struct kfd_process *p, ++ uint32_t gpu_id, int dmabuf_fd, ++ uint64_t va_addr, uint64_t *handle, ++ uint64_t *mmap_offset); ++int kfd_ipc_export_as_handle(struct kfd_dev *dev, struct kfd_process *p, ++ uint64_t handle, uint32_t *ipc_handle); ++ ++void ipc_obj_get(struct kfd_ipc_obj *obj); ++void ipc_obj_put(struct kfd_ipc_obj **obj); ++ ++#endif /* KFD_IPC_H_ */ +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c +index ca82a02..274312f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c +@@ -133,6 +133,10 @@ static int __init kfd_module_init(void) + if (err < 0) + goto err_topology; + ++ err = kfd_ipc_init(); ++ if (err < 0) ++ goto err_topology; ++ + kfd_process_create_wq(); + + kfd_init_peer_direct(); +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +index d96d256..40dd5db 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +@@ -280,11 +280,14 @@ struct kfd_dev { + uint32_t ib_size; + }; + ++struct kfd_ipc_obj; ++ + struct kfd_bo { + void *mem; + struct interval_tree_node it; + struct kfd_dev *dev; + struct list_head cb_data_head; ++ struct kfd_ipc_obj *kfd_ipc_obj; + }; + + /* KGD2KFD callbacks */ +@@ -729,7 +732,8 @@ int kfd_reserved_mem_mmap(struct kfd_process *process, struct vm_area_struct *vm + /* KFD process API for creating and translating handles */ + int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd, + void *mem, uint64_t start, +- uint64_t length); ++ uint64_t length, ++ struct kfd_ipc_obj *ipc_obj); + void *kfd_process_device_translate_handle(struct kfd_process_device *p, + int handle); + struct kfd_bo *kfd_process_device_find_bo(struct kfd_process_device *pdd, +@@ -964,6 +968,9 @@ int dbgdev_wave_reset_wavefronts(struct kfd_dev *dev, struct kfd_process *p); + void kfd_init_peer_direct(void); + void kfd_close_peer_direct(void); + ++/* IPC Support */ ++int kfd_ipc_init(void); ++ + /* Debugfs */ + #if defined(CONFIG_DEBUG_FS) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +index fa13696..63e85de 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -32,6 +32,7 @@ + #include <asm/tlb.h> + #include <linux/highmem.h> + #include <uapi/asm-generic/mman-common.h> ++#include "kfd_ipc.h" + + struct mm_struct; + +@@ -118,7 +119,7 @@ static int kfd_process_alloc_gpuvm(struct kfd_process *p, + * created and the ioctls have not had the chance to run. + */ + if (kfd_process_device_create_obj_handle( +- pdd, mem, gpu_va, size) < 0) { ++ pdd, mem, gpu_va, size, NULL) < 0) { + err = -ENOMEM; + *kptr = NULL; + goto free_gpuvm; +@@ -803,7 +804,8 @@ bool kfd_has_process_device_data(struct kfd_process *p) + * Assumes that the process lock is held. */ + int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd, + void *mem, uint64_t start, +- uint64_t length) ++ uint64_t length, ++ struct kfd_ipc_obj *ipc_obj) + { + int handle; + struct kfd_bo *buf_obj; +@@ -825,6 +827,7 @@ int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd, + + buf_obj->mem = mem; + buf_obj->dev = pdd->dev; ++ buf_obj->kfd_ipc_obj = ipc_obj; + + INIT_LIST_HEAD(&buf_obj->cb_data_head); + +@@ -904,6 +907,9 @@ void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd, + + buf_obj = kfd_process_device_find_bo(pdd, handle); + ++ if (buf_obj->kfd_ipc_obj) ++ ipc_obj_put(&buf_obj->kfd_ipc_obj); ++ + idr_remove(&pdd->alloc_idr, handle); + + interval_tree_remove(&buf_obj->it, &p->bo_interval_tree); +-- +2.7.4 + |