drm/i915: fix oops on single crtc devices.
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_bufs.c
index 1b8dbd5..2092e7b 100644 (file)
@@ -34,6 +34,9 @@
  */
 
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <asm/shmparam.h>
 #include "drmP.h"
 
 resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource)
@@ -54,20 +57,40 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
 {
        struct drm_map_list *entry;
        list_for_each_entry(entry, &dev->maplist, head) {
-               if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
-                   ((entry->map->offset == map->offset) ||
-                    ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
+               /*
+                * Because the kernel-userspace ABI is fixed at a 32-bit offset
+                * while PCI resources may live above that, we ignore the map
+                * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
+                * It is assumed that each driver will have only one resource of
+                * each type.
+                */
+               if (!entry->map ||
+                   map->type != entry->map->type ||
+                   entry->master != dev->primary->master)
+                       continue;
+               switch (map->type) {
+               case _DRM_SHM:
+                       if (map->flags != _DRM_CONTAINS_LOCK)
+                               break;
+               case _DRM_REGISTERS:
+               case _DRM_FRAME_BUFFER:
                        return entry;
+               default: /* Make gcc happy */
+                       ;
                }
+               if (entry->map->offset == map->offset)
+                       return entry;
        }
 
        return NULL;
 }
 
 static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
-                         unsigned long user_token, int hashed_handle)
+                         unsigned long user_token, int hashed_handle, int shm)
 {
-       int use_hashed_handle;
+       int use_hashed_handle, shift;
+       unsigned long add;
+
 #if (BITS_PER_LONG == 64)
        use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
 #elif (BITS_PER_LONG == 32)
@@ -83,9 +106,31 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
                if (ret != -EINVAL)
                        return ret;
        }
+
+       shift = 0;
+       add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT;
+       if (shm && (SHMLBA > PAGE_SIZE)) {
+               int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1;
+
+               /* For shared memory, we have to preserve the SHMLBA
+                * bits of the eventual vma->vm_pgoff value during
+                * mmap().  Otherwise we run into cache aliasing problems
+                * on some platforms.  On these platforms, the pgoff of
+                * a mmap() request is used to pick a suitable virtual
+                * address for the mmap() region such that it will not
+                * cause cache aliasing problems.
+                *
+                * Therefore, make sure the SHMLBA relevant bits of the
+                * hash value we use are equal to those in the original
+                * kernel virtual address.
+                */
+               shift = bits;
+               add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL));
+       }
+
        return drm_ht_just_insert_please(&dev->map_hash, hash,
                                         user_token, 32 - PAGE_SHIFT - 3,
-                                        0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
+                                        shift, add);
 }
 
 /**
@@ -96,7 +141,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
  * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where
  * applicable and if supported by the kernel.
  */
-static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
+static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                           unsigned int size, enum drm_map_type type,
                           enum drm_map_flags flags,
                           struct drm_map_list ** maplist)
@@ -107,7 +152,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        unsigned long user_token;
        int ret;
 
-       map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+       map = kmalloc(sizeof(*map), GFP_KERNEL);
        if (!map)
                return -ENOMEM;
 
@@ -121,13 +166,21 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
         * when processes fork.
         */
        if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) {
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               kfree(map);
                return -EINVAL;
        }
-       DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
-                 map->offset, map->size, map->type);
-       if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+       DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n",
+                 (unsigned long long)map->offset, map->size, map->type);
+
+       /* page-align _DRM_SHM maps. They are allocated here so there is no security
+        * hole created by that and it works around various broken drivers that use
+        * a non-aligned quantity to map the SAREA. --BenH
+        */
+       if (map->type == _DRM_SHM)
+               map->size = PAGE_ALIGN(map->size);
+
+       if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+               kfree(map);
                return -EINVAL;
        }
        map->mtrr = -1;
@@ -139,7 +192,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
 #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
                if (map->offset + (map->size-1) < map->offset ||
                    map->offset < virt_to_phys(high_memory)) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -EINVAL;
                }
 #endif
@@ -160,7 +213,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                                list->map->size = map->size;
                        }
 
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        *maplist = list;
                        return 0;
                }
@@ -175,7 +228,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                if (map->type == _DRM_REGISTERS) {
                        map->handle = ioremap(map->offset, map->size);
                        if (!map->handle) {
-                               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                               kfree(map);
                                return -ENOMEM;
                        }
                }
@@ -191,7 +244,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                                list->map->size = map->size;
                        }
 
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        *maplist = list;
                        return 0;
                }
@@ -199,7 +252,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                DRM_DEBUG("%lu %d %p\n",
                          map->size, drm_order(map->size), map->handle);
                if (!map->handle) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -ENOMEM;
                }
                map->offset = (unsigned long)map->handle;
@@ -207,7 +260,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                        /* Prevent a 2nd X Server from creating a 2nd lock */
                        if (dev->primary->master->lock.hw_lock != NULL) {
                                vfree(map->handle);
-                               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                               kfree(map);
                                return -EBUSY;
                        }
                        dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle;   /* Pointer to lock */
@@ -218,7 +271,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                int valid = 0;
 
                if (!drm_core_has_AGP(dev)) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -EINVAL;
                }
 #ifdef __alpha__
@@ -251,19 +304,20 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                        }
                }
                if (!list_empty(&dev->agp->memory) && !valid) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -EPERM;
                }
-               DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+               DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n",
+                         (unsigned long long)map->offset, map->size);
 
                break;
+       }
        case _DRM_GEM:
-               DRM_ERROR("tried to rmmap GEM object\n");
+               DRM_ERROR("tried to addmap GEM object\n");
                break;
-       }
        case _DRM_SCATTER_GATHER:
                if (!dev->sg) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -EINVAL;
                }
                map->offset += (unsigned long)dev->sg->virtual;
@@ -273,9 +327,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                 * As we're limiting the address to 2^32-1 (or less),
                 * casting it down to 32 bits is no problem, but we
                 * need to point to a 64bit variable first. */
-               dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL);
+               dmah = drm_pci_alloc(dev, map->size, map->size);
                if (!dmah) {
-                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       kfree(map);
                        return -ENOMEM;
                }
                map->handle = dmah->vaddr;
@@ -283,15 +337,15 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                kfree(dmah);
                break;
        default:
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               kfree(map);
                return -EINVAL;
        }
 
-       list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
+       list = kmalloc(sizeof(*list), GFP_KERNEL);
        if (!list) {
                if (map->type == _DRM_REGISTERS)
                        iounmap(map->handle);
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               kfree(map);
                return -EINVAL;
        }
        memset(list, 0, sizeof(*list));
@@ -304,12 +358,13 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        /* We do it here so that dev->struct_mutex protects the increment */
        user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
                map->offset;
-       ret = drm_map_handle(dev, &list->hash, user_token, 0);
+       ret = drm_map_handle(dev, &list->hash, user_token, 0,
+                            (map->type == _DRM_SHM));
        if (ret) {
                if (map->type == _DRM_REGISTERS)
                        iounmap(map->handle);
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
-               drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+               kfree(map);
+               kfree(list);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
@@ -317,12 +372,13 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
-       list->master = dev->primary->master;
+       if (!(map->flags & _DRM_DRIVER))
+               list->master = dev->primary->master;
        *maplist = list;
        return 0;
        }
 
-int drm_addmap(struct drm_device * dev, unsigned int offset,
+int drm_addmap(struct drm_device * dev, resource_size_t offset,
               unsigned int size, enum drm_map_type type,
               enum drm_map_flags flags, struct drm_local_map ** map_ptr)
 {
@@ -393,7 +449,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
                        list_del(&r_list->head);
                        drm_ht_remove_key(&dev->map_hash,
                                          r_list->user_token >> PAGE_SHIFT);
-                       drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
+                       kfree(r_list);
                        found = 1;
                        break;
                }
@@ -436,7 +492,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
                DRM_ERROR("tried to rmmap GEM object\n");
                break;
        }
-       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+       kfree(map);
 
        return 0;
 }
@@ -527,24 +583,16 @@ static void drm_cleanup_buf_error(struct drm_device * dev,
                                drm_pci_free(dev, entry->seglist[i]);
                        }
                }
-               drm_free(entry->seglist,
-                        entry->seg_count *
-                        sizeof(*entry->seglist), DRM_MEM_SEGS);
+               kfree(entry->seglist);
 
                entry->seg_count = 0;
        }
 
        if (entry->buf_count) {
                for (i = 0; i < entry->buf_count; i++) {
-                       if (entry->buflist[i].dev_private) {
-                               drm_free(entry->buflist[i].dev_private,
-                                        entry->buflist[i].dev_priv_size,
-                                        DRM_MEM_BUFS);
-                       }
+                       kfree(entry->buflist[i].dev_private);
                }
-               drm_free(entry->buflist,
-                        entry->buf_count *
-                        sizeof(*entry->buflist), DRM_MEM_BUFS);
+               kfree(entry->buflist);
 
                entry->buf_count = 0;
        }
@@ -643,8 +691,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                return -EINVAL;
        }
 
-       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
-                                  DRM_MEM_BUFS);
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -674,7 +721,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
+               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -694,10 +741,9 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
 
        DRM_DEBUG("byte_count: %d\n", byte_count);
 
-       temp_buflist = drm_realloc(dma->buflist,
-                                  dma->buf_count * sizeof(*dma->buflist),
-                                  (dma->buf_count + entry->buf_count)
-                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       temp_buflist = krealloc(dma->buflist,
+                               (dma->buf_count + entry->buf_count) *
+                               sizeof(*dma->buflist), GFP_KERNEL);
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
@@ -799,8 +845,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                return -EINVAL;
        }
 
-       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
-                                  DRM_MEM_BUFS);
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -808,11 +853,9 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
        }
        memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
-       entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
-                                  DRM_MEM_SEGS);
+       entry->seglist = kmalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
        if (!entry->seglist) {
-               drm_free(entry->buflist,
-                        count * sizeof(*entry->buflist), DRM_MEM_BUFS);
+               kfree(entry->buflist);
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
@@ -822,13 +865,11 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
        /* Keep the original pagelist until we know all the allocations
         * have succeeded
         */
-       temp_pagelist = drm_alloc((dma->page_count + (count << page_order))
-                                 * sizeof(*dma->pagelist), DRM_MEM_PAGES);
+       temp_pagelist = kmalloc((dma->page_count + (count << page_order)) *
+                              sizeof(*dma->pagelist), GFP_KERNEL);
        if (!temp_pagelist) {
-               drm_free(entry->buflist,
-                        count * sizeof(*entry->buflist), DRM_MEM_BUFS);
-               drm_free(entry->seglist,
-                        count * sizeof(*entry->seglist), DRM_MEM_SEGS);
+               kfree(entry->buflist);
+               kfree(entry->seglist);
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
@@ -845,16 +886,14 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
 
        while (entry->buf_count < count) {
 
-               dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful);
+               dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000);
 
                if (!dmah) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
                        entry->seg_count = count;
                        drm_cleanup_buf_error(dev, entry);
-                       drm_free(temp_pagelist,
-                                (dma->page_count + (count << page_order))
-                                * sizeof(*dma->pagelist), DRM_MEM_PAGES);
+                       kfree(temp_pagelist);
                        mutex_unlock(&dev->struct_mutex);
                        atomic_dec(&dev->buf_alloc);
                        return -ENOMEM;
@@ -885,18 +924,14 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                        buf->file_priv = NULL;
 
                        buf->dev_priv_size = dev->driver->dev_priv_size;
-                       buf->dev_private = drm_alloc(buf->dev_priv_size,
-                                                    DRM_MEM_BUFS);
+                       buf->dev_private = kmalloc(buf->dev_priv_size,
+                                                 GFP_KERNEL);
                        if (!buf->dev_private) {
                                /* Set count correctly so we free the proper amount. */
                                entry->buf_count = count;
                                entry->seg_count = count;
                                drm_cleanup_buf_error(dev, entry);
-                               drm_free(temp_pagelist,
-                                        (dma->page_count +
-                                         (count << page_order))
-                                        * sizeof(*dma->pagelist),
-                                        DRM_MEM_PAGES);
+                               kfree(temp_pagelist);
                                mutex_unlock(&dev->struct_mutex);
                                atomic_dec(&dev->buf_alloc);
                                return -ENOMEM;
@@ -909,16 +944,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                byte_count += PAGE_SIZE << page_order;
        }
 
-       temp_buflist = drm_realloc(dma->buflist,
-                                  dma->buf_count * sizeof(*dma->buflist),
-                                  (dma->buf_count + entry->buf_count)
-                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       temp_buflist = krealloc(dma->buflist,
+                               (dma->buf_count + entry->buf_count) *
+                               sizeof(*dma->buflist), GFP_KERNEL);
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
-               drm_free(temp_pagelist,
-                        (dma->page_count + (count << page_order))
-                        * sizeof(*dma->pagelist), DRM_MEM_PAGES);
+               kfree(temp_pagelist);
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
                return -ENOMEM;
@@ -929,13 +961,11 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
        }
 
-       /* No allocations failed, so now we can replace the orginal pagelist
+       /* No allocations failed, so now we can replace the original pagelist
         * with the new one.
         */
        if (dma->page_count) {
-               drm_free(dma->pagelist,
-                        dma->page_count * sizeof(*dma->pagelist),
-                        DRM_MEM_PAGES);
+               kfree(dma->pagelist);
        }
        dma->pagelist = temp_pagelist;
 
@@ -1031,8 +1061,8 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                return -EINVAL;
        }
 
-       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
-                                  DRM_MEM_BUFS);
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+                               GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -1063,7 +1093,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
+               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -1084,10 +1114,9 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
 
        DRM_DEBUG("byte_count: %d\n", byte_count);
 
-       temp_buflist = drm_realloc(dma->buflist,
-                                  dma->buf_count * sizeof(*dma->buflist),
-                                  (dma->buf_count + entry->buf_count)
-                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       temp_buflist = krealloc(dma->buflist,
+                               (dma->buf_count + entry->buf_count) *
+                               sizeof(*dma->buflist), GFP_KERNEL);
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
@@ -1193,8 +1222,8 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                return -EINVAL;
        }
 
-       entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
-                                  DRM_MEM_BUFS);
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+                               GFP_KERNEL);
        if (!entry->buflist) {
                mutex_unlock(&dev->struct_mutex);
                atomic_dec(&dev->buf_alloc);
@@ -1224,7 +1253,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->dev_priv_size;
-               buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
+               buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
                if (!buf->dev_private) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
@@ -1244,10 +1273,9 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
 
        DRM_DEBUG("byte_count: %d\n", byte_count);
 
-       temp_buflist = drm_realloc(dma->buflist,
-                                  dma->buf_count * sizeof(*dma->buflist),
-                                  (dma->buf_count + entry->buf_count)
-                                  * sizeof(*dma->buflist), DRM_MEM_BUFS);
+       temp_buflist = krealloc(dma->buflist,
+                               (dma->buf_count + entry->buf_count) *
+                               sizeof(*dma->buflist), GFP_KERNEL);
        if (!temp_buflist) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);