forked from Minki/linux
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>
This commit is contained in:
parent
43efc9ce25
commit
5125bfd886
@ -513,8 +513,12 @@ struct drm_nouveau_private {
|
||||
int flags;
|
||||
|
||||
void __iomem *mmio;
|
||||
|
||||
void __iomem *ramin;
|
||||
uint32_t ramin_size;
|
||||
u32 ramin_size;
|
||||
u32 ramin_base;
|
||||
bool ramin_available;
|
||||
spinlock_t ramin_lock;
|
||||
|
||||
struct nouveau_bo *vga_ram;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (!gpuobj->im_pramin) {
|
||||
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);
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ int nv04_instmem_init(struct drm_device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->ramin_available = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
|
||||
ctx.data = chan->ramin_grctx;
|
||||
nv40_grctx_init(&ctx);
|
||||
|
||||
nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->im_pramin->start);
|
||||
nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,8 @@ nv50_instmem_init(struct drm_device *dev)
|
||||
for (i = 0; i < 8; i++)
|
||||
nv_wr32(dev, 0x1900 + (i*4), 0);
|
||||
|
||||
dev_priv->ramin_available = true;
|
||||
|
||||
/* Assume that praying isn't enough, check that we can re-read the
|
||||
* entire fake channel back from the PRAMIN BAR */
|
||||
for (i = 0; i < c_size; i += 4) {
|
||||
|
Loading…
Reference in New Issue
Block a user