From e47a4fda2ef7aada45b7799ad20e8012102dc12e Mon Sep 17 00:00:00 2001
From: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date: Wed, 30 Aug 2006 13:04:08 +0200
Subject: Memory manager init and takedown.

---
 libdrm/Makefile.am   |   2 +-
 libdrm/xf86drm.c     |  30 ++++++++++++-
 libdrm/xf86drm.h     |   2 +
 libdrm/xf86mm.h      |   9 +++-
 linux-core/drmP.h    |   5 ++-
 linux-core/drm_bo.c  | 123 +++++++++++++++++++++++++++++++++++++++++++++------
 linux-core/drm_drv.c |   3 ++
 shared-core/drm.h    |  19 ++++++++
 8 files changed, 175 insertions(+), 18 deletions(-)

diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am
index b12e87fa..91a7e5dc 100644
--- a/libdrm/Makefile.am
+++ b/libdrm/Makefile.am
@@ -26,6 +26,6 @@ AM_CFLAGS = -I$(top_srcdir)/shared-core
 libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c
 
 libdrmincludedir = ${includedir}
-libdrminclude_HEADERS = xf86drm.h
+libdrminclude_HEADERS = xf86drm.h xf86mm.h
 
 EXTRA_DIST = ChangeLog TODO
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index 3fccdf69..c9005c41 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -65,7 +65,6 @@
 # define _DRM_FREE   free
 # include "drm.h"
 #endif
-#include "xf86mm.h"
 
 
 /* Not all systems have MAP_FAILED defined */
@@ -2582,6 +2581,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size,
 	buf->ttm = ttm;
 	break;
     case drm_bo_type_dc:
+        req->buffer_start = start;
 	break;
     case drm_bo_type_user:
 	req->buffer_start = (unsigned long) user_buffer;
@@ -2699,4 +2699,32 @@ int drmBOUnReference(int fd, drmBO *buf)
     return 0;
 }   
 
+int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize,
+	      unsigned long ttPOffset, unsigned long ttPSize)
+{
+    drm_mm_init_arg_t arg;
+
+    arg.req.op = mm_init;
+    arg.req.vr_p_offset = vramPOffset;
+    arg.req.vr_p_size = vramPSize;
+    arg.req.tt_p_offset = vramPOffset;
+    arg.req.tt_p_size = vramPSize;
+    
+    if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg))
+	return -errno;
+    
+    return 0;	
+}
+
+int drmMMTakedown(int fd)
+{
+    drm_mm_init_arg_t arg;
+    arg.req.op = mm_takedown;
+
+    if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg))
+	return -errno;
+    
+    return 0;	
+}
+
 #endif
diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index ca48bfbf..f257deda 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -670,4 +670,6 @@ extern int  drmSLLookupNeighbors(void *l, unsigned long key,
 				 unsigned long *prev_key, void **prev_value,
 				 unsigned long *next_key, void **next_value);
 
+#include "xf86mm.h"
+
 #endif
diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h
index 08149d08..8711a144 100644
--- a/libdrm/xf86mm.h
+++ b/libdrm/xf86mm.h
@@ -29,7 +29,7 @@
 #ifndef _XF86MM_H_
 #define _XF86MM_H_
 #include <stddef.h>
-#include "xf86drm.h"
+#include "drm.h"
 
 /*
  * List macros heavily inspired by the Linux kernel
@@ -114,5 +114,12 @@ typedef struct _drmBOList {
     drmMMListHead free;
 } drmBOList;
 
+extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size,
+			      void *user_buffer, drm_bo_type_t type, unsigned mask,
+		unsigned hint, drmBO *buf);
+extern int drmBODestroy(int fd, drmBO *buf);
+extern int drmBOReference(int fd, unsigned handle, drmBO *buf);
+extern int drmBOUnReference(int fd, drmBO *buf);
+
 
 #endif
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 63bcde2e..59926968 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -775,7 +775,9 @@ typedef struct drm_fence_manager{
 
 typedef struct drm_buffer_manager{
 	int initialized;
-	struct mutex bm_mutex;
+	int has_vram;
+	int has_tt;
+	struct mutex mutex;
 	drm_mm_t tt_manager;
 	struct list_head tt_lru;
 	drm_mm_t vram_manager;
@@ -1363,6 +1365,7 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS);
  */
 
 extern int drm_bo_ioctl(DRM_IOCTL_ARGS);
+extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS);
 
 
 /* Inline replacements for DRM_IOREMAP macros */
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 24389447..5f557d55 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -66,7 +66,7 @@ int drm_fence_buffer_objects(drm_file_t * priv)
 	drm_fence_object_t *fence;
 	int ret;
 
-	mutex_lock(&bm->bm_mutex);
+	mutex_lock(&bm->mutex);
 
 	list_for_each_entry(entry, &bm->unfenced, head) {
 		BUG_ON(!entry->unfenced);
@@ -75,21 +75,21 @@ int drm_fence_buffer_objects(drm_file_t * priv)
 	}
 
 	if (!count) {
-		mutex_unlock(&bm->bm_mutex);
+		mutex_unlock(&bm->mutex);
 		return 0;
 	}
 
 	fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE);
 
 	if (!fence) {
-		mutex_unlock(&bm->bm_mutex);
+		mutex_unlock(&bm->mutex);
 		return -ENOMEM;
 	}
 
 	ret = drm_fence_object_init(dev, fence_flags, 1, fence);
 	if (ret) {
 		drm_free(fence, sizeof(*fence), DRM_MEM_FENCE);
-		mutex_unlock(&bm->bm_mutex);
+		mutex_unlock(&bm->mutex);
 		return ret;
 	}
 
@@ -111,7 +111,7 @@ int drm_fence_buffer_objects(drm_file_t * priv)
 	mutex_lock(&dev->struct_mutex);
 	atomic_add(count - 1, &fence->usage);
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&bm->bm_mutex);
+	mutex_unlock(&bm->mutex);
 	return 0;
 }
 
@@ -179,11 +179,12 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo)
 		drm_mm_put_block(&bm->vram_manager, bo->vram);
 		bo->vram = NULL;
 	}
-
-	/*
-	 * FIXME: Destroy ttm.
-	 */
-
+	if (bo->ttm_region) {
+		drm_destroy_ttm_region(bo->ttm_region);
+	}
+	if (bo->ttm_object) {
+		drm_ttm_object_deref_locked(dev, bo->ttm_object);
+	}
 	drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);
 }
 
@@ -356,8 +357,11 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv,
 
 	uo = drm_lookup_user_object(priv, handle);
 
-	if (!uo || (uo->type != drm_buffer_type))
+	if (!uo || (uo->type != drm_buffer_type)) {
+		DRM_ERROR("Could not find buffer object 0x%08x\n",
+			  handle);
 		return NULL;
+	}
 
 	if (check_owner && priv != uo->owner) {
 		if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE))
@@ -541,9 +545,10 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv,
 	}
 }
 
-static int drm_buffer_object_validate(drm_device_t * dev,
+static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags,
 				      drm_buffer_object_t * bo)
 {
+        bo->flags = new_flags;
 	return 0;
 }
 
@@ -574,14 +579,18 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo,
 		mutex_lock(&dev->struct_mutex);
 		to = drm_lookup_ttm_object(priv, ttm_handle, 1);
 		mutex_unlock(&dev->struct_mutex);
-		if (!to)
+		if (!to) {
+			DRM_ERROR("Could not find TTM object\n");
 			ret = -EINVAL;
+		}
 		break;
 	case drm_bo_type_user:
 	case drm_bo_type_fake:
 		break;
 	default:
+		DRM_ERROR("Illegal buffer object type\n");
 		ret = -EINVAL;
+		break;
 	}
 
 	if (ret) {
@@ -656,7 +665,7 @@ int drm_buffer_object_create(drm_file_t * priv,
 	bo->mask = mask;
 	bo->hint = hint;
 
-	ret = drm_buffer_object_validate(dev, bo);
+	ret = drm_buffer_object_validate(dev, new_flags, bo);
 	if (ret)
 		goto out_err;
 
@@ -805,3 +814,89 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
 	return 0;
 
 }
+
+static void drm_bo_clean_mm(drm_file_t *priv)
+{
+}
+
+
+int drm_mm_init_ioctl(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	
+	int ret = 0;
+	drm_mm_init_arg_t arg;
+	drm_buffer_manager_t *bm = &dev->bm;
+	drm_bo_driver_t *driver = dev->driver->bo_driver;
+
+	if (!driver) {
+		DRM_ERROR("Buffer objects is not supported by this driver\n");
+		return -EINVAL;
+	}
+
+	DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg));
+
+	switch(arg.req.op) {
+	case mm_init:
+		if (bm->initialized) {
+			DRM_ERROR("Memory manager already initialized\n");
+			return -EINVAL;
+		}
+		mutex_init(&bm->mutex);
+		mutex_lock(&bm->mutex);
+		bm->has_vram = 0;
+		bm->has_tt = 0;
+
+		if (arg.req.vr_p_size) {
+			ret = drm_mm_init(&bm->vram_manager, 
+					  arg.req.vr_p_offset, 
+					  arg.req.vr_p_size);
+			bm->has_vram = 1;
+			if (ret)
+				break;
+		}
+
+		if (arg.req.tt_p_size) {
+			ret = drm_mm_init(&bm->tt_manager, 
+					  arg.req.tt_p_offset, 
+					  arg.req.tt_p_size);
+			bm->has_tt = 1;
+			if (ret) {
+				if (bm->has_vram)
+					drm_mm_takedown(&bm->vram_manager);
+				break;
+			}
+		}
+		arg.rep.mm_sarea = 0;
+
+		INIT_LIST_HEAD(&bm->vram_lru);
+		INIT_LIST_HEAD(&bm->tt_lru);
+		INIT_LIST_HEAD(&bm->unfenced);
+		INIT_LIST_HEAD(&bm->ddestroy);
+
+		bm->initialized = 1;
+		break;
+	case mm_takedown:
+		if (!bm->initialized) {
+			DRM_ERROR("Memory manager was not initialized\n");
+			return -EINVAL;
+		}
+		mutex_lock(&bm->mutex);
+		drm_bo_clean_mm(priv);
+		if (bm->has_vram)
+			drm_mm_takedown(&bm->vram_manager);
+		if (bm->has_tt)
+			drm_mm_takedown(&bm->tt_manager);
+		bm->initialized = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+		
+	mutex_unlock(&bm->mutex);
+	if (ret)
+		return ret;
+	
+	DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg));
+	return 0;
+}
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index f27a7aff..62df6803 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -121,6 +121,9 @@ static drm_ioctl_desc_t drm_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
 	[DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH},
 	[DRM_IOCTL_NR(DRM_IOCTL_TTM)] = {drm_ttm_ioctl, DRM_AUTH},
+	[DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH},
+	[DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, 
+					     DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
 };
 
 #define DRIVER_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/shared-core/drm.h b/shared-core/drm.h
index f6abfeb9..f900dd51 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -747,8 +747,26 @@ typedef union drm_bo_arg{
 	drm_bo_arg_request_t req;
 	drm_bo_arg_reply_t rep;
 } drm_bo_arg_t;
+
+typedef union drm_mm_init_arg{
+	struct {
+		enum {
+			mm_init,
+			mm_takedown,
+			mm_query
+		} op;
+		drm_u64_t vr_p_offset;
+		drm_u64_t vr_p_size;
+		drm_u64_t tt_p_offset;
+		drm_u64_t tt_p_size;
+	} req;
+	struct {
+		drm_handle_t mm_sarea;
+	} rep;
+} drm_mm_init_arg_t;
 #endif
 
+
 /**
  * \name Ioctls Definitions
  */
@@ -818,6 +836,7 @@ typedef union drm_bo_arg{
 #define DRM_IOCTL_FENCE                 DRM_IOWR(0x3b, drm_fence_arg_t)
 #define DRM_IOCTL_TTM                   DRM_IOWR(0x3c, drm_ttm_arg_t)
 #define DRM_IOCTL_BUFOBJ                DRM_IOWR(0x3d, drm_bo_arg_t)
+#define DRM_IOCTL_MM_INIT               DRM_IOWR(0x3e, drm_mm_init_arg_t)
 #endif
 
 /*@}*/
-- 
cgit v1.2.3