From ca4e34e532e818921f7b2d36fc6886874b7f7924 Mon Sep 17 00:00:00 2001
From: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date: Tue, 22 Aug 2006 11:19:53 +0200
Subject: ttm code cleanup. Fix the sleep-in-page-table-spinlock bug discovered
 by Dave Airlie

---
 linux-core/drmP.h    |  3 +-
 linux-core/drm_ttm.c | 98 ++++++++++++++++++++++------------------------------
 linux-core/drm_ttm.h | 42 ++++++++++++++++------
 3 files changed, 75 insertions(+), 68 deletions(-)

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 5a4a37fc..e42b5e55 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -156,7 +156,8 @@
 #define DRM_MEM_HASHTAB   23
 #define DRM_MEM_OBJECTS   24
 #define DRM_MEM_FENCE     25
-
+#define DRM_MEM_TTM       26
+#define DRM_MEM_BUFOBJ    27
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
 #define DRM_MAP_HASH_OFFSET 0x10000000
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index b3ea7c9b..493f1465 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -60,7 +60,7 @@ int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm)
 		} else if ((unsigned long)mm < (unsigned long)entry->mm) ;
 	}
 
-	n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM);
+	n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM);
 	if (!entry) {
 		DRM_ERROR("Allocation of process mm pointer entry failed\n");
 		return -ENOMEM;
@@ -83,7 +83,7 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm)
 		if (mm == entry->mm) {
 			if (atomic_add_negative(-1, &entry->refcount)) {
 				list_del(&entry->head);
-				drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+				drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 				atomic_dec(&ttm->shared_count);
 				ttm->mm_list_seq++;
 			}
@@ -155,7 +155,9 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset,
 	struct page **first_page = ttm->pages + page_offset;
 	struct page **last_page = ttm->pages + (page_offset + num_pages);
 	struct page **cur_page;
-
+#if !defined(flush_tlb_mm) && defined(MODULE)
+	int flush_tlb = 0;
+#endif
 	list_for_each(list, &ttm->vma_list->head) {
 		drm_ttm_vma_list_t *entry =
 		    list_entry(list, drm_ttm_vma_list_t, head);
@@ -164,7 +166,14 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset,
 			      (page_offset << PAGE_SHIFT),
 			      entry->vma->vm_start +
 			      ((page_offset + num_pages) << PAGE_SHIFT));
+#if !defined(flush_tlb_mm) && defined(MODULE)
+		flush_tlb = 1;
+#endif
 	}
+#if !defined(flush_tlb_mm) && defined(MODULE)
+	if (flush_tlb)
+		global_flush_tlb();
+#endif
 
 	for (cur_page = first_page; cur_page != last_page; ++cur_page) {
 		if (page_mapcount(*cur_page) != 0) {
@@ -193,33 +202,19 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
 	if (atomic_read(&ttm->vma_count) > 0) {
 		DRM_DEBUG("VMAs are still alive. Skipping destruction.\n");
 		return -EBUSY;
-	} else {
-		DRM_DEBUG("Checking for busy regions.\n");
-	}
+	} 
 
 	if (ttm->be_list) {
 		list_for_each_safe(list, next, &ttm->be_list->head) {
 			drm_ttm_backend_list_t *entry =
 			    list_entry(list, drm_ttm_backend_list_t, head);
-#ifdef REMOVED
-			drm_ht_remove_item(&ttm->dev->ttmreghash, 
-					   &entry->hash);
-#endif
 			drm_destroy_ttm_region(entry);
 		}
 
-		drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS);
+		drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_TTM);
 		ttm->be_list = NULL;
 	}
 
-	if (atomic_read(&ttm->unfinished_regions) > 0) {
-		DRM_DEBUG("Regions are still busy. Skipping destruction.\n");
-		ttm->destroy = TRUE;
-		return -EAGAIN;
-	} else {
-		DRM_DEBUG("About to really destroy ttm.\n");
-	}
-
 	if (ttm->pages) {
 		for (i = 0; i < ttm->num_pages; ++i) {
 			cur_page = ttm->pages + i;
@@ -237,6 +232,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
 		vfree(ttm->pages);
 		ttm->pages = NULL;
 	}
+
 	if (ttm->page_flags) {
 		vfree(ttm->page_flags);
 		ttm->page_flags = NULL;
@@ -248,12 +244,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
 			    list_entry(list, drm_ttm_vma_list_t, head);
 			list_del(list);
 			entry->vma->vm_private_data = NULL;
-			drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
+			drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 		}
-		drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS);
+		drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_TTM);
 		ttm->vma_list = NULL;
 	}
-	drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS);
+
+	drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM);
 
 	return 0;
 }
@@ -271,14 +268,12 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
 	if (!dev->driver->bo_driver)
 		return NULL;
 
-	ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS);
+	ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM);
 	if (!ttm)
 		return NULL;
 
 	ttm->lhandle = 0;
 	atomic_set(&ttm->vma_count, 0);
-	atomic_set(&ttm->unfinished_regions, 0);
-	ttm->destroy = FALSE;
 	ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
 	ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags));
@@ -297,7 +292,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
 	}
 	memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages));
 
-	ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS);
+	ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_TTM);
 	if (!ttm->be_list) {
 		DRM_ERROR("Alloc be regions failed\n");
 		drm_destroy_ttm(ttm);
@@ -309,7 +304,7 @@ drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size)
 	atomic_set(&ttm->shared_count, 0);
 	ttm->mm_list_seq = 0;
 
-	ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS);
+	ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_TTM);
 	if (!ttm->vma_list) {
 		DRM_ERROR("Alloc vma list failed\n");
 		drm_destroy_ttm(ttm);
@@ -350,10 +345,10 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm)
 		if (shared_count > cur_count) {
 			if (mm_list)
 				drm_free(mm_list, sizeof(*mm_list) * cur_count,
-					 DRM_MEM_MM);
+					 DRM_MEM_TTM);
 			cur_count = shared_count + 10;
 			mm_list =
-			    drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM);
+			    drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM);
 			if (!mm_list)
 				return -ENOMEM;
 		}
@@ -383,9 +378,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm)
 	} while (list_seq != ttm->mm_list_seq);
 
 	if (mm_list)
-		drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM);
+		drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_TTM);
 
-	ttm->mmap_sem_locked = TRUE;
 	return 0;
 }
 
@@ -403,6 +397,7 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset,
 
 	drm_ttm_lock_mm(ttm, FALSE, TRUE);
 	unmap_vma_pages(ttm, page_offset, num_pages);
+	drm_ttm_unlock_mm(ttm, FALSE, TRUE);
 
 	for (i = 0; i < num_pages; ++i) {
 		cur = page_offset + i;
@@ -413,7 +408,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset,
 				    && page_address(*cur_page) != NULL) {
 					DRM_ERROR
 					    ("Illegal mapped HighMem Page\n");
-					drm_ttm_unlock_mm(ttm, FALSE, TRUE);
 					return -EINVAL;
 				}
 			} else if ((ttm->page_flags[cur] &
@@ -426,12 +420,9 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset,
 	}
 	if (do_tlbflush)
 		global_flush_tlb();
-
-	drm_ttm_unlock_mm(ttm, FALSE, TRUE);
 	return 0;
 }
 
-
 /*
  * Unbind a ttm region from the aperture.
  */
@@ -508,7 +499,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry)
 		cur_page_flags++;
 	}
 
-	drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
+	drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 }
 
 /*
@@ -541,13 +532,13 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
 		}
 	}
 
-	entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS);
+	entry = drm_calloc(1, sizeof(*entry), DRM_MEM_TTM);
 	if (!entry)
 		return -ENOMEM;
 
 	be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached);
 	if (!be) {
-		drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
+		drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 		DRM_ERROR("Couldn't create backend.\n");
 		return -EINVAL;
 	}
@@ -661,7 +652,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry)
 
 	be = entry->be;
 	if (!be) {
-		drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
+		drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 		return;
 	}
 
@@ -679,7 +670,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry)
 	}
 
 	be->destroy(be);
-	drm_free(entry, sizeof(*entry), DRM_MEM_MAPS);
+	drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
 	return;
 }
 
@@ -703,7 +694,7 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len,
 	if (!dev->driver->bo_driver->create_ttm_backend_entry)
 		return -EFAULT;
 
-	tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS);
+	tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_TTM);
 
 	if (!tmp)
 		return -ENOMEM;
@@ -748,9 +739,6 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len,
 	}
 
 	tmp->state = ttm_unbound;
-#ifdef REMOVED
-	tmp->mm = &dev->driver->bo_driver->ttm_mm;
-#endif
 	*entry = tmp;
 
 	return 0;
@@ -766,7 +754,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
 	drm_map_t *map;
 	drm_ttm_t *ttm;
 
-	map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+	map = drm_alloc(sizeof(*map), DRM_MEM_TTM);
 	if (!map)
 		return -ENOMEM;
 
@@ -774,7 +762,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
 
 	if (!ttm) {
 		DRM_ERROR("Could not create ttm\n");
-		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		drm_free(map, sizeof(*map), DRM_MEM_TTM);
 		return -ENOMEM;
 	}
 
@@ -783,25 +771,23 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist)
 	map->flags = _DRM_REMOVABLE;
 	map->size = size;
 
-	list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS);
+	list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM);
 	if (!list) {
 		drm_destroy_ttm(ttm);
-		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		drm_free(map, sizeof(*map), DRM_MEM_TTM);
 		return -ENOMEM;
 	}
 	map->handle = (void *)list;
 
-
-#ifdef REMOVED
-	if (drm_ht_just_insert_please(&dev->maphash, &list->hash, 
+	if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, 
 				      (unsigned long) map->handle, 
-				      32 - PAGE_SHIFT)) {
+				      32 - PAGE_SHIFT - 3, PAGE_SHIFT,
+				      DRM_MAP_HASH_OFFSET)) {
 		drm_destroy_ttm(ttm);
-		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
-		drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+		drm_free(map, sizeof(*map), DRM_MEM_TTM);
+		drm_free(list, sizeof(*list), DRM_MEM_TTM);
 		return -ENOMEM;
 	}
-#endif
 
 	list->user_token =
 	    (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET;
diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h
index 07592a84..f695fcce 100644
--- a/linux-core/drm_ttm.h
+++ b/linux-core/drm_ttm.h
@@ -1,3 +1,34 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ * 
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * 
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com>
+ */
+
 #ifndef _DRM_TTM_H
 #define _DRM_TTM_H
 #define DRM_HAS_TTM
@@ -30,9 +61,7 @@ typedef struct drm_ttm_backend {
 #define DRM_FLUSH_EXE   (0x04)
 
 typedef struct drm_ttm_backend_list {
-        drm_hash_item_t hash;
 	uint32_t flags;
-	atomic_t refcount;
 	struct list_head head;
 	drm_ttm_backend_t *be;
 	unsigned page_offset;
@@ -68,9 +97,6 @@ typedef struct drm_ttm {
 	struct drm_device *dev;
 	drm_ttm_backend_list_t *be_list;
 	atomic_t vma_count;
-	atomic_t unfinished_regions;
-	drm_file_t *owner;
-	int destroy;
 	int mmap_sem_locked;
 } drm_ttm_t;
 
@@ -127,12 +153,6 @@ extern int drm_destroy_ttm(drm_ttm_t * ttm);
 extern void drm_user_destroy_region(drm_ttm_backend_list_t * entry);
 extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm);
 extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm);
-extern void drm_ttm_fence_before_destroy(drm_ttm_t * ttm);
-extern void drm_fence_unfenced_region(drm_ttm_backend_list_t * entry);
-
-extern int drm_ttm_ioctl(DRM_IOCTL_ARGS);
-extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS);
-extern int drm_mm_fence_ioctl(DRM_IOCTL_ARGS);
 
 #define DRM_MASK_VAL(dest, mask, val)			\
   (dest) = ((dest) & ~(mask)) | ((val) & (mask));
-- 
cgit v1.2.3