#include "drmP.h" #include "drm.h" #include "nouveau_drv.h" #include "nouveau_ramht.h" /* returns the size of fifo context */ static int nouveau_fifo_ctx_size(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; if (dev_priv->chipset >= 0x40) return 128; else if (dev_priv->chipset >= 0x17) return 64; return 32; } int nv04_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *ramht = NULL; u32 offset, length; int ret; /* RAMIN always available */ dev_priv->ramin_available = true; /* Reserve space at end of VRAM for PRAMIN */ if (dev_priv->card_type >= NV_40) { u32 vs = hweight8((nv_rd32(dev, 0x001540) & 0x0000ff00) >> 8); u32 rsvd; /* estimate grctx size, the magics come from nv40_grctx.c */ if (dev_priv->chipset == 0x40) rsvd = 0x6aa0 * vs; else if (dev_priv->chipset < 0x43) rsvd = 0x4f00 * vs; else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs; else rsvd = 0x4a40 * vs; rsvd += 16 * 1024; rsvd *= dev_priv->engine.fifo.channels; /* pciegart table */ if (pci_is_pcie(dev->pdev)) rsvd += 512 * 1024; /* object storage */ rsvd += 512 * 1024; dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096); } else { dev_priv->ramin_rsvd_vram = 512 * 1024; } /* Setup shared RAMHT */ ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096, NVOBJ_FLAG_ZERO_ALLOC, &ramht); if (ret) return ret; ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht); nouveau_gpuobj_ref(NULL, &ramht); if (ret) return ret; /* And RAMRO */ ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512, NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro); if (ret) return ret; /* And RAMFC */ length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev); switch (dev_priv->card_type) { case NV_40: offset = 0x20000; break; default: offset = 0x11400; break; } ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length, NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc); if (ret) return ret; /* Only allow space after RAMFC to be used for object allocation */ offset += length; /* It appears RAMRO (or something?) is controlled by 0x2220/0x2230 * on certain NV4x chipsets as well as RAMFC. When 0x2230 == 0 * ("new style" control) the upper 16-bits of 0x2220 points at this * other mysterious table that's clobbering important things. * * We're now pointing this at RAMIN+0x30000 to avoid RAMFC getting * smashed to pieces on us, so reserve 0x30000-0x40000 too.. */ if (dev_priv->card_type >= NV_40) { if (offset < 0x40000) offset = 0x40000; } ret = drm_mm_init(&dev_priv->ramin_heap, offset, dev_priv->ramin_rsvd_vram - offset); if (ret) { NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret); return ret; } return 0; } void nv04_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL); nouveau_gpuobj_ref(NULL, &dev_priv->ramro); nouveau_gpuobj_ref(NULL, &dev_priv->ramfc); if (drm_mm_initialized(&dev_priv->ramin_heap)) drm_mm_takedown(&dev_priv->ramin_heap); } int nv04_instmem_suspend(struct drm_device *dev) { return 0; } void nv04_instmem_resume(struct drm_device *dev) { } int nv04_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, u32 size, u32 align) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_mm_node *ramin = NULL; do { if (drm_mm_pre_get(&dev_priv->ramin_heap)) return -ENOMEM; spin_lock(&dev_priv->ramin_lock); ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0); if (ramin == NULL) { spin_unlock(&dev_priv->ramin_lock); return -ENOMEM; } ramin = drm_mm_get_block_atomic(ramin, size, align); spin_unlock(&dev_priv->ramin_lock); } while (ramin == NULL); gpuobj->node = ramin; gpuobj->vinst = ramin->start; return 0; } void nv04_instmem_put(struct nouveau_gpuobj *gpuobj) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; spin_lock(&dev_priv->ramin_lock); drm_mm_put_block(gpuobj->node); gpuobj->node = NULL; spin_unlock(&dev_priv->ramin_lock); } int nv04_instmem_map(struct nouveau_gpuobj *gpuobj) { gpuobj->pinst = gpuobj->vinst; return 0; } void nv04_instmem_unmap(struct nouveau_gpuobj *gpuobj) { } void nv04_instmem_flush(struct drm_device *dev) { }