diff mbox series

[16/18] drm/ttm: Implement struct ttm_global_item and helpers

Message ID 20181019085423.28159-17-tzimmermann@suse.de (mailing list archive)
State New, archived
Headers show
Series Provide a nice interface for TTM global state | expand

Commit Message

Thomas Zimmermann Oct. 19, 2018, 8:54 a.m. UTC
The data structure struct ttm_global_item is a replacement for struct
drm_global_item. While struct drm_global_item depends on global data
instances, struct ttm_global_item allows drivers to use their own privat
instances.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/ttm/ttm_global.c | 98 ++++++++++++++++++++++++++++++++
 include/drm/ttm/ttm_global.h     | 22 +++++++
 2 files changed, 120 insertions(+)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/ttm/ttm_global.c
index ca9da0a46147..1e5c2f5eeca0 100644
--- a/drivers/gpu/drm/ttm/ttm_global.c
+++ b/drivers/gpu/drm/ttm/ttm_global.c
@@ -31,6 +31,104 @@ 
 #include <drm/ttm/ttm_memory.h>
 #include <linux/kernel.h>
 
+/*
+ * struct ttm_global_item
+ */
+
+struct ttm_global_item {
+	struct mutex mutex;
+	void *object;
+	int refcount;
+};
+
+#define TTM_GLOBAL_ITEM_INIT(name_) { \
+	.mutex = __MUTEX_INITIALIZER(name_.mutex), \
+	.object = NULL, \
+	.refcount = 0 }
+
+#define DEFINE_TTM_GLOBAL_ITEM_ARRAY(name_) \
+	struct ttm_global_item name_[TTM_NUM_GLOBAL_TYPES] = { \
+		[0] = TTM_GLOBAL_ITEM_INIT(name_[0]), \
+		[1] = TTM_GLOBAL_ITEM_INIT(name_[0]) \
+	}
+
+/**
+ * ttm_global_item_ref - Initialize and acquire reference to a global TTM item
+ *
+ * @items: Array of global TTM items
+ * @ref: Object for initialization
+ * @return Zero on success, or a negative error code otherwise.
+ *
+ * This initializes a TTM item by allocating memory and calling the
+ * .init() hook. Further calls will increase the reference count for
+ * that item.
+ */
+static int ttm_global_item_ref(
+	struct ttm_global_item items[TTM_NUM_GLOBAL_TYPES],
+	struct ttm_global_ref *ref)
+{
+	struct ttm_global_item *item = &items[ref->global_type];
+	int ret = 0;
+
+	mutex_lock(&item->mutex);
+	if (item->refcount == 0) {
+		ref->object = kzalloc(ref->size, GFP_KERNEL);
+		if (unlikely(ref->object == NULL)) {
+			ret = -ENOMEM;
+			goto error_mutex_unlock;
+		}
+		ret = ref->init(ref);
+		if (unlikely(ret != 0))
+			goto error_kfree;
+
+		item->object = ref->object;
+	} else {
+		ref->object = item->object;
+	}
+
+	++item->refcount;
+	mutex_unlock(&item->mutex);
+
+	return 0;
+
+error_kfree:
+	kfree(ref->object);
+	ref->object = NULL;
+error_mutex_unlock:
+	mutex_unlock(&item->mutex);
+	return ret;
+}
+
+/**
+ * ttm_global_item_unref - Drop reference to global TTM item
+ *
+ * @items: Array of global TTM items
+ * @ref: Object being removed
+ *
+ * Drops a reference to the global TTM item and eventually call the
+ * release() hook. The allocated object should be dropped in the
+ * release() hook or before calling this function
+ */
+static void ttm_global_item_unref(
+	struct ttm_global_item items[TTM_NUM_GLOBAL_TYPES],
+	struct ttm_global_ref *ref)
+{
+	struct ttm_global_item *item = &items[ref->global_type];
+
+	mutex_lock(&item->mutex);
+	BUG_ON(item->refcount == 0);
+	BUG_ON(ref->object != item->object);
+	if (--item->refcount == 0) {
+		ref->release(ref);
+		item->object = NULL;
+	}
+	mutex_unlock(&item->mutex);
+}
+
+/*
+ * struct ttm_global
+ */
+
 static int ttm_global_init_mem(struct drm_global_reference *ref)
 {
 	BUG_ON(!ref->object);
diff --git a/include/drm/ttm/ttm_global.h b/include/drm/ttm/ttm_global.h
index 06e791499f87..9aa0ddbbe2ef 100644
--- a/include/drm/ttm/ttm_global.h
+++ b/include/drm/ttm/ttm_global.h
@@ -29,6 +29,28 @@ 
 #define _TTM_GLOBAL_H_
 
 #include <drm/drm_global.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/**
+ * enum ttm_global_types - Enumerates types of global TTM state
+ */
+enum ttm_global_types {
+	TTM_GLOBAL_MEM = 0,
+	TTM_GLOBAL_BO,
+	TTM_NUM_GLOBAL_TYPES
+};
+
+/**
+ * struct ttm_global_ref - References global TTM item
+ */
+struct ttm_global_ref {
+	enum ttm_global_types global_type;
+	size_t size;
+	void *object;
+	int (*init) (struct ttm_global_ref *);
+	void (*release) (struct ttm_global_ref *);
+};
 
 struct ttm_bo_global;