aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-08-22 11:19:53 +0200
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-08-22 11:19:53 +0200
commitca4e34e532e818921f7b2d36fc6886874b7f7924 (patch)
tree8f6b6774d0a7fba5b6570d253016546c381ef6c7
parenta6535c8db4614376ce8ecb7d889b92db066a96cc (diff)
ttm code cleanup.
Fix the sleep-in-page-table-spinlock bug discovered by Dave Airlie
-rw-r--r--linux-core/drmP.h3
-rw-r--r--linux-core/drm_ttm.c98
-rw-r--r--linux-core/drm_ttm.h42
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));