Commit a76fb4e8 authored by Ben Skeggs's avatar Ben Skeggs

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 952eb635
...@@ -71,7 +71,7 @@ nouveau_bo_fixup_align(struct drm_device *dev, ...@@ -71,7 +71,7 @@ nouveau_bo_fixup_align(struct drm_device *dev,
* many small buffers. * many small buffers.
*/ */
if (dev_priv->card_type == NV_50) { 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; int i;
switch (tile_flags) { switch (tile_flags) {
...@@ -399,8 +399,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, ...@@ -399,8 +399,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->io_addr = NULL; man->io_addr = NULL;
man->io_offset = drm_get_resource_start(dev, 1); man->io_offset = drm_get_resource_start(dev, 1);
man->io_size = drm_get_resource_len(dev, 1); man->io_size = drm_get_resource_len(dev, 1);
if (man->io_size > nouveau_mem_fb_amount(dev)) if (man->io_size > dev_priv->vram_size)
man->io_size = nouveau_mem_fb_amount(dev); man->io_size = dev_priv->vram_size;
man->gpu_offset = dev_priv->vm_vram_base; man->gpu_offset = dev_priv->vm_vram_base;
break; break;
......
...@@ -137,10 +137,9 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data) ...@@ -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_info_node *node = (struct drm_info_node *) m->private;
struct drm_minor *minor = node->minor; 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", seq_printf(m, "VRAM total: %dKiB\n", (int)(dev_priv->vram_size >> 10));
(int)(nouveau_mem_fb_amount(dev) >> 10));
return 0; return 0;
} }
......
...@@ -553,12 +553,6 @@ struct drm_nouveau_private { ...@@ -553,12 +553,6 @@ struct drm_nouveau_private {
uint32_t ramro_offset; uint32_t ramro_offset;
uint32_t ramro_size; 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 { struct {
enum { enum {
NOUVEAU_GART_NONE = 0, NOUVEAU_GART_NONE = 0,
...@@ -580,6 +574,16 @@ struct drm_nouveau_private { ...@@ -580,6 +574,16 @@ struct drm_nouveau_private {
spinlock_t lock; spinlock_t lock;
} tile; } 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 */ /* G8x/G9x virtual address space */
uint64_t vm_gart_base; uint64_t vm_gart_base;
uint64_t vm_gart_size; uint64_t vm_gart_size;
...@@ -588,10 +592,6 @@ struct drm_nouveau_private { ...@@ -588,10 +592,6 @@ struct drm_nouveau_private {
uint64_t vm_end; uint64_t vm_end;
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
int vm_vram_pt_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 mem_block *ramin_heap;
...@@ -709,7 +709,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, ...@@ -709,7 +709,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
struct drm_file *, int tail); struct drm_file *, int tail);
extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_takedown(struct mem_block **heap);
extern void nouveau_mem_free_block(struct mem_block *); 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 void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *);
......
...@@ -477,9 +477,30 @@ void nouveau_mem_close(struct drm_device *dev) ...@@ -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 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 drm_nouveau_private *dev_priv = dev->dev_private;
struct pci_dev *bridge; struct pci_dev *bridge;
...@@ -491,11 +512,11 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev) ...@@ -491,11 +512,11 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev)
return 0; return 0;
} }
if (dev_priv->flags&NV_NFORCE) { if (dev_priv->flags & NV_NFORCE) {
pci_read_config_dword(bridge, 0x7C, &mem); pci_read_config_dword(bridge, 0x7C, &mem);
return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024; return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
} else } else
if (dev_priv->flags&NV_NFORCE2) { if (dev_priv->flags & NV_NFORCE2) {
pci_read_config_dword(bridge, 0x84, &mem); pci_read_config_dword(bridge, 0x84, &mem);
return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024; return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
} }
...@@ -505,50 +526,32 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev) ...@@ -505,50 +526,32 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev)
} }
/* returns the amount of FB ram in bytes */ /* 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; struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t boot0;
switch (dev_priv->card_type) { if (dev_priv->card_type == NV_04) {
case NV_04: dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
boot0 = nv_rd32(dev, NV03_BOOT_0); } else
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)) { 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 { } else {
uint64_t mem; dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA);
mem = (nv_rd32(dev, NV04_FIFO_DATA) & dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK) >> if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT; dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
return mem * 1024 * 1024;
} }
break;
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);
} }
NV_ERROR(dev, if (dev_priv->vram_size)
"Unable to detect video ram size. Please report your setup to "
DRIVER_EMAIL "\n");
return 0; return 0;
return -ENOMEM;
} }
#if __OS_HAS_AGP #if __OS_HAS_AGP
...@@ -659,15 +662,12 @@ nouveau_mem_init(struct drm_device *dev) ...@@ -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->ttm.bo_list_lock);
spin_lock_init(&dev_priv->tile.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; dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1)) 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 = drm_get_resource_len(dev, 1);
dev_priv->fb_mappable_pages >>= PAGE_SHIFT; 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 */ /* remove reserved space at end of vram from available amount */
dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
dev_priv->fb_aper_free = dev_priv->fb_available_size; dev_priv->fb_aper_free = dev_priv->fb_available_size;
......
...@@ -340,7 +340,7 @@ nouveau_card_init_channel(struct drm_device *dev) ...@@ -340,7 +340,7 @@ nouveau_card_init_channel(struct drm_device *dev)
gpuobj = NULL; gpuobj = NULL;
ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, 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, NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
&gpuobj); &gpuobj);
if (ret) if (ret)
...@@ -426,6 +426,10 @@ nouveau_card_init(struct drm_device *dev) ...@@ -426,6 +426,10 @@ nouveau_card_init(struct drm_device *dev)
goto out; goto out;
} }
ret = nouveau_mem_detect(dev);
if (ret)
goto out_bios;
ret = nouveau_gpuobj_early_init(dev); ret = nouveau_gpuobj_early_init(dev);
if (ret) if (ret)
goto out_bios; goto out_bios;
......
...@@ -278,7 +278,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev) ...@@ -278,7 +278,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
default: default:
nv_wr32(dev, 0x2230, 0); nv_wr32(dev, 0x2230, 0);
nv_wr32(dev, NV40_PFIFO_RAMFC, 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)); dev_priv->ramfc_offset) >> 16) | (3 << 16));
break; break;
} }
......
...@@ -143,7 +143,7 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) ...@@ -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, ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19,
0, nouveau_mem_fb_amount(dev)); 0, dev_priv->vram_size);
if (ret) { if (ret) {
nv50_evo_channel_del(pchan); nv50_evo_channel_del(pchan);
return ret; return ret;
...@@ -231,7 +231,7 @@ nv50_display_init(struct drm_device *dev) ...@@ -231,7 +231,7 @@ nv50_display_init(struct drm_device *dev)
/* This used to be in crtc unblank, but seems out of place there. */ /* This used to be in crtc unblank, but seems out of place there. */
nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0); nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
/* RAM is clamped to 256 MiB. */ /* 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); NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
if (ram_amount > 256*1024*1024) if (ram_amount > 256*1024*1024)
ram_amount = 256*1024*1024; ram_amount = 256*1024*1024;
......
...@@ -76,17 +76,12 @@ nv50_instmem_init(struct drm_device *dev) ...@@ -76,17 +76,12 @@ nv50_instmem_init(struct drm_device *dev)
for (i = 0x1700; i <= 0x1710; i += 4) for (i = 0x1700; i <= 0x1710; i += 4)
priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); 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 /* 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 * setting up the below tables over the top of the VBIOS image at
* some point. * some point.
*/ */
dev_priv->ramin_rsvd_vram = 1 << 20; 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_size = 128 << 10;
c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
...@@ -106,7 +101,7 @@ nv50_instmem_init(struct drm_device *dev) ...@@ -106,7 +101,7 @@ nv50_instmem_init(struct drm_device *dev)
dev_priv->vm_gart_size = NV50_VM_BLOCK; 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_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) if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
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); dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment