ttm code cleanup.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Tue, 22 Aug 2006 09:19:53 +0000 (11:19 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Tue, 22 Aug 2006 09:19:53 +0000 (11:19 +0200)
Fix the sleep-in-page-table-spinlock bug discovered by Dave Airlie

linux-core/drmP.h
linux-core/drm_ttm.c
linux-core/drm_ttm.h

index 5a4a37f..e42b5e5 100644 (file)
 #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
index b3ea7c9..493f146 100644 (file)
@@ -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;
index 07592a8..f695fcc 100644 (file)
@@ -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));