* many small buffers.
         */
        if (dev_priv->card_type == NV_50) {
-               uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15;
+               uint32_t block_size = dev_priv->vram_size >> 15;
                int i;
 
                switch (tile_flags) {
                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;
 
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_minor *minor = node->minor;
-       struct drm_device *dev = minor->dev;
+       struct drm_nouveau_private *dev_priv = minor->dev->dev_private;
 
-       seq_printf(m, "VRAM total: %dKiB\n",
-                  (int)(nouveau_mem_fb_amount(dev) >> 10));
+       seq_printf(m, "VRAM total: %dKiB\n", (int)(dev_priv->vram_size >> 10));
        return 0;
 }
 
 
        uint32_t ramro_offset;
        uint32_t ramro_size;
 
-       /* base physical addresses */
-       uint64_t fb_phys;
-       uint64_t fb_available_size;
-       uint64_t fb_mappable_pages;
-       uint64_t fb_aper_free;
-
        struct {
                enum {
                        NOUVEAU_GART_NONE = 0,
                spinlock_t lock;
        } tile;
 
+       /* VRAM/fb configuration */
+       uint64_t vram_size;
+       uint64_t vram_sys_base;
+
+       uint64_t fb_phys;
+       uint64_t fb_available_size;
+       uint64_t fb_mappable_pages;
+       uint64_t fb_aper_free;
+       int fb_mtrr;
+
        /* G8x/G9x virtual address space */
        uint64_t vm_gart_base;
        uint64_t vm_gart_size;
        uint64_t vm_end;
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
-       uint64_t vram_sys_base;
-
-       /* the mtrr covering the FB */
-       int fb_mtrr;
 
        struct mem_block *ramin_heap;
 
                                                 struct drm_file *, int tail);
 extern void nouveau_mem_takedown(struct mem_block **heap);
 extern void nouveau_mem_free_block(struct mem_block *);
-extern uint64_t nouveau_mem_fb_amount(struct drm_device *);
+extern int  nouveau_mem_detect(struct drm_device *dev);
 extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
 extern int  nouveau_mem_init(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
 
        }
 }
 
-/*XXX won't work on BSD because of pci_read_config_dword */
 static uint32_t
-nouveau_mem_fb_amount_igp(struct drm_device *dev)
+nouveau_mem_detect_nv04(struct drm_device *dev)
+{
+       uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0);
+
+       if (boot0 & 0x00000100)
+               return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
+
+       switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
+       case NV04_BOOT_0_RAM_AMOUNT_32MB:
+               return 32 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_16MB:
+               return 16 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_8MB:
+               return 8 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_4MB:
+               return 4 * 1024 * 1024;
+       }
+
+       return 0;
+}
+
+static uint32_t
+nouveau_mem_detect_nforce(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct pci_dev *bridge;
                return 0;
        }
 
-       if (dev_priv->flags&NV_NFORCE) {
+       if (dev_priv->flags & NV_NFORCE) {
                pci_read_config_dword(bridge, 0x7C, &mem);
                return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
        } else
-       if (dev_priv->flags&NV_NFORCE2) {
+       if (dev_priv->flags & NV_NFORCE2) {
                pci_read_config_dword(bridge, 0x84, &mem);
                return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
        }
 }
 
 /* returns the amount of FB ram in bytes */
-uint64_t nouveau_mem_fb_amount(struct drm_device *dev)
+int
+nouveau_mem_detect(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t boot0;
-
-       switch (dev_priv->card_type) {
-       case NV_04:
-               boot0 = nv_rd32(dev, NV03_BOOT_0);
-               if (boot0 & 0x00000100)
-                       return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
-
-               switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
-               case NV04_BOOT_0_RAM_AMOUNT_32MB:
-                       return 32 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_16MB:
-                       return 16 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_8MB:
-                       return 8 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_4MB:
-                       return 4 * 1024 * 1024;
-               }
-               break;
-       case NV_10:
-       case NV_20:
-       case NV_30:
-       case NV_40:
-       case NV_50:
-       default:
-               if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
-                       return nouveau_mem_fb_amount_igp(dev);
-               } else {
-                       uint64_t mem;
-                       mem = (nv_rd32(dev, NV04_FIFO_DATA) &
-                                       NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK) >>
-                                       NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT;
-                       return mem * 1024 * 1024;
-               }
-               break;
+
+       if (dev_priv->card_type == NV_04) {
+               dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
+       } else
+       if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
+               dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
+       } else {
+               dev_priv->vram_size  = nv_rd32(dev, NV04_FIFO_DATA);
+               dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
+               if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
+                       dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
        }
 
-       NV_ERROR(dev,
-               "Unable to detect video ram size. Please report your setup to "
-                                                       DRIVER_EMAIL "\n");
-       return 0;
+       NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
+       if (dev_priv->vram_sys_base) {
+               NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
+                       dev_priv->vram_sys_base);
+       }
+
+       if (dev_priv->vram_size)
+               return 0;
+       return -ENOMEM;
 }
 
 #if __OS_HAS_AGP
        spin_lock_init(&dev_priv->ttm.bo_list_lock);
        spin_lock_init(&dev_priv->tile.lock);
 
-       dev_priv->fb_available_size = nouveau_mem_fb_amount(dev);
-
+       dev_priv->fb_available_size = dev_priv->vram_size;
        dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
        if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1))
                dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1);
        dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
 
-       NV_INFO(dev, "%d MiB VRAM\n", (int)(dev_priv->fb_available_size >> 20));
-
        /* remove reserved space at end of vram from available amount */
        dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
        dev_priv->fb_aper_free = dev_priv->fb_available_size;
 
 
        gpuobj = NULL;
        ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
-                                    0, nouveau_mem_fb_amount(dev),
+                                    0, dev_priv->vram_size,
                                     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
                                     &gpuobj);
        if (ret)
                        goto out;
        }
 
+       ret = nouveau_mem_detect(dev);
+       if (ret)
+               goto out_bios;
+
        ret = nouveau_gpuobj_early_init(dev);
        if (ret)
                goto out_bios;
 
        default:
                nv_wr32(dev, 0x2230, 0);
                nv_wr32(dev, NV40_PFIFO_RAMFC,
-                       ((nouveau_mem_fb_amount(dev) - 512 * 1024 +
+                       ((dev_priv->vram_size - 512 * 1024 +
                          dev_priv->ramfc_offset) >> 16) | (3 << 16));
                break;
        }
 
        }
 
        ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19,
-                                 0, nouveau_mem_fb_amount(dev));
+                                 0, dev_priv->vram_size);
        if (ret) {
                nv50_evo_channel_del(pchan);
                return ret;
        /* This used to be in crtc unblank, but seems out of place there. */
        nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
        /* RAM is clamped to 256 MiB. */
-       ram_amount = nouveau_mem_fb_amount(dev);
+       ram_amount = dev_priv->vram_size;
        NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
        if (ram_amount > 256*1024*1024)
                ram_amount = 256*1024*1024;
 
        for (i = 0x1700; i <= 0x1710; i += 4)
                priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
 
-       if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
-               dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
-       else
-               dev_priv->vram_sys_base = 0;
-
        /* Reserve the last MiB of VRAM, we should probably try to avoid
         * setting up the below tables over the top of the VBIOS image at
         * some point.
         */
        dev_priv->ramin_rsvd_vram = 1 << 20;
-       c_offset = nouveau_mem_fb_amount(dev) - dev_priv->ramin_rsvd_vram;
+       c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
        c_size   = 128 << 10;
        c_vmpd   = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
        c_ramfc  = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
        dev_priv->vm_gart_size = NV50_VM_BLOCK;
 
        dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
-       dev_priv->vm_vram_size = nouveau_mem_fb_amount(dev);
+       dev_priv->vm_vram_size = dev_priv->vram_size;
        if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
                dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
        dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);