aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nve0_fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nve0_fifo.c')
-rw-r--r--drivers/gpu/drm/nouveau/nve0_fifo.c284
1 files changed, 127 insertions, 157 deletions
diff --git a/drivers/gpu/drm/nouveau/nve0_fifo.c b/drivers/gpu/drm/nouveau/nve0_fifo.c
index 52c54e0fdce..1855ecbd843 100644
--- a/drivers/gpu/drm/nouveau/nve0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nve0_fifo.c
@@ -26,6 +26,7 @@
#include "nouveau_drv.h"
#include "nouveau_mm.h"
+#include "nouveau_fifo.h"
#define NVE0_FIFO_ENGINE_NUM 32
@@ -37,6 +38,7 @@ struct nve0_fifo_engine {
};
struct nve0_fifo_priv {
+ struct nouveau_fifo_priv base;
struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM];
struct {
struct nouveau_gpuobj *mem;
@@ -46,7 +48,7 @@ struct nve0_fifo_priv {
};
struct nve0_fifo_chan {
- struct nouveau_gpuobj *ramfc;
+ struct nouveau_fifo_chan base;
u32 engine;
};
@@ -55,8 +57,7 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nve0_fifo_priv *priv = pfifo->priv;
+ struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nve0_fifo_engine *peng = &priv->engine[engine];
struct nouveau_gpuobj *cur;
u32 match = (engine << 16) | 0x00000001;
@@ -75,7 +76,7 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
peng->cur_playlist = !peng->cur_playlist;
- for (i = 0, p = 0; i < pfifo->channels; i++) {
+ for (i = 0, p = 0; i < priv->base.channels; i++) {
u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001;
if (ctrl != match)
continue;
@@ -91,24 +92,23 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine);
}
-int
-nve0_fifo_create_context(struct nouveau_channel *chan)
+static int
+nve0_fifo_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nve0_fifo_priv *priv = pfifo->priv;
- struct nve0_fifo_chan *fifoch;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ struct nve0_fifo_chan *fctx;
u64 usermem = priv->user.mem->vinst + chan->id * 512;
u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
- int ret;
+ int ret = 0, i;
- chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
- if (!chan->fifo_priv)
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
return -ENOMEM;
- fifoch = chan->fifo_priv;
- fifoch->engine = 0; /* PGRAPH */
+
+ fctx->engine = 0; /* PGRAPH */
/* allocate vram for control regs, map into polling area */
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
@@ -118,56 +118,48 @@ nve0_fifo_create_context(struct nouveau_channel *chan)
goto error;
}
- /* ramfc */
- ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
- chan->ramin->vinst, 0x100,
- NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc);
- if (ret)
- goto error;
-
- nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(usermem));
- nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(usermem));
- nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
- nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
- nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
- nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
+ for (i = 0; i < 0x100; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
+ nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
+ nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
+ nv_wo32(chan->ramin, 0x10, 0x0000face);
+ nv_wo32(chan->ramin, 0x30, 0xfffff902);
+ nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
+ nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
upper_32_bits(ib_virt));
- nv_wo32(fifoch->ramfc, 0x84, 0x20400000);
- nv_wo32(fifoch->ramfc, 0x94, 0x30000001);
- nv_wo32(fifoch->ramfc, 0x9c, 0x00000100);
- nv_wo32(fifoch->ramfc, 0xac, 0x0000001f);
- nv_wo32(fifoch->ramfc, 0xe4, 0x00000000);
- nv_wo32(fifoch->ramfc, 0xe8, chan->id);
- nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */
- nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */
+ nv_wo32(chan->ramin, 0x84, 0x20400000);
+ nv_wo32(chan->ramin, 0x94, 0x30000001);
+ nv_wo32(chan->ramin, 0x9c, 0x00000100);
+ nv_wo32(chan->ramin, 0xac, 0x0000001f);
+ nv_wo32(chan->ramin, 0xe4, 0x00000000);
+ nv_wo32(chan->ramin, 0xe8, chan->id);
+ nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
pinstmem->flush(dev);
nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 |
(chan->ramin->vinst >> 12));
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
- nve0_fifo_playlist_update(dev, fifoch->engine);
+ nve0_fifo_playlist_update(dev, fctx->engine);
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
- return 0;
error:
- pfifo->destroy_context(chan);
+ if (ret)
+ priv->base.base.context_del(chan, engine);
return ret;
}
-void
-nve0_fifo_destroy_context(struct nouveau_channel *chan)
+static void
+nve0_fifo_context_del(struct nouveau_channel *chan, int engine)
{
- struct nve0_fifo_chan *fifoch = chan->fifo_priv;
+ struct nve0_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
- if (!fifoch)
- return;
-
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
nv_wr32(dev, 0x002634, chan->id);
if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
- nve0_fifo_playlist_update(dev, fifoch->engine);
+ nve0_fifo_playlist_update(dev, fctx->engine);
nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000);
if (chan->user) {
@@ -175,118 +167,17 @@ nve0_fifo_destroy_context(struct nouveau_channel *chan)
chan->user = NULL;
}
- nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
- chan->fifo_priv = NULL;
- kfree(fifoch);
-}
-
-int
-nve0_fifo_load_context(struct nouveau_channel *chan)
-{
- return 0;
-}
-
-int
-nve0_fifo_unload_context(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- int i;
-
- for (i = 0; i < pfifo->channels; i++) {
- if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
- continue;
-
- nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
- nv_wr32(dev, 0x002634, i);
- if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
- NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
- i, nv_rd32(dev, 0x002634));
- return -EBUSY;
- }
- }
-
- return 0;
-}
-
-static void
-nve0_fifo_destroy(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nve0_fifo_priv *priv;
- int i;
-
- priv = pfifo->priv;
- if (!priv)
- return;
-
- nouveau_vm_put(&priv->user.bar);
- nouveau_gpuobj_ref(NULL, &priv->user.mem);
-
- for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
- nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
- nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
- }
- kfree(priv);
-}
-
-void
-nve0_fifo_takedown(struct drm_device *dev)
-{
- nv_wr32(dev, 0x002140, 0x00000000);
- nve0_fifo_destroy(dev);
+ chan->engctx[NVOBJ_ENGINE_FIFO] = NULL;
+ kfree(fctx);
}
static int
-nve0_fifo_create(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nve0_fifo_priv *priv;
- int ret;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- pfifo->priv = priv;
-
- ret = nouveau_gpuobj_new(dev, NULL, pfifo->channels * 512, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
- if (ret)
- goto error;
-
- ret = nouveau_vm_get(dev_priv->bar1_vm, priv->user.mem->size,
- 12, NV_MEM_ACCESS_RW, &priv->user.bar);
- if (ret)
- goto error;
-
- nouveau_vm_map(&priv->user.bar, *(struct nouveau_mem **)priv->user.mem->node);
-
- nouveau_irq_register(dev, 8, nve0_fifo_isr);
- return 0;
-
-error:
- nve0_fifo_destroy(dev);
- return ret;
-}
-
-int
-nve0_fifo_init(struct drm_device *dev)
+nve0_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_channel *chan;
- struct nve0_fifo_chan *fifoch;
- struct nve0_fifo_priv *priv;
- int ret, i;
-
- if (!pfifo->priv) {
- ret = nve0_fifo_create(dev);
- if (ret)
- return ret;
- }
- priv = pfifo->priv;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ struct nve0_fifo_chan *fctx;
+ int i;
/* reset PFIFO, enable all available PSUBFIFO areas */
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
@@ -310,22 +201,44 @@ nve0_fifo_init(struct drm_device *dev)
nv_wr32(dev, 0x002140, 0xbfffffff);
/* restore PFIFO context table */
- for (i = 0; i < pfifo->channels; i++) {
- chan = dev_priv->channels.ptr[i];
- if (!chan || !chan->fifo_priv)
+ for (i = 0; i < priv->base.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (!chan || !(fctx = chan->engctx[engine]))
continue;
- fifoch = chan->fifo_priv;
nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 |
(chan->ramin->vinst >> 12));
nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
- nve0_fifo_playlist_update(dev, fifoch->engine);
+ nve0_fifo_playlist_update(dev, fctx->engine);
nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
}
return 0;
}
+static int
+nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ for (i = 0; i < priv->base.channels; i++) {
+ if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
+ continue;
+
+ nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
+ nv_wr32(dev, 0x002634, i);
+ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+ i, nv_rd32(dev, 0x002634));
+ return -EBUSY;
+ }
+ }
+
+ nv_wr32(dev, 0x002140, 0x00000000);
+ return 0;
+}
+
struct nouveau_enum nve0_fifo_fault_unit[] = {
{}
};
@@ -451,3 +364,60 @@ nve0_fifo_isr(struct drm_device *dev)
nv_wr32(dev, 0x002140, 0);
}
}
+
+static void
+nve0_fifo_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ nouveau_vm_put(&priv->user.bar);
+ nouveau_gpuobj_ref(NULL, &priv->user.mem);
+
+ for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
+ nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
+ nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
+ }
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nve0_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_fifo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nve0_fifo_destroy;
+ priv->base.base.init = nve0_fifo_init;
+ priv->base.base.fini = nve0_fifo_fini;
+ priv->base.base.context_new = nve0_fifo_context_new;
+ priv->base.base.context_del = nve0_fifo_context_del;
+ priv->base.channels = 4096;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_get(dev_priv->bar1_vm, priv->user.mem->size,
+ 12, NV_MEM_ACCESS_RW, &priv->user.bar);
+ if (ret)
+ goto error;
+
+ nouveau_vm_map(&priv->user.bar, *(struct nouveau_mem **)priv->user.mem->node);
+
+ nouveau_irq_register(dev, 8, nve0_fifo_isr);
+error:
+ if (ret)
+ priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+ return ret;
+}