drm/nouveau: detect vram amount once, and save the value

As opposed to repeatedly reading the amount back from the GPU every
time we need to know the VRAM size.

We should now fail to load gracefully on detecting no VRAM, rather than
something potentially messy happening.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2010-03-18 09:45:20 +10:00
parent 952eb63543
commit a76fb4e8ff
8 changed files with 73 additions and 75 deletions

View File

@ -71,7 +71,7 @@ nouveau_bo_fixup_align(struct drm_device *dev,
* 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) {
@ -399,8 +399,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;

View File

@ -137,10 +137,9 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data)
{
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;
}

View File

@ -553,12 +553,6 @@ struct drm_nouveau_private {
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,
@ -580,6 +574,16 @@ struct drm_nouveau_private {
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;
@ -588,10 +592,6 @@ struct drm_nouveau_private {
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;
@ -709,7 +709,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
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 *);

View File

@ -477,9 +477,30 @@ void nouveau_mem_close(struct drm_device *dev)
}
}
/*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;
@ -505,50 +526,32 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev)
}
/* 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->card_type == NV_04) {
dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
} else
if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
return nouveau_mem_fb_amount_igp(dev);
dev_priv->vram_size = nouveau_mem_detect_nforce(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;
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");
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
@ -659,15 +662,12 @@ nouveau_mem_init(struct drm_device *dev)
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;

View File

@ -340,7 +340,7 @@ nouveau_card_init_channel(struct drm_device *dev)
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)
@ -426,6 +426,10 @@ nouveau_card_init(struct drm_device *dev)
goto out;
}
ret = nouveau_mem_detect(dev);
if (ret)
goto out_bios;
ret = nouveau_gpuobj_early_init(dev);
if (ret)
goto out_bios;

View File

@ -278,7 +278,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
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;
}

View File

@ -143,7 +143,7 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
}
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;
@ -231,7 +231,7 @@ nv50_display_init(struct drm_device *dev)
/* 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;

View File

@ -76,17 +76,12 @@ nv50_instmem_init(struct drm_device *dev)
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;
@ -106,7 +101,7 @@ nv50_instmem_init(struct drm_device *dev)
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);