diff mbox series

[05/15] drm: Add Simple TTM, a memory manager for dedicated VRAM

Message ID 20190408092144.4548-6-tzimmermann@suse.de (mailing list archive)
State New, archived
Headers show
Series Share TTM code among framebuffer drivers | expand

Commit Message

Thomas Zimmermann April 8, 2019, 9:21 a.m. UTC
The Simple TTM memory manager is a helper library that manages dedicated
video memory of simple framebuffer devices. The implementation is based on
the respective code from ast, bochs, and mgag200. These drivers share the
exact same implementation execept for type names.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 Documentation/gpu/drm-mm.rst            |  11 ++
 drivers/gpu/drm/Kconfig                 |   7 +
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/drm_simple_ttm_helper.c | 191 ++++++++++++++++++++++++
 include/drm/drm_simple_ttm_helper.h     |  74 +++++++++
 5 files changed, 284 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_simple_ttm_helper.c
 create mode 100644 include/drm/drm_simple_ttm_helper.h
diff mbox series

Patch

diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index 596e5f15f459..94e8afaa55d2 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -79,6 +79,17 @@  count for the TTM, which will call your initialization function.
 
 See the radeon_ttm.c file for an example of usage.
 
+Simple TTM Helper Functions Reference
+-------------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_simple_ttm_helper.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/drm_simple_ttm_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_simple_ttm_helper.c
+   :export:
 
 The Graphics Execution Manager (GEM)
 ====================================
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 684bd327eb07..fb84ab61fee3 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -166,6 +166,13 @@  config DRM_TTM_HELPER
 	help
 	  Helpers for TTM-based memory management
 
+config DRM_SIMPLE_TTM_HELPER
+	tristate
+	depends on DRM && DRM_TTM
+	select DRM_TTM_HELPER
+	help
+	  Choose this if you need the Simple TTM helper functions
+
 config DRM_GEM_CMA_HELPER
 	bool
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index acd0f3e4f079..54b128ba0b8e 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -35,6 +35,7 @@  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 
 drm_ttm_helper-y := drm_ttm_helper_common.o
 drm_ttm_helper-$(CONFIG_DRM_GEM_TTM_HELPER) += drm_gem_ttm_helper.o
+drm_ttm_helper-$(CONFIG_DRM_SIMPLE_TTM_HELPER) += drm_simple_ttm_helper.o
 obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
diff --git a/drivers/gpu/drm/drm_simple_ttm_helper.c b/drivers/gpu/drm/drm_simple_ttm_helper.c
new file mode 100644
index 000000000000..52471f150f63
--- /dev/null
+++ b/drivers/gpu/drm/drm_simple_ttm_helper.c
@@ -0,0 +1,191 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <drm/drm_simple_ttm_helper.h>
+#include <drm/drmP.h>
+#include <drm/ttm/ttm_page_alloc.h>
+
+/**
+ * DOC: overview
+ *
+ * Simple TTM implements a TTM memory manager for framebuffer devices with
+ * dedicated video memory. It currently support memory regions TTM_PL_VRAM
+ * and TTM_PL_SYSTEM. Support for TTM_PL_TT could probably be added if
+ * necessary.
+ */
+
+/*
+ * TTM TT
+ */
+
+static void backend_func_destroy(struct ttm_tt *tt)
+{
+	ttm_tt_fini(tt);
+	kfree(tt);
+}
+
+static struct ttm_backend_func backend_func = {
+	.destroy = backend_func_destroy
+};
+
+/*
+ * TTM BO device
+ */
+
+static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,
+					      uint32_t page_flags)
+{
+	struct ttm_tt *tt;
+	int ret;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt)
+		return NULL;
+
+	tt->func = &backend_func;
+
+	ret = ttm_tt_init(tt, bo, page_flags);
+	if (ret < 0)
+		goto err_ttm_tt_init;
+
+	return tt;
+
+err_ttm_tt_init:
+	kfree(tt);
+	return NULL;
+}
+
+static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+				   struct ttm_mem_type_manager *man)
+{
+	switch (type) {
+	case TTM_PL_SYSTEM:
+		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_MASK_CACHING;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
+		man->flags = TTM_MEMTYPE_FLAG_FIXED |
+			     TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_FLAG_UNCACHED |
+					 TTM_PL_FLAG_WC;
+		man->default_caching = TTM_PL_FLAG_WC;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void bo_driver_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement)
+{
+	struct drm_simple_ttm *ttm = drm_simple_ttm_of_bdev(bo->bdev);
+
+	if (ttm->funcs && ttm->funcs->evict_flags)
+		ttm->funcs->evict_flags(bo, placement);
+}
+
+static int bo_driver_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+	struct drm_simple_ttm *ttm = drm_simple_ttm_of_bdev(bo->bdev);
+
+	if (!ttm->funcs || !ttm->funcs->verify_access)
+		return 0;
+	return ttm->funcs->verify_access(bo, filp);
+}
+
+static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
+				    struct ttm_mem_reg *mem)
+{
+	struct ttm_mem_type_manager *man = bdev->man + mem->mem_type;
+	struct drm_simple_ttm *ttm = drm_simple_ttm_of_bdev(bdev);
+
+	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+		return -EINVAL;
+
+	mem->bus.addr = NULL;
+	mem->bus.size = mem->num_pages << PAGE_SHIFT;
+
+	switch (mem->mem_type) {
+	case TTM_PL_SYSTEM:	/* nothing to do */
+		mem->bus.offset = 0;
+		mem->bus.base = 0;
+		mem->bus.is_iomem = false;
+		break;
+	case TTM_PL_VRAM:
+		mem->bus.offset = mem->start << PAGE_SHIFT;
+		mem->bus.base = ttm->vram_base;
+		mem->bus.is_iomem = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void bo_driver_io_mem_free(struct ttm_bo_device *bdev,
+				  struct ttm_mem_reg *mem)
+{ }
+
+static struct ttm_bo_driver bo_driver = {
+	.ttm_tt_create = bo_driver_ttm_tt_create,
+	.ttm_tt_populate = ttm_pool_populate,
+	.ttm_tt_unpopulate = ttm_pool_unpopulate,
+	.init_mem_type = bo_driver_init_mem_type,
+	.eviction_valuable = ttm_bo_eviction_valuable,
+	.evict_flags = bo_driver_evict_flags,
+	.verify_access = bo_driver_verify_access,
+	.io_mem_reserve = bo_driver_io_mem_reserve,
+	.io_mem_free = bo_driver_io_mem_free,
+};
+
+/*
+ * struct drm_simple_ttm
+ */
+
+/**
+ * drm_simple_ttm_init() - Initialize an instance of Simple TTM.
+ * @ttm:	the Simple TTM instance to initialize
+ * @dev:	the DRM device
+ * @vram_base:	the base address of the video memory
+ * @vram_size:	the size of the video memory in bytes
+ * @funcs:	callback functions for buffer objects
+ *
+ * Returns:
+ * 0 on success, or
+ * a negative error code otherwise.
+ */
+int drm_simple_ttm_init(struct drm_simple_ttm *ttm, struct drm_device *dev,
+			u64 vram_base, unsigned long vram_size,
+			const struct drm_simple_ttm_funcs* funcs)
+{
+	int ret;
+
+	ttm->vram_base = vram_base;
+	ttm->vram_size = vram_size;
+	ttm->funcs = funcs;
+
+	ret = ttm_bo_device_init(&ttm->bdev, &bo_driver,
+				 dev->anon_inode->i_mapping,
+				 true);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_init_mm(&ttm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_simple_ttm_init);
+
+/**
+ * drm_simple_ttm_cleanup() - Cleans up an initialized instance of Simple TTM.
+ * @ttm:	the Simple TTM instance to clean up
+ */
+void drm_simple_ttm_cleanup(struct drm_simple_ttm *ttm)
+{
+	ttm_bo_device_release(&ttm->bdev);
+}
+EXPORT_SYMBOL(drm_simple_ttm_cleanup);
diff --git a/include/drm/drm_simple_ttm_helper.h b/include/drm/drm_simple_ttm_helper.h
new file mode 100644
index 000000000000..eaf507dfc7fe
--- /dev/null
+++ b/include/drm/drm_simple_ttm_helper.h
@@ -0,0 +1,74 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DRM_SIMPLE_TTM_HELPER_H
+#define DRM_SIMPLE_TTM_HELPER_H
+
+#include <drm/ttm/ttm_bo_driver.h>
+
+struct drm_device;
+
+/**
+ * struct drm_simple_ttm_funcs - Callback functions for struct drm_simple_ttm
+ *
+ * These callback function integrate Simple TTM with TTM buffer objects. New
+ * functions can be added if necessary.
+ */
+struct drm_simple_ttm_funcs {
+	/**
+	 * Provides an implementation for struct ttm_bo_driver.evict_flags.
+	 */
+        void (*evict_flags)(struct ttm_buffer_object *bo,
+                            struct ttm_placement *placement);
+
+	/**
+	 * Provides an implementation for struct ttm_bo_driver.verify_access.
+	 */
+	int (*verify_access)(struct ttm_buffer_object *bo, struct file *filp);
+};
+
+/**
+ * struct drm_simple_ttm - An instance of Simple TTM
+ *
+ * The fields struct drm_simple_ttm.vram_base and
+ * struct drm_simple_ttm.vrm_size are managed by Simple TTM,
+ * but available for public read access. Use the field
+ * struct drm_simple_ttm.bdev to access the TTM BO device.
+ */
+struct drm_simple_ttm {
+	/**
+	 * Base address of the managed video memory
+	 */
+	u64 vram_base;
+
+	/**
+	 * Size of the managed video memory in bytes
+	 */
+	unsigned long vram_size;
+
+	/**
+	 * The TTM BO device.
+	 */
+	struct ttm_bo_device bdev;
+
+	/* TTM BO functions */
+	const struct drm_simple_ttm_funcs *funcs;
+};
+
+/**
+ * Returns the container of type struct ttm_bo_device
+ * for field bdev.
+ * @bdev:	the TTM BO device
+ * Returns:	The containing Simple TTM instance
+ */
+static inline struct drm_simple_ttm* drm_simple_ttm_of_bdev(
+	struct ttm_bo_device *bdev)
+{
+	return container_of(bdev, struct drm_simple_ttm, bdev);
+}
+
+int drm_simple_ttm_init(struct drm_simple_ttm *ttm, struct drm_device *dev,
+			u64 vram_base, unsigned long vram_size,
+			const struct drm_simple_ttm_funcs* funcs);
+void drm_simple_ttm_cleanup(struct drm_simple_ttm *ttm);
+
+#endif