Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[safe/jmp/linux-2.6] / drivers / gpu / drm / nouveau / nouveau_bo.c
index 1d6036f..957d176 100644 (file)
@@ -33,6 +33,9 @@
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
 
+#include <linux/log2.h>
+#include <linux/slab.h>
+
 static void
 nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
 {
@@ -63,31 +66,34 @@ nouveau_bo_fixup_align(struct drm_device *dev,
 
        /*
         * Some of the tile_flags have a periodic structure of N*4096 bytes,
-        * align to to that as well as the page size. Overallocate memory to
-        * avoid corruption of other buffer objects.
+        * align to to that as well as the page size. Align the size to the
+        * appropriate boundaries. This does imply that sizes are rounded up
+        * 3-7 pages, so be aware of this and do not waste memory by allocating
+        * many small buffers.
         */
        if (dev_priv->card_type == NV_50) {
+               uint32_t block_size = dev_priv->vram_size >> 15;
+               int i;
+
                switch (tile_flags) {
                case 0x1800:
                case 0x2800:
                case 0x4800:
                case 0x7a00:
-                       if (dev_priv->chipset >= 0xA0) {
-                               /* This is based on high end cards with 448 bits
-                                * memory bus, could be different elsewhere.*/
-                               *size += 6 * 28672;
-                               /* 8 * 28672 is the actual alignment requirement
-                                * but we must also align to page size. */
-                               *align = 2 * 8 * 28672;
-                       } else if (dev_priv->chipset >= 0x90) {
-                               *size += 3 * 16384;
-                               *align = 12 * 16384;
+                       if (is_power_of_2(block_size)) {
+                               for (i = 1; i < 10; i++) {
+                                       *align = 12 * i * block_size;
+                                       if (!(*align % 65536))
+                                               break;
+                               }
                        } else {
-                               *size += 3 * 8192;
-                               /* 12 * 8192 is the actual alignment requirement
-                                * but we must also align to page size. */
-                               *align = 2 * 12 * 8192;
+                               for (i = 1; i < 10; i++) {
+                                       *align = 8 * i * block_size;
+                                       if (!(*align % 65536))
+                                               break;
+                               }
                        }
+                       *size = roundup(*size, *align);
                        break;
                default:
                        break;
@@ -114,10 +120,11 @@ nouveau_bo_fixup_align(struct drm_device *dev,
                }
        }
 
-       *size = ALIGN(*size, PAGE_SIZE);
+       /* ALIGN works only on powers of two. */
+       *size = roundup(*size, PAGE_SIZE);
 
        if (dev_priv->card_type == NV_50) {
-               *size = ALIGN(*size, 65536);
+               *size = roundup(*size, 65536);
                *align = max(65536, *align);
        }
 }
@@ -130,7 +137,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_bo *nvbo;
-       int ret, n = 0;
+       int ret = 0;
 
        nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
        if (!nvbo)
@@ -145,19 +152,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
        align >>= PAGE_SHIFT;
 
-       if (flags & TTM_PL_FLAG_VRAM)
-               nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING;
-       if (flags & TTM_PL_FLAG_TT)
-               nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
        nvbo->placement.fpfn = 0;
        nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0;
-       nvbo->placement.placement = nvbo->placements;
-       nvbo->placement.busy_placement = nvbo->placements;
-       nvbo->placement.num_placement = n;
-       nvbo->placement.num_busy_placement = n;
+       nouveau_bo_placement_set(nvbo, flags, 0);
 
        nvbo->channel = chan;
-       nouveau_bo_placement_set(nvbo, flags);
        ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
                          ttm_bo_type_device, &nvbo->placement, align, 0,
                          false, NULL, size, nouveau_bo_del_ttm);
@@ -174,26 +173,33 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        return 0;
 }
 
+static void
+set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
+{
+       *n = 0;
+
+       if (type & TTM_PL_FLAG_VRAM)
+               pl[(*n)++] = TTM_PL_FLAG_VRAM | flags;
+       if (type & TTM_PL_FLAG_TT)
+               pl[(*n)++] = TTM_PL_FLAG_TT | flags;
+       if (type & TTM_PL_FLAG_SYSTEM)
+               pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
+}
+
 void
-nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t memtype)
+nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 {
-       int n = 0;
-
-       if (memtype & TTM_PL_FLAG_VRAM)
-               nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING;
-       if (memtype & TTM_PL_FLAG_TT)
-               nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
-       if (memtype & TTM_PL_FLAG_SYSTEM)
-               nvbo->placements[n++] = TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;
-       nvbo->placement.placement = nvbo->placements;
-       nvbo->placement.busy_placement = nvbo->placements;
-       nvbo->placement.num_placement = n;
-       nvbo->placement.num_busy_placement = n;
-
-       if (nvbo->pin_refcnt) {
-               while (n--)
-                       nvbo->placements[n] |= TTM_PL_FLAG_NO_EVICT;
-       }
+       struct ttm_placement *pl = &nvbo->placement;
+       uint32_t flags = TTM_PL_MASK_CACHING |
+               (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
+
+       pl->placement = nvbo->placements;
+       set_placement_list(nvbo->placements, &pl->num_placement,
+                          type, flags);
+
+       pl->busy_placement = nvbo->busy_placements;
+       set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
+                          type | busy, flags);
 }
 
 int
@@ -201,7 +207,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
-       int ret, i;
+       int ret;
 
        if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
                NV_ERROR(nouveau_bdev(bo->bdev)->dev,
@@ -217,9 +223,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
        if (ret)
                goto out;
 
-       nouveau_bo_placement_set(nvbo, memtype);
-       for (i = 0; i < nvbo->placement.num_placement; i++)
-               nvbo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+       nouveau_bo_placement_set(nvbo, memtype, 0);
 
        ret = ttm_bo_validate(bo, &nvbo->placement, false, false);
        if (ret == 0) {
@@ -246,7 +250,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
-       int ret, i;
+       int ret;
 
        if (--nvbo->pin_refcnt)
                return 0;
@@ -255,8 +259,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
        if (ret)
                return ret;
 
-       for (i = 0; i < nvbo->placement.num_placement; i++)
-               nvbo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+       nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
 
        ret = ttm_bo_validate(bo, &nvbo->placement, false, false);
        if (ret == 0) {
@@ -397,8 +400,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->io_addr = NULL;
                man->io_offset = drm_get_resource_start(dev, 1);
                man->io_size = drm_get_resource_len(dev, 1);
-               if (man->io_size > nouveau_mem_fb_amount(dev))
-                       man->io_size = nouveau_mem_fb_amount(dev);
+               if (man->io_size > dev_priv->vram_size)
+                       man->io_size = dev_priv->vram_size;
 
                man->gpu_offset = dev_priv->vm_vram_base;
                break;
@@ -441,11 +444,11 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 
        switch (bo->mem.mem_type) {
        case TTM_PL_VRAM:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT |
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT,
                                         TTM_PL_FLAG_SYSTEM);
                break;
        default:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM);
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0);
                break;
        }
 
@@ -471,6 +474,8 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
 
        ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
                                        evict, no_wait, new_mem);
+       if (nvbo->channel && nvbo->channel != chan)
+               ret = nouveau_fence_wait(fence, NULL, false, false);
        nouveau_fence_unref((void *)&fence);
        return ret;
 }
@@ -584,7 +589,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
 
        placement.fpfn = placement.lpfn = 0;
        placement.num_placement = placement.num_busy_placement = 1;
-       placement.placement = &placement_memtype;
+       placement.placement = placement.busy_placement = &placement_memtype;
 
        tmp_mem = *new_mem;
        tmp_mem.mm_node = NULL;
@@ -622,7 +627,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
 
        placement.fpfn = placement.lpfn = 0;
        placement.num_placement = placement.num_busy_placement = 1;
-       placement.placement = &placement_memtype;
+       placement.placement = placement.busy_placement = &placement_memtype;
 
        tmp_mem = *new_mem;
        tmp_mem.mm_node = NULL;
@@ -634,7 +639,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                goto out;
 
-       ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait, new_mem);
+       ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait, new_mem);
        if (ret)
                goto out;