From 78ad0f7bf2bb667729581f099781fc0b7ae58fcc Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 18 Mar 2010 13:07:47 +0100 Subject: drm/nouveau: Make use of TTM busy_placements. Previously we were filling it the same as "placements", but in some cases there're valid alternatives that we were ignoring completely. Keeping a back-up memory type helps on several low-mem situations. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 61 +++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_bo.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 026612471c9..418d881050a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -153,7 +153,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->placement.fpfn = 0; nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0; - nouveau_bo_placement_set(nvbo, flags); + nouveau_bo_placement_set(nvbo, flags, 0); nvbo->channel = chan; ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, @@ -172,26 +172,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 @@ -199,7 +206,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, @@ -215,9 +222,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) { @@ -244,7 +249,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; @@ -253,8 +258,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) { @@ -439,10 +443,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; } -- cgit v1.2.3-70-g09d2 From a76fb4e8ffe42144529e21fe1e609b762e8eb5cc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 18 Mar 2010 09:45:20 +1000 Subject: 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 --- drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +- drivers/gpu/drm/nouveau/nouveau_debugfs.c | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 22 +++---- drivers/gpu/drm/nouveau/nouveau_mem.c | 96 +++++++++++++++---------------- drivers/gpu/drm/nouveau/nouveau_state.c | 6 +- drivers/gpu/drm/nouveau/nv40_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 4 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 9 +-- 8 files changed, 74 insertions(+), 76 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nouveau_bo.c') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 418d881050a..eeab3fb2708 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 8ff9ef5d4b4..a251886a0ce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5d3618e4520..f7d4d2a1005 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -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 *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a4d5ecc6ed5..775a7017af6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -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; @@ -491,11 +512,11 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev) 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; } @@ -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->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 @@ -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; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 58b46807de2..1ee2b65d72e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 6b2ef4a9fce..500ccfd3a0b 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index fac6c88a2b1..bd99986a114 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -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; diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index de1f5b0062c..34280eb31df 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -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); -- cgit v1.2.3-70-g09d2