Compatibility code for 2.6.15-2.6.18. It is ugly but a little comfort is that
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Wed, 11 Oct 2006 20:21:01 +0000 (22:21 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Wed, 11 Oct 2006 20:21:01 +0000 (22:21 +0200)
it will go away in the mainstream kernel.
Some bugfixes, mainly in error paths.

libdrm/xf86drm.c
linux-core/drm_bo.c
linux-core/drm_compat.c
linux-core/drm_compat.h
linux-core/drm_ttm.c
linux-core/drm_ttm.h
linux-core/drm_vm.c

index a083ca2..c768318 100644 (file)
@@ -2624,7 +2624,8 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size,
     drm_bo_arg_t arg;
     drm_bo_arg_request_t *req = &arg.d.req;
     drm_bo_arg_reply_t *rep = &arg.d.rep;
-    
+    int ret;
+
     memset(buf, 0, sizeof(*buf));
     memset(&arg, 0, sizeof(arg));
     req->mask = mask;
@@ -2650,7 +2651,11 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size,
     }
     req->op = drm_bo_create;
 
-    if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg))
+    do {
+       ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg);
+    } while (ret != 0 && errno == EAGAIN);
+
+    if (ret)
        return -errno;
     if (!arg.handled) {
        return -EFAULT;
index d8cab2a..0e2b3fa 100644 (file)
@@ -67,14 +67,23 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict)
 {
        drm_device_t *dev = buf->dev;
        drm_buffer_manager_t *bm = &dev->bm;
+       int ret;
 
        BUG_ON(!buf->tt);
 
        mutex_lock(&dev->struct_mutex);
        if (evict)
-               drm_evict_ttm(buf->ttm);
+               ret = drm_evict_ttm(buf->ttm);
        else
-               drm_unbind_ttm(buf->ttm);
+               ret = drm_unbind_ttm(buf->ttm);
+
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               if (ret == -EAGAIN)
+                       schedule();
+               return ret;
+       }
+       
        drm_mm_put_block(&bm->tt_manager, buf->tt);
        buf->tt = NULL;
 
@@ -126,13 +135,31 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo)
        list_del_init(&bo->tt_lru);
        list_del_init(&bo->vram_lru);
 
-       if (bo->tt) {
+       if (bo->ttm) {
+               unsigned long _end = jiffies + DRM_HZ;
+               int ret;
 
                /*
                 * This temporarily unlocks struct_mutex. 
                 */
+               
+               do {
+                       ret = drm_unbind_ttm(bo->ttm);
+                       if (ret == -EAGAIN) {
+                               mutex_unlock(&dev->struct_mutex);
+                               schedule();
+                               mutex_lock(&dev->struct_mutex);
+                       }
+               } while (ret == -EAGAIN && !time_after_eq(jiffies, _end));
+
+               if (ret) {
+                       DRM_ERROR("Couldn't unbind buffer. "
+                                 "Bad. Continuing anyway\n");
+               }
+       }
+               
+       if (bo->tt) {
 
-               drm_unbind_ttm(bo->ttm);
                drm_mm_put_block(&bm->tt_manager, bo->tt);
                bo->tt = NULL;
        }
@@ -435,6 +462,9 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait)
                ret = drm_move_vram_to_local(bo);
        }
 #endif
+       if (ret)
+               goto out;
+
        mutex_lock(&dev->struct_mutex);
        list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru);
        if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru))
@@ -442,7 +472,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait)
        mutex_unlock(&dev->struct_mutex);
        DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED,
                        _DRM_BO_FLAG_EVICTED);
     out:
+ out:
        return ret;
 }
 
@@ -521,14 +551,18 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait)
        if (ret)
                return ret;
        DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start);
+
        mutex_lock(&dev->struct_mutex);
        ret = drm_bind_ttm(bo->ttm, bo->tt->start);
        if (ret) {
                drm_mm_put_block(&bm->tt_manager, bo->tt);
+               bo->tt = NULL;
        }
        mutex_unlock(&dev->struct_mutex);
-       if (ret)
+
+       if (ret) {
                return ret;
+       }
 
        be = bo->ttm->be;
        if (be->needs_cache_adjust(be))
@@ -1296,6 +1330,7 @@ int drm_buffer_object_create(drm_file_t * priv,
        }
        bo->priv_flags = 0;
        bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED;
+       atomic_inc(&bm->count);
        ret = drm_bo_new_flags(dev, bo->flags, mask, hint,
                               1, &new_flags, &bo->mask);
        if (ret)
@@ -1311,12 +1346,11 @@ int drm_buffer_object_create(drm_file_t * priv,
 
        mutex_unlock(&bo->mutex);
        *buf_obj = bo;
-       atomic_inc(&bm->count);
        return 0;
-
     out_err:
+       
+ out_err:
        mutex_unlock(&bo->mutex);
-       drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);
+       drm_bo_usage_deref_unlocked(dev, bo);   
        return ret;
 }
 
index 1aa835c..5287614 100644 (file)
@@ -183,3 +183,239 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma,
 }
 
 #endif
+
+#ifdef DRM_ODD_MM_COMPAT
+
+typedef struct p_mm_entry {
+       struct list_head head;
+       struct mm_struct *mm;
+       atomic_t refcount;
+        int locked;
+} p_mm_entry_t;
+
+typedef struct vma_entry {
+       struct list_head head;
+       struct vm_area_struct *vma;
+} vma_entry_t;
+
+
+struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma,
+                              unsigned long address, 
+                              int *type)
+{
+       drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data;
+       unsigned long page_offset;
+       struct page *page;
+       drm_ttm_t *ttm; 
+       drm_buffer_manager_t *bm;
+       drm_device_t *dev;
+
+       /*
+        * FIXME: Check can't map aperture flag.
+        */
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
+       if (!map) 
+               return NOPAGE_OOM;
+
+       if (address > vma->vm_end) 
+               return NOPAGE_SIGBUS;
+
+       ttm = (drm_ttm_t *) map->offset;        
+       dev = ttm->dev;
+       mutex_lock(&dev->struct_mutex);
+       drm_fixup_ttm_caching(ttm);
+       BUG_ON(ttm->page_flags & DRM_TTM_PAGE_UNCACHED);
+
+       bm = &dev->bm;
+       page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
+       page = ttm->pages[page_offset];
+
+       if (!page) {
+               if (bm->cur_pages >= bm->max_pages) {
+                       DRM_ERROR("Maximum locked page count exceeded\n"); 
+                       page = NOPAGE_OOM;
+                       goto out;
+               }
+               page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0);
+               if (!page) {
+                       page = NOPAGE_OOM;
+                       goto out;
+               }
+               ++bm->cur_pages;
+               SetPageLocked(page);
+       }
+
+       get_page(page);
+ out:
+       mutex_unlock(&dev->struct_mutex);
+       return page;
+}
+
+
+
+
+int drm_ttm_map_bound(struct vm_area_struct *vma)
+{
+       drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data;
+       drm_ttm_t *ttm = (drm_ttm_t *) map->offset;
+       int ret = 0;
+
+       if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) {
+               unsigned long pfn = ttm->aper_offset + 
+                       (ttm->be->aperture_base >> PAGE_SHIFT);
+               pgprot_t pgprot = drm_io_prot(ttm->be->drm_map_type, vma);
+               
+               ret = io_remap_pfn_range(vma, vma->vm_start, pfn,
+                                        vma->vm_end - vma->vm_start,
+                                        pgprot);
+       }
+       return ret;
+}
+       
+
+int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma)
+{
+       p_mm_entry_t *entry, *n_entry;
+       vma_entry_t *v_entry;
+       drm_local_map_t *map = (drm_local_map_t *)
+               vma->vm_private_data;
+       struct mm_struct *mm = vma->vm_mm;
+
+       v_entry = drm_alloc(sizeof(*v_entry), DRM_MEM_TTM);
+       if (!v_entry) {
+               DRM_ERROR("Allocation of vma pointer entry failed\n");
+               return -ENOMEM;
+       }
+       v_entry->vma = vma;
+       map->handle = (void *) v_entry;
+       list_add_tail(&v_entry->head, &ttm->vma_list);
+
+       list_for_each_entry(entry, &ttm->p_mm_list, head) {
+               if (mm == entry->mm) {
+                       atomic_inc(&entry->refcount);
+                       return 0;
+               } else if ((unsigned long)mm < (unsigned long)entry->mm) ;
+       }
+
+       n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM);
+       if (!n_entry) {
+               DRM_ERROR("Allocation of process mm pointer entry failed\n");
+               return -ENOMEM;
+       }
+       INIT_LIST_HEAD(&n_entry->head);
+       n_entry->mm = mm;
+       n_entry->locked = 0;
+       atomic_set(&n_entry->refcount, 0);
+       list_add_tail(&n_entry->head, &entry->head);
+
+       return 0;
+}
+
+void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma)
+{
+       p_mm_entry_t *entry, *n;
+       vma_entry_t *v_entry, *v_n;
+       int found = 0;
+       struct mm_struct *mm = vma->vm_mm;
+
+       list_for_each_entry_safe(v_entry, v_n, &ttm->vma_list, head) {
+               if (v_entry->vma == vma) {
+                       found = 1;
+                       list_del(&v_entry->head);
+                       drm_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM);
+                       break;
+               }
+       }
+       BUG_ON(!found);
+
+       list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) {
+               if (mm == entry->mm) {
+                       if (atomic_add_negative(-1, &entry->refcount)) {
+                               list_del(&entry->head);
+                               BUG_ON(entry->locked);
+                               drm_free(entry, sizeof(*entry), DRM_MEM_TTM);
+                       }
+                       return;
+               }
+       }
+       BUG_ON(1);
+}
+
+
+
+int drm_ttm_lock_mm(drm_ttm_t * ttm)
+{
+       p_mm_entry_t *entry;
+       int lock_ok = 1;
+       
+       list_for_each_entry(entry, &ttm->p_mm_list, head) {
+               BUG_ON(entry->locked);
+               if (!down_write_trylock(&entry->mm->mmap_sem)) {
+                       lock_ok = 0;
+                       break;
+               }
+               entry->locked = 1;
+       }
+
+       if (lock_ok)
+               return 0;
+
+       list_for_each_entry(entry, &ttm->p_mm_list, head) {
+               if (!entry->locked) 
+                       break;
+               up_write(&entry->mm->mmap_sem);
+               entry->locked = 0;
+       }
+
+       /*
+        * Possible deadlock. Try again. Our callers should handle this
+        * and restart.
+        */
+
+       return -EAGAIN;
+}
+
+void drm_ttm_unlock_mm(drm_ttm_t * ttm)
+{
+       p_mm_entry_t *entry;
+       
+       list_for_each_entry(entry, &ttm->p_mm_list, head) {
+               BUG_ON(!entry->locked);
+               up_write(&entry->mm->mmap_sem);
+               entry->locked = 0;
+       }
+}
+
+int drm_ttm_remap_bound(drm_ttm_t *ttm) 
+{
+       vma_entry_t *v_entry;
+       int ret = 0;
+       
+       list_for_each_entry(v_entry, &ttm->vma_list, head) {
+               ret = drm_ttm_map_bound(v_entry->vma);
+               if (ret)
+                       break;
+       }
+
+       drm_ttm_unlock_mm(ttm);
+       return ret;
+}
+
+void drm_ttm_finish_unmap(drm_ttm_t *ttm)
+{
+       vma_entry_t *v_entry;
+       
+       if (!(ttm->page_flags & DRM_TTM_PAGE_UNCACHED))
+               return;
+
+       list_for_each_entry(v_entry, &ttm->vma_list, head) {
+               v_entry->vma->vm_flags &= ~VM_PFNMAP; 
+       }
+       drm_ttm_unlock_mm(ttm);
+}      
+
+#endif
+
index 4e95679..5617fb7 100644 (file)
@@ -231,6 +231,13 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from
 #include <linux/mm.h>
 #include <asm/page.h>
 
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) && \
+     (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))) 
+#define DRM_ODD_MM_COMPAT
+#endif
+
+
+
 /*
  * Flush relevant caches and clear a VMA structure so that page references 
  * will cause a page fault. Don't flush tlbs.
@@ -304,4 +311,65 @@ extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma,
                                     struct fault_data *data);
 
 #endif
+
+#ifdef DRM_ODD_MM_COMPAT
+
+struct drm_ttm;
+
+
+/*
+ * Add a vma to the ttm vma list, and the 
+ * process mm pointer to the ttm mm list. Needs the ttm mutex.
+ */
+
+extern int drm_ttm_add_vma(struct drm_ttm * ttm, 
+                          struct vm_area_struct *vma);
+/*
+ * Delete a vma and the corresponding mm pointer from the
+ * ttm lists. Needs the ttm mutex.
+ */
+extern void drm_ttm_delete_vma(struct drm_ttm * ttm, 
+                              struct vm_area_struct *vma);
+
+/*
+ * Attempts to lock all relevant mmap_sems for a ttm, while
+ * not releasing the ttm mutex. May return -EAGAIN to avoid 
+ * deadlocks. In that case the caller shall release the ttm mutex,
+ * schedule() and try again.
+ */
+
+extern int drm_ttm_lock_mm(struct drm_ttm * ttm);
+
+/*
+ * Unlock all relevant mmap_sems for a ttm.
+ */
+extern void drm_ttm_unlock_mm(struct drm_ttm * ttm);
+
+/*
+ * If the ttm was bound to the aperture, this function shall be called
+ * with all relevant mmap sems held. It deletes the flag VM_PFNMAP from all
+ * vmas mapping this ttm. This is needed just after unmapping the ptes of
+ * the vma, otherwise the do_nopage() function will bug :(. The function
+ * releases the mmap_sems for this ttm.
+ */
+
+extern void drm_ttm_finish_unmap(struct drm_ttm *ttm);
+
+/*
+ * Remap all vmas of this ttm using io_remap_pfn_range. We cannot 
+ * fault these pfns in, because the first one will set the vma VM_PFNMAP
+ * flag, which will make the next fault bug in do_nopage(). The function
+ * releases the mmap_sems for this ttm.
+ */
+
+extern int drm_ttm_remap_bound(struct drm_ttm *ttm);
+
+
+/*
+ * Remap a vma for a bound ttm. Call with the ttm mutex held and
+ * the relevant mmap_sem locked.
+ */
+extern int drm_ttm_map_bound(struct vm_area_struct *vma);
+
+#endif
 #endif
index 297d4f7..b56270e 100644 (file)
@@ -66,8 +66,17 @@ static int unmap_vma_pages(drm_ttm_t * ttm)
        drm_device_t *dev = ttm->dev;
        loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT;
        loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT;
-       
+
+#ifdef DRM_ODD_MM_COMPAT
+       int ret;
+       ret = drm_ttm_lock_mm(ttm);
+       if (ret)
+               return ret;
+#endif
        unmap_mapping_range(dev->dev_mapping, offset, holelen, 1);
+#ifdef DRM_ODD_MM_COMPAT
+       drm_ttm_finish_unmap(ttm);
+#endif
        return 0;
 }
 
@@ -128,8 +137,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
 
        DRM_DEBUG("Destroying a ttm\n");
 
+#ifdef DRM_TTM_ODD_COMPAT
+       BUG_ON(!list_empty(&ttm->vma_list));
+       BUG_ON(!list_empty(&ttm->p_mm_list));
+#endif
        be = ttm->be;
-
        if (be) {
                be->destroy(be);
                ttm->be = NULL;
@@ -231,6 +243,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size,
        if (!ttm)
                return NULL;
 
+#ifdef DRM_ODD_MM_COMPAT
+       INIT_LIST_HEAD(&ttm->p_mm_list);
+       INIT_LIST_HEAD(&ttm->vma_list);
+#endif
+
        ttm->dev = dev;
        atomic_set(&ttm->vma_count, 0);
 
@@ -263,11 +280,15 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size,
 int drm_evict_ttm(drm_ttm_t * ttm)
 {
        drm_ttm_backend_t *be = ttm->be;
+       int ret;
 
        switch (ttm->state) {
        case ttm_bound:
                if (be->needs_cache_adjust(be)) {
-                       unmap_vma_pages(ttm);
+                       ret = unmap_vma_pages(ttm);
+                       if (ret) {
+                               return ret;
+                       }
                }
                be->unbind(be);
                break;
@@ -291,12 +312,18 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm)
 }
                
 
-void drm_unbind_ttm(drm_ttm_t * ttm)
+int drm_unbind_ttm(drm_ttm_t * ttm)
 {
+       int ret = 0;
+
        if (ttm->state == ttm_bound) 
-               drm_evict_ttm(ttm);
+               ret = drm_evict_ttm(ttm);
+
+       if (ret)
+               return ret;
 
        drm_fixup_ttm_caching(ttm);
+       return 0;
 }
 
 int drm_bind_ttm(drm_ttm_t * ttm,
@@ -313,20 +340,45 @@ int drm_bind_ttm(drm_ttm_t * ttm,
 
        be = ttm->be;
        
-       drm_ttm_populate(ttm);
+       ret = drm_ttm_populate(ttm);
+       if (ret)
+               return ret;
        if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) {
-               unmap_vma_pages(ttm);
+               ret = unmap_vma_pages(ttm);
+               if (ret)
+                       return ret;
+
                drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED);
-       } 
+       }
+#ifdef DRM_ODD_MM_COMPAT 
+       else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) {
+               ret = drm_ttm_lock_mm(ttm);
+               if (ret)
+                       return ret;
+       }
+#endif
        if ((ret = be->bind(be, aper_offset))) {
-               drm_unbind_ttm(ttm);
+               ttm->state = ttm_evicted;
+#ifdef DRM_ODD_MM_COMPAT
+               if (be->needs_cache_adjust(be))
+                       drm_ttm_unlock_mm(ttm);
+#endif
                DRM_ERROR("Couldn't bind backend.\n");
                return ret;
        }
 
+                       
        ttm->aper_offset = aper_offset;
        ttm->state = ttm_bound;
 
+#ifdef DRM_ODD_MM_COMPAT
+       if (be->needs_cache_adjust(be)) {
+               ret = drm_ttm_remap_bound(ttm);
+               if (ret) 
+                       return ret;
+       }
+#endif
+                       
        return 0;
 }
 
index 19c1df5..5421c52 100644 (file)
@@ -74,6 +74,11 @@ typedef struct drm_ttm {
                ttm_unbound,
                ttm_unpopulated,
        } state;
+#ifdef DRM_ODD_MM_COMPAT
+       struct list_head vma_list;
+       struct list_head p_mm_list;
+#endif
+
 } drm_ttm_t;
 
 typedef struct drm_ttm_object {
@@ -95,7 +100,7 @@ extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv,
 extern int drm_bind_ttm(drm_ttm_t * ttm,
                        unsigned long aper_offset);
 
-extern void drm_unbind_ttm(drm_ttm_t * ttm);
+extern int drm_unbind_ttm(drm_ttm_t * ttm);
 
 /*
  * Evict a ttm region. Keeps Aperture caching policy.
index 4595115..091b43f 100644 (file)
@@ -204,15 +204,15 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma,
        if (!page) {
                if (bm->cur_pages >= bm->max_pages) {
                        DRM_ERROR("Maximum locked page count exceeded\n"); 
-                       page = NOPAGE_OOM;
+                       data->type = VM_FAULT_OOM;
                        goto out;
                }
-               ++bm->cur_pages;
                page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0);
                if (!page) {
                        data->type = VM_FAULT_OOM;
                        goto out;
                }
+               ++bm->cur_pages;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
                SetPageLocked(page);
 #else
@@ -236,28 +236,6 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma,
        
        err = vm_insert_pfn(vma, address, pfn, pgprot);
 
-       if (!err && (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) && 
-           ttm->num_pages > 1) {
-
-               /*
-                * FIXME: Check can't map aperture flag.
-                */
-
-               /*
-                * Since we're not racing with anybody else, 
-                * we might as well populate the whole object space.
-                * Note that we're touching vma->vm_flags with this
-                * operation, but we are not changing them, so we should be 
-                * OK.
-                */
-
-               BUG_ON(ttm->state == ttm_unpopulated);
-               err = io_remap_pfn_range(vma, address + PAGE_SIZE, pfn+1,
-                                        (ttm->num_pages - 1) * PAGE_SIZE,
-                                        pgprot);
-       }
-               
-
        if (!err || err == -EBUSY) 
                data->type = VM_FAULT_MINOR; 
        else
@@ -611,6 +589,9 @@ static int drm_vm_ttm_open(struct vm_area_struct *vma) {
        mutex_lock(&dev->struct_mutex);
        ttm = (drm_ttm_t *) map->offset;
        atomic_inc(&ttm->vma_count);
+#ifdef DRM_ODD_MM_COMPAT
+       drm_ttm_add_vma(ttm, vma);
+#endif
        mutex_unlock(&dev->struct_mutex);
        return 0;
 }
@@ -666,6 +647,9 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma)
                ttm = (drm_ttm_t *) map->offset;
                dev = ttm->dev;
                mutex_lock(&dev->struct_mutex);
+#ifdef DRM_ODD_MM_COMPAT
+               drm_ttm_delete_vma(ttm, vma);
+#endif
                if (atomic_dec_and_test(&ttm->vma_count)) {
                        if (ttm->destroy) {
                                ret = drm_destroy_ttm(ttm);
@@ -877,6 +861,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
                vma->vm_private_data = (void *) map;
                vma->vm_file = filp;
                vma->vm_flags |= VM_RESERVED | VM_IO;
+#ifdef DRM_ODD_MM_COMPAT
+               mutex_lock(&dev->struct_mutex);
+               drm_ttm_map_bound(vma);
+               mutex_unlock(&dev->struct_mutex);
+#endif         
                if (drm_vm_ttm_open(vma))
                        return -EAGAIN;
                return 0;