summaryrefslogtreecommitdiff
path: root/shared-core/nouveau_mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/nouveau_mem.c')
-rw-r--r--shared-core/nouveau_mem.c910
1 files changed, 0 insertions, 910 deletions
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
deleted file mode 100644
index 627b9178..00000000
--- a/shared-core/nouveau_mem.c
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
- * Copyright 2005 Stephane Marchesin
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-
-#include "drmP.h"
-#include "drm.h"
-#include "drm_sarea.h"
-#include "nouveau_drv.h"
-
-static struct mem_block *
-split_block(struct mem_block *p, uint64_t start, uint64_t size,
- struct drm_file *file_priv)
-{
- /* Maybe cut off the start of an existing block */
- if (start > p->start) {
- struct mem_block *newblock =
- drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
- if (!newblock)
- goto out;
- newblock->start = start;
- newblock->size = p->size - (start - p->start);
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size -= newblock->size;
- p = newblock;
- }
-
- /* Maybe cut off the end of an existing block */
- if (size < p->size) {
- struct mem_block *newblock =
- drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
- if (!newblock)
- goto out;
- newblock->start = start + size;
- newblock->size = p->size - size;
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size = size;
- }
-
-out:
- /* Our block is in the middle */
- p->file_priv = file_priv;
- return p;
-}
-
-struct mem_block *
-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
- int align2, struct drm_file *file_priv, int tail)
-{
- struct mem_block *p;
- uint64_t mask = (1 << align2) - 1;
-
- if (!heap)
- return NULL;
-
- if (tail) {
- list_for_each_prev(p, heap) {
- uint64_t start = ((p->start + p->size) - size) & ~mask;
-
- if (p->file_priv == 0 && start >= p->start &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- } else {
- list_for_each(p, heap) {
- uint64_t start = (p->start + mask) & ~mask;
-
- if (p->file_priv == 0 &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- }
-
- return NULL;
-}
-
-static struct mem_block *find_block(struct mem_block *heap, uint64_t start)
-{
- struct mem_block *p;
-
- list_for_each(p, heap)
- if (p->start == start)
- return p;
-
- return NULL;
-}
-
-void nouveau_mem_free_block(struct mem_block *p)
-{
- p->file_priv = NULL;
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- if (p->next->file_priv == 0) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- drm_free(q, sizeof(*q), DRM_MEM_BUFS);
- }
-
- if (p->prev->file_priv == 0) {
- struct mem_block *q = p->prev;
- q->size += p->size;
- q->next = p->next;
- q->next->prev = q;
- drm_free(p, sizeof(*q), DRM_MEM_BUFS);
- }
-}
-
-/* Initialize. How to check for an uninitialized heap?
- */
-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
- uint64_t size)
-{
- struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
-
- if (!blocks)
- return -ENOMEM;
-
- *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
- if (!*heap) {
- drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
- return -ENOMEM;
- }
-
- blocks->start = start;
- blocks->size = size;
- blocks->file_priv = NULL;
- blocks->next = blocks->prev = *heap;
-
- memset(*heap, 0, sizeof(**heap));
- (*heap)->file_priv = (struct drm_file *) - 1;
- (*heap)->next = (*heap)->prev = blocks;
- return 0;
-}
-
-/*
- * Free all blocks associated with the releasing file_priv
- */
-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
-{
- struct mem_block *p;
-
- if (!heap || !heap->next)
- return;
-
- list_for_each(p, heap) {
- if (p->file_priv == file_priv)
- p->file_priv = NULL;
- }
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- list_for_each(p, heap) {
- while ((p->file_priv == 0) && (p->next->file_priv == 0) &&
- (p->next!=heap)) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
- }
- }
-}
-
-/*
- * Cleanup everything
- */
-void nouveau_mem_takedown(struct mem_block **heap)
-{
- struct mem_block *p;
-
- if (!*heap)
- return;
-
- for (p = (*heap)->next; p != *heap;) {
- struct mem_block *q = p;
- p = p->next;
- drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
- }
-
- drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER);
- *heap = NULL;
-}
-
-void nouveau_mem_close(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- nouveau_mem_takedown(&dev_priv->agp_heap);
- nouveau_mem_takedown(&dev_priv->fb_heap);
- if (dev_priv->pci_heap)
- nouveau_mem_takedown(&dev_priv->pci_heap);
-}
-
-/*XXX BSD needs compat functions for pci access
- * #define DRM_PCI_DEV struct device
- * #define drm_pci_get_bsf pci_get_bsf
- * and a small inline to do *val = pci_read_config(pdev->device, where, 4);
- * might work
- */
-static int nforce_pci_fn_read_config_dword(int devfn, int where, uint32_t *val)
-{
-#ifdef __linux__
- DRM_PCI_DEV *pdev;
-
- if (!(pdev = drm_pci_get_bsf(0, 0, devfn))) {
- DRM_ERROR("nForce PCI device function 0x%02x not found\n",
- devfn);
- return -ENODEV;
- }
-
- return drm_pci_read_config_dword(pdev, where, val);
-#else
- DRM_ERROR("BSD compat for checking IGP memory amount needed\n");
- return 0;
-#endif
-}
-
-static void nouveau_mem_check_nforce_dimms(struct drm_device *dev)
-{
- uint32_t mem_ctrlr_pciid;
-
- nforce_pci_fn_read_config_dword(3, 0x00, &mem_ctrlr_pciid);
- mem_ctrlr_pciid >>= 16;
-
- if (mem_ctrlr_pciid == 0x01a9 || mem_ctrlr_pciid == 0x01ab ||
- mem_ctrlr_pciid == 0x01ed) {
- uint32_t dimm[3];
- int i;
-
- for (i = 0; i < 3; i++) {
- nforce_pci_fn_read_config_dword(2, 0x40 + i * 4, &dimm[i]);
- dimm[i] = (dimm[i] >> 8) & 0x4f;
- }
-
- if (dimm[0] + dimm[1] != dimm[2])
- DRM_INFO("Your nForce DIMMs are not arranged in "
- "optimal banks!\n");
- }
-}
-
-static uint32_t
-nouveau_mem_fb_amount_igp(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t mem = 0;
-
- if (dev_priv->flags & NV_NFORCE) {
- nforce_pci_fn_read_config_dword(1, 0x7C, &mem);
- return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
- }
- if (dev_priv->flags & NV_NFORCE2) {
- nforce_pci_fn_read_config_dword(1, 0x84, &mem);
- return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
- }
-
- DRM_ERROR("impossible!\n");
-
- return 0;
-}
-
-/* returns the amount of FB ram in bytes */
-uint64_t nouveau_mem_fb_amount(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv=dev->dev_private;
- switch(dev_priv->card_type)
- {
- case NV_04:
- case NV_05:
- if (NV_READ(NV03_BOOT_0) & 0x00000100) {
- return (((NV_READ(NV03_BOOT_0) >> 12) & 0xf)*2+2)*1024*1024;
- } else
- switch(NV_READ(NV03_BOOT_0)&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_11:
- case NV_17:
- case NV_20:
- case NV_30:
- case NV_40:
- case NV_44:
- 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_READ(NV10_PFB_CSTATUS) &
- NV10_PFB_CSTATUS_RAM_AMOUNT_MB_MASK) >>
- NV10_PFB_CSTATUS_RAM_AMOUNT_MB_SHIFT;
- return mem*1024*1024;
- }
- break;
- }
-
- DRM_ERROR("Unable to detect video ram size. Please report your setup to " DRIVER_EMAIL "\n");
- return 0;
-}
-
-static void nouveau_mem_reset_agp(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
-
- saved_pci_nv_1 = NV_READ(NV04_PBUS_PCI_NV_1);
- saved_pci_nv_19 = NV_READ(NV04_PBUS_PCI_NV_19);
-
- /* clear busmaster bit */
- NV_WRITE(NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4);
- /* clear SBA and AGP bits */
- NV_WRITE(NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff);
-
- /* power cycle pgraph, if enabled */
- pmc_enable = NV_READ(NV03_PMC_ENABLE);
- if (pmc_enable & NV_PMC_ENABLE_PGRAPH) {
- NV_WRITE(NV03_PMC_ENABLE, pmc_enable & ~NV_PMC_ENABLE_PGRAPH);
- NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) |
- NV_PMC_ENABLE_PGRAPH);
- }
-
- /* and restore (gives effect of resetting AGP) */
- NV_WRITE(NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
- NV_WRITE(NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
-}
-
-static int
-nouveau_mem_init_agp(struct drm_device *dev, int ttm)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_agp_info info;
- struct drm_agp_mode mode;
- int ret;
-
- nouveau_mem_reset_agp(dev);
-
- ret = drm_agp_acquire(dev);
- if (ret) {
- DRM_ERROR("Unable to acquire AGP: %d\n", ret);
- return ret;
- }
-
- ret = drm_agp_info(dev, &info);
- if (ret) {
- DRM_ERROR("Unable to get AGP info: %d\n", ret);
- return ret;
- }
-
- /* see agp.h for the AGPSTAT_* modes available */
- mode.mode = info.mode;
- ret = drm_agp_enable(dev, mode);
- if (ret) {
- DRM_ERROR("Unable to enable AGP: %d\n", ret);
- return ret;
- }
-
- if (!ttm) {
- struct drm_agp_buffer agp_req;
- struct drm_agp_binding bind_req;
-
- agp_req.size = info.aperture_size;
- agp_req.type = 0;
- ret = drm_agp_alloc(dev, &agp_req);
- if (ret) {
- DRM_ERROR("Unable to alloc AGP: %d\n", ret);
- return ret;
- }
-
- bind_req.handle = agp_req.handle;
- bind_req.offset = 0;
- ret = drm_agp_bind(dev, &bind_req);
- if (ret) {
- DRM_ERROR("Unable to bind AGP: %d\n", ret);
- return ret;
- }
- }
-
- dev_priv->gart_info.type = NOUVEAU_GART_AGP;
- dev_priv->gart_info.aper_base = info.aperture_base;
- dev_priv->gart_info.aper_size = info.aperture_size;
- return 0;
-}
-
-#define HACK_OLD_MM
-int
-nouveau_mem_init_ttm(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t vram_size, bar1_size;
- int ret;
-
- dev_priv->agp_heap = dev_priv->pci_heap = dev_priv->fb_heap = NULL;
- dev_priv->fb_phys = drm_get_resource_start(dev,1);
- dev_priv->gart_info.type = NOUVEAU_GART_NONE;
-
- drm_bo_driver_init(dev);
-
- /* non-mappable vram */
- dev_priv->fb_available_size = nouveau_mem_fb_amount(dev);
- dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
- vram_size = dev_priv->fb_available_size >> PAGE_SHIFT;
- bar1_size = drm_get_resource_len(dev, 1) >> PAGE_SHIFT;
- if (bar1_size < vram_size) {
- if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0,
- bar1_size, vram_size - bar1_size, 1))) {
- DRM_ERROR("Failed PRIV0 mm init: %d\n", ret);
- return ret;
- }
- vram_size = bar1_size;
- }
-
- /* mappable vram */
-#ifdef HACK_OLD_MM
- vram_size /= 4;
-#endif
- if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size, 1))) {
- DRM_ERROR("Failed VRAM mm init: %d\n", ret);
- return ret;
- }
-
- /* GART */
-#if !defined(__powerpc__) && !defined(__ia64__)
- if (drm_device_is_agp(dev) && dev->agp) {
- if ((ret = nouveau_mem_init_agp(dev, 1)))
- DRM_ERROR("Error initialising AGP: %d\n", ret);
- }
-#endif
-
- if (dev_priv->gart_info.type == NOUVEAU_GART_NONE) {
- if ((ret = nouveau_sgdma_init(dev)))
- DRM_ERROR("Error initialising PCI SGDMA: %d\n", ret);
- }
-
- if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0,
- dev_priv->gart_info.aper_size >>
- PAGE_SHIFT, 1))) {
- DRM_ERROR("Failed TT mm init: %d\n", ret);
- return ret;
- }
-
-#ifdef HACK_OLD_MM
- vram_size <<= PAGE_SHIFT;
- DRM_INFO("Old MM using %dKiB VRAM\n", (vram_size * 3) >> 10);
- if (nouveau_mem_init_heap(&dev_priv->fb_heap, vram_size, vram_size * 3))
- return -ENOMEM;
-#endif
-
- return 0;
-}
-
-int nouveau_mem_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t fb_size;
- int ret = 0;
-
- dev_priv->agp_heap = dev_priv->pci_heap = dev_priv->fb_heap = NULL;
- dev_priv->fb_phys = 0;
- dev_priv->gart_info.type = NOUVEAU_GART_NONE;
-
- if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2))
- nouveau_mem_check_nforce_dimms(dev);
-
- /* setup a mtrr over the FB */
- dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
- nouveau_mem_fb_amount(dev),
- DRM_MTRR_WC);
-
- /* Init FB */
- dev_priv->fb_phys=drm_get_resource_start(dev,1);
- fb_size = nouveau_mem_fb_amount(dev);
- /* On G80, limit VRAM to 512MiB temporarily due to limits in how
- * we handle VRAM page tables.
- */
- if (dev_priv->card_type >= NV_50 && fb_size > (512 * 1024 * 1024))
- fb_size = (512 * 1024 * 1024);
- fb_size -= dev_priv->ramin_rsvd_vram;
- dev_priv->fb_available_size = fb_size;
- DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10);
-
- if (fb_size>256*1024*1024) {
- /* On cards with > 256Mb, you can't map everything.
- * So we create a second FB heap for that type of memory */
- if (nouveau_mem_init_heap(&dev_priv->fb_heap,
- 0, 256*1024*1024))
- return -ENOMEM;
- if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap,
- 256*1024*1024, fb_size-256*1024*1024))
- return -ENOMEM;
- } else {
- if (nouveau_mem_init_heap(&dev_priv->fb_heap, 0, fb_size))
- return -ENOMEM;
- dev_priv->fb_nomap_heap=NULL;
- }
-
-#if !defined(__powerpc__) && !defined(__ia64__)
- /* Init AGP / NV50 PCIEGART */
- if (drm_device_is_agp(dev) && dev->agp) {
- if ((ret = nouveau_mem_init_agp(dev, 0)))
- DRM_ERROR("Error initialising AGP: %d\n", ret);
- }
-#endif
-
- /*Note: this is *not* just NV50 code, but only used on NV50 for now */
- if (dev_priv->gart_info.type == NOUVEAU_GART_NONE &&
- dev_priv->card_type >= NV_50) {
- ret = nouveau_sgdma_init(dev);
- if (!ret) {
- ret = nouveau_sgdma_nottm_hack_init(dev);
- if (ret)
- nouveau_sgdma_takedown(dev);
- }
-
- if (ret)
- DRM_ERROR("Error initialising SG DMA: %d\n", ret);
- }
-
- if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
- if (nouveau_mem_init_heap(&dev_priv->agp_heap,
- 0, dev_priv->gart_info.aper_size)) {
- if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
- nouveau_sgdma_nottm_hack_takedown(dev);
- nouveau_sgdma_takedown(dev);
- }
- }
- }
-
- /* NV04-NV40 PCIEGART */
- if (!dev_priv->agp_heap && dev_priv->card_type < NV_50) {
- struct drm_scatter_gather sgreq;
-
- DRM_DEBUG("Allocating sg memory for PCI DMA\n");
- sgreq.size = 16 << 20; //16MB of PCI scatter-gather zone
-
- if (drm_sg_alloc(dev, &sgreq)) {
- DRM_ERROR("Unable to allocate %ldMB of scatter-gather"
- " pages for PCI DMA!",sgreq.size>>20);
- } else {
- if (nouveau_mem_init_heap(&dev_priv->pci_heap, 0,
- dev->sg->pages * PAGE_SIZE)) {
- DRM_ERROR("Unable to initialize pci_heap!");
- }
- }
- }
-
- /* G8x: Allocate shared page table to map real VRAM pages into */
- if (dev_priv->card_type >= NV_50) {
- unsigned size = ((512 * 1024 * 1024) / 65536) * 8;
-
- ret = nouveau_gpuobj_new(dev, NULL, size, 0,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ALLOW_NO_REFS,
- &dev_priv->vm_vram_pt);
- if (ret) {
- DRM_ERROR("Error creating VRAM page table: %d\n", ret);
- return ret;
- }
- }
-
-
- return 0;
-}
-
-struct mem_block *
-nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,
- int flags, struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct mem_block *block;
- int type, tail = !(flags & NOUVEAU_MEM_USER);
-
- /*
- * Make things easier on ourselves: all allocations are page-aligned.
- * We need that to map allocated regions into the user space
- */
- if (alignment < PAGE_SIZE)
- alignment = PAGE_SIZE;
-
- /* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB
- * page size in the GPU VM.
- */
- if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) {
- size = (size + 65535) & ~65535;
- if (alignment < 65536)
- alignment = 65536;
- }
-
- /* Further down wants alignment in pages, not bytes */
- alignment >>= PAGE_SHIFT;
-
- /*
- * Warn about 0 sized allocations, but let it go through. It'll return 1 page
- */
- if (size == 0)
- DRM_INFO("warning : 0 byte allocation\n");
-
- /*
- * Keep alloc size a multiple of the page size to keep drm_addmap() happy
- */
- if (size & (~PAGE_MASK))
- size = ((size/PAGE_SIZE) + 1) * PAGE_SIZE;
-
-
-#define NOUVEAU_MEM_ALLOC_AGP {\
- type=NOUVEAU_MEM_AGP;\
- block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\
- alignment, file_priv, tail); \
- if (block) goto alloc_ok;\
- }
-
-#define NOUVEAU_MEM_ALLOC_PCI {\
- type = NOUVEAU_MEM_PCI;\
- block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \
- alignment, file_priv, tail); \
- if ( block ) goto alloc_ok;\
- }
-
-#define NOUVEAU_MEM_ALLOC_FB {\
- type=NOUVEAU_MEM_FB;\
- if (!(flags&NOUVEAU_MEM_MAPPED)) {\
- block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\
- size, alignment, \
- file_priv, tail); \
- if (block) goto alloc_ok;\
- }\
- block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\
- alignment, file_priv, tail);\
- if (block) goto alloc_ok;\
- }
-
-
- if (flags&NOUVEAU_MEM_FB) NOUVEAU_MEM_ALLOC_FB
- if (flags&NOUVEAU_MEM_AGP) NOUVEAU_MEM_ALLOC_AGP
- if (flags&NOUVEAU_MEM_PCI) NOUVEAU_MEM_ALLOC_PCI
- if (flags&NOUVEAU_MEM_FB_ACCEPTABLE) NOUVEAU_MEM_ALLOC_FB
- if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) NOUVEAU_MEM_ALLOC_AGP
- if (flags&NOUVEAU_MEM_PCI_ACCEPTABLE) NOUVEAU_MEM_ALLOC_PCI
-
-
- return NULL;
-
-alloc_ok:
- block->flags=type;
-
- /* On G8x, map memory into VM */
- if (block->flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50 &&
- !(flags & NOUVEAU_MEM_NOVM)) {
- struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
- unsigned offset = block->start;
- unsigned count = block->size / 65536;
- unsigned tile = 0;
-
- if (!pt) {
- DRM_ERROR("vm alloc without vm pt\n");
- nouveau_mem_free_block(block);
- return NULL;
- }
-
- /* The tiling stuff is *not* what NVIDIA does - but both the
- * 2D and 3D engines seem happy with this simpler method.
- * Should look into why NVIDIA do what they do at some point.
- */
- if (flags & NOUVEAU_MEM_TILE) {
- if (flags & NOUVEAU_MEM_TILE_ZETA)
- tile = 0x00002800;
- else
- tile = 0x00007000;
- }
-
- while (count--) {
- unsigned pte = offset / 65536;
-
- INSTANCE_WR(pt, (pte * 2) + 0, offset | 1);
- INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile);
- offset += 65536;
- }
- } else {
- block->flags |= NOUVEAU_MEM_NOVM;
- }
-
- if (flags&NOUVEAU_MEM_MAPPED)
- {
- struct drm_map_list *entry;
- int ret = 0;
- block->flags|=NOUVEAU_MEM_MAPPED;
-
- if (type == NOUVEAU_MEM_AGP) {
- if (dev_priv->gart_info.type != NOUVEAU_GART_SGDMA)
- ret = drm_addmap(dev, block->start, block->size,
- _DRM_AGP, 0, &block->map);
- else
- ret = drm_addmap(dev, block->start, block->size,
- _DRM_SCATTER_GATHER, 0, &block->map);
- }
- else if (type == NOUVEAU_MEM_FB)
- ret = drm_addmap(dev, block->start + dev_priv->fb_phys,
- block->size, _DRM_FRAME_BUFFER,
- 0, &block->map);
- else if (type == NOUVEAU_MEM_PCI)
- ret = drm_addmap(dev, block->start, block->size,
- _DRM_SCATTER_GATHER, 0, &block->map);
-
- if (ret) {
- nouveau_mem_free_block(block);
- return NULL;
- }
-
- entry = drm_find_matching_map(dev, block->map);
- if (!entry) {
- nouveau_mem_free_block(block);
- return NULL;
- }
- block->map_handle = entry->user_token;
- }
-
- DRM_DEBUG("allocated %lld bytes at 0x%llx type=0x%08x\n", block->size, block->start, block->flags);
- return block;
-}
-
-void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags);
-
- if (block->flags&NOUVEAU_MEM_MAPPED)
- drm_rmmap(dev, block->map);
-
- /* G8x: Remove pages from vm */
- if (block->flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50 &&
- !(block->flags & NOUVEAU_MEM_NOVM)) {
- struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
- unsigned offset = block->start;
- unsigned count = block->size / 65536;
-
- if (!pt) {
- DRM_ERROR("vm free without vm pt\n");
- goto out_free;
- }
-
- while (count--) {
- unsigned pte = offset / 65536;
- INSTANCE_WR(pt, (pte * 2) + 0, 0);
- INSTANCE_WR(pt, (pte * 2) + 1, 0);
- offset += 65536;
- }
- }
-
-out_free:
- nouveau_mem_free_block(block);
-}
-
-/*
- * Ioctls
- */
-
-int
-nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_nouveau_mem_alloc *alloc = data;
- struct mem_block *block;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
- if (alloc->flags & NOUVEAU_MEM_INTERNAL)
- return -EINVAL;
-
- block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
- alloc->flags | NOUVEAU_MEM_USER, file_priv);
- if (!block)
- return -ENOMEM;
- alloc->map_handle=block->map_handle;
- alloc->offset=block->start;
- alloc->flags=block->flags;
-
- if (dev_priv->card_type >= NV_50 && alloc->flags & NOUVEAU_MEM_FB)
- alloc->offset += 512*1024*1024;
-
- return 0;
-}
-
-int
-nouveau_ioctl_mem_free(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_nouveau_mem_free *memfree = data;
- struct mem_block *block;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
- if (dev_priv->card_type >= NV_50 && memfree->flags & NOUVEAU_MEM_FB)
- memfree->offset -= 512*1024*1024;
-
- block=NULL;
- if (dev_priv->fb_heap && memfree->flags & NOUVEAU_MEM_FB)
- block = find_block(dev_priv->fb_heap, memfree->offset);
- else if (dev_priv->agp_heap && memfree->flags & NOUVEAU_MEM_AGP)
- block = find_block(dev_priv->agp_heap, memfree->offset);
- else if (dev_priv->pci_heap && memfree->flags & NOUVEAU_MEM_PCI)
- block = find_block(dev_priv->pci_heap, memfree->offset);
- if (!block)
- return -EFAULT;
- if (block->file_priv != file_priv)
- return -EPERM;
-
- nouveau_mem_free(dev, block);
- return 0;
-}
-
-int
-nouveau_ioctl_mem_tile(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct drm_nouveau_mem_tile *memtile = data;
- struct mem_block *block = NULL;
-
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
- if (dev_priv->card_type < NV_50)
- return -EINVAL;
-
- if (memtile->flags & NOUVEAU_MEM_FB) {
- memtile->offset -= 512*1024*1024;
- block = find_block(dev_priv->fb_heap, memtile->offset);
- }
-
- if (!block)
- return -EINVAL;
-
- if (block->file_priv != file_priv)
- return -EPERM;
-
- {
- struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt;
- unsigned offset = block->start + memtile->delta;
- unsigned count = memtile->size / 65536;
- unsigned tile = 0;
-
- if (memtile->flags & NOUVEAU_MEM_TILE) {
- if (memtile->flags & NOUVEAU_MEM_TILE_ZETA)
- tile = 0x00002800;
- else
- tile = 0x00007000;
- }
-
- while (count--) {
- unsigned pte = offset / 65536;
-
- INSTANCE_WR(pt, (pte * 2) + 0, offset | 1);
- INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile);
- offset += 65536;
- }
- }
-
- return 0;
-}
-