summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_object.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-09-01 15:24:33 +1000
committerBen Skeggs <bskeggs@redhat.com>2010-09-24 16:20:28 +1000
commit5125bfd88608012d58652ac7ea6a03a78773200f (patch)
tree8ccb36c6a023392e3c8a9f2c4e84c74ccdcaeb44 /drivers/gpu/drm/nouveau/nouveau_object.c
parent43efc9ce25c6956133c07394a6fa44ef2c9268a4 (diff)
drm/nv50: allow gpuobjs that aren't mapped into aperture
Reviewed-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_object.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c102
1 files changed, 77 insertions, 25 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 4bcea11f54e6..df445fcb8321 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -75,7 +75,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
- struct drm_mm *pramin = NULL;
+ struct drm_mm_node *ramin = NULL;
int ret;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -95,36 +95,42 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
- /* Choose between global instmem heap, and per-channel private
- * instmem heap. On <NV50 allow requests for private instmem
- * to be satisfied from global heap if no per-channel area
- * available.
- */
if (chan) {
NV_DEBUG(dev, "channel heap\n");
- pramin = &chan->ramin_heap;
+
+ ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
+ if (ramin)
+ ramin = drm_mm_get_block(ramin, size, align);
+
+ if (!ramin) {
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return -ENOMEM;
+ }
} else {
NV_DEBUG(dev, "global heap\n");
- pramin = &dev_priv->ramin_heap;
+ /* allocate backing pages, sets vinst */
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
- }
- /* Allocate a chunk of the PRAMIN aperture */
- gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
- if (gpuobj->im_pramin)
- gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+ /* try and get aperture space */
+ ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0);
+ if (ramin)
+ ramin = drm_mm_get_block(ramin, size, align);
- if (!gpuobj->im_pramin) {
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return -ENOMEM;
+ /* on nv50 it's ok to fail, we have a fallback path */
+ if (!ramin && dev_priv->card_type < NV_50) {
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return -ENOMEM;
+ }
}
- if (!chan) {
+ /* if we got a chunk of the aperture, map pages into it */
+ gpuobj->im_pramin = ramin;
+ if (!chan && gpuobj->im_pramin) {
ret = engine->instmem.bind(dev, gpuobj);
if (ret) {
nouveau_gpuobj_ref(NULL, &gpuobj);
@@ -134,7 +140,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
/* calculate the various different addresses for the object */
if (chan) {
- gpuobj->pinst = gpuobj->im_pramin->start + chan->ramin->pinst;
+ gpuobj->pinst = chan->ramin->pinst;
+ if (gpuobj->pinst != ~0)
+ gpuobj->pinst += gpuobj->im_pramin->start;
+
if (dev_priv->card_type < NV_50) {
gpuobj->cinst = gpuobj->pinst;
} else {
@@ -143,7 +152,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
chan->ramin->vinst;
}
} else {
- gpuobj->pinst = gpuobj->im_pramin->start;
+ if (gpuobj->im_pramin)
+ gpuobj->pinst = gpuobj->im_pramin->start;
+ else
+ gpuobj->pinst = ~0;
gpuobj->cinst = 0xdeadbeef;
}
@@ -168,6 +180,8 @@ nouveau_gpuobj_early_init(struct drm_device *dev)
NV_DEBUG(dev, "\n");
INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+ spin_lock_init(&dev_priv->ramin_lock);
+ dev_priv->ramin_base = ~0;
return 0;
}
@@ -650,12 +664,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
* locations determined during init.
*/
if (dev_priv->card_type >= NV_50) {
- uint32_t vm_offset, pde;
+ u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+ u64 vm_vinst = chan->ramin->vinst + pgd_offs;
+ u32 vm_pinst = chan->ramin->pinst;
+ u32 pde;
- vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
- vm_offset += chan->ramin->im_pramin->start;
+ if (vm_pinst != ~0)
+ vm_pinst += pgd_offs;
- ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
+ ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000,
0, &chan->vm_pd);
if (ret)
return ret;
@@ -941,11 +958,46 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
u32
nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
{
- return nv_ri32(gpuobj->dev, gpuobj->pinst + offset);
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct drm_device *dev = gpuobj->dev;
+
+ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+ u64 ptr = gpuobj->vinst + offset;
+ u32 base = ptr >> 16;
+ u32 val;
+
+ spin_lock(&dev_priv->ramin_lock);
+ if (dev_priv->ramin_base != base) {
+ dev_priv->ramin_base = base;
+ nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+ }
+ val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
+ spin_unlock(&dev_priv->ramin_lock);
+ return val;
+ }
+
+ return nv_ri32(dev, gpuobj->pinst + offset);
}
void
nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
{
- nv_wi32(gpuobj->dev, gpuobj->pinst + offset, val);
+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+ struct drm_device *dev = gpuobj->dev;
+
+ if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+ u64 ptr = gpuobj->vinst + offset;
+ u32 base = ptr >> 16;
+
+ spin_lock(&dev_priv->ramin_lock);
+ if (dev_priv->ramin_base != base) {
+ dev_priv->ramin_base = base;
+ nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+ }
+ nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
+ spin_unlock(&dev_priv->ramin_lock);
+ return;
+ }
+
+ nv_wi32(dev, gpuobj->pinst + offset, val);
}