aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch251
1 files changed, 251 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch
new file mode 100644
index 00000000..88f4be66
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/1564-drm-amdkfd-Remove-assoc_array-dependency-for-IPC.patch
@@ -0,0 +1,251 @@
+From 53d06c5161e208d90d4de21079c2447a0c0b25b6 Mon Sep 17 00:00:00 2001
+From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+Date: Wed, 30 Nov 2016 17:31:04 -0500
+Subject: [PATCH 1564/4131] drm/amdkfd: Remove assoc_array dependency for IPC
+
+Use hash table instead. This makes IPC support compatible with older
+kernels
+
+Change-Id: Ia099f7d99d96dd3741d1ebfa3c2c1c7498ec1a73
+Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_ipc.c | 147 ++++++++++-------------------------
+ drivers/gpu/drm/amd/amdkfd/kfd_ipc.h | 5 +-
+ 2 files changed, 42 insertions(+), 110 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c
+index 5391f8a..62aaeac 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.c
+@@ -21,100 +21,29 @@
+ */
+
+ #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;
++#define KFD_IPC_HASH_TABLE_SIZE_SHIFT 4
++#define KFD_IPC_HASH_TABLE_SIZE_MASK ((1 << KFD_IPC_HASH_TABLE_SIZE_SHIFT) - 1)
+
+- return memcmp(obj->key, index_key, IPC_KEY_SIZE_BYTES) == 0;
+-}
++static struct kfd_ipc_handles {
++ DECLARE_HASHTABLE(handles, KFD_IPC_HASH_TABLE_SIZE_SHIFT);
++ struct mutex lock;
++} kfd_ipc_handles;
+
+-/*
+- * Compare the index keys of a pair of objects and determine the bit position
+- * at which they differ - if they differ.
++/* Since, handles are random numbers, it can be used directly as hashing key.
++ * The least 4 bits of the handle are used as key. However, during import all
++ * 128 bits of the handle are checked to prevent handle snooping.
+ */
+-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;
++#define HANDLE_TO_KEY(sh) ((*(uint64_t *)sh) & KFD_IPC_HASH_TABLE_SIZE_MASK)
+
+- /* 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)
++static int ipc_store_insert(void *val, void *sh, 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)
+@@ -129,16 +58,14 @@ static int ipc_store_insert(void *val, void *key, struct kfd_ipc_obj **ipc_obj)
+ */
+ kref_init(&obj->ref);
+ obj->data = val;
+- ipc_gen_key(obj->key);
++ get_random_bytes(obj->share_handle, sizeof(obj->share_handle));
+
+- memcpy(key, obj->key, IPC_KEY_SIZE_BYTES);
++ memcpy(sh, obj->share_handle, sizeof(obj->share_handle));
+
+- 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);
++ mutex_lock(&kfd_ipc_handles.lock);
++ hlist_add_head(&obj->node,
++ &kfd_ipc_handles.handles[HANDLE_TO_KEY(obj->share_handle)]);
++ mutex_unlock(&kfd_ipc_handles.lock);
+
+ if (ipc_obj)
+ *ipc_obj = obj;
+@@ -146,22 +73,16 @@ static int ipc_store_insert(void *val, void *key, struct kfd_ipc_obj **ipc_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);
++ mutex_lock(&kfd_ipc_handles.lock);
++ hash_del(&obj->node);
++ mutex_unlock(&kfd_ipc_handles.lock);
++
+ dma_buf_put(obj->data);
+ kfree(obj);
+ }
+@@ -179,7 +100,8 @@ void ipc_obj_put(struct kfd_ipc_obj **obj)
+
+ int kfd_ipc_init(void)
+ {
+- assoc_array_init(&ipc_handles);
++ mutex_init(&kfd_ipc_handles.lock);
++ hash_init(kfd_ipc_handles.handles);
+ return 0;
+ }
+
+@@ -262,11 +184,22 @@ int kfd_ipc_import_handle(struct kfd_dev *dev, struct kfd_process *p,
+ uint64_t *mmap_offset)
+ {
+ int r;
+- struct kfd_ipc_obj *found;
++ struct kfd_ipc_obj *entry, *found = NULL;
++
++ mutex_lock(&kfd_ipc_handles.lock);
++ /* Convert the user provided handle to hash key and search only in that
++ * bucket
++ */
++ hlist_for_each_entry(entry,
++ &kfd_ipc_handles.handles[HANDLE_TO_KEY(share_handle)], node) {
++ if (!memcmp(entry->share_handle, share_handle,
++ sizeof(entry->share_handle))) {
++ found = entry;
++ break;
++ }
++ }
++ mutex_unlock(&kfd_ipc_handles.lock);
+
+- found = assoc_array_find(&ipc_handles,
+- &ipc_assoc_array_ops,
+- share_handle);
+ if (!found)
+ return -EINVAL;
+ ipc_obj_get(found);
+@@ -316,8 +249,8 @@ int kfd_ipc_export_as_handle(struct kfd_dev *dev, struct kfd_process *p,
+ return -EINVAL;
+ }
+ if (kfd_bo->kfd_ipc_obj) {
+- memcpy(ipc_handle, kfd_bo->kfd_ipc_obj->key,
+- sizeof(kfd_bo->kfd_ipc_obj->key));
++ memcpy(ipc_handle, kfd_bo->kfd_ipc_obj->share_handle,
++ sizeof(kfd_bo->kfd_ipc_obj->share_handle));
+ return 0;
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h
+index 52049d2..9ee8627 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_ipc.h
+@@ -27,12 +27,11 @@
+ #include <linux/types.h>
+ #include "kfd_priv.h"
+
+-#define IPC_KEY_SIZE_BYTES 16
+-
+ struct kfd_ipc_obj {
++ struct hlist_node node;
+ struct kref ref;
+ void *data;
+- char key[IPC_KEY_SIZE_BYTES];
++ uint32_t share_handle[4];
+ };
+
+ int kfd_ipc_import_handle(struct kfd_dev *dev, struct kfd_process *p,
+--
+2.7.4
+