diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_fifo.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_fifo.c | 281 |
1 files changed, 125 insertions, 156 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index 471723eaf8ad..7d85553d518c 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -26,10 +26,12 @@ #include "nouveau_drv.h" #include "nouveau_mm.h" +#include "nouveau_fifo.h" static void nvc0_fifo_isr(struct drm_device *); struct nvc0_fifo_priv { + struct nouveau_fifo_priv base; struct nouveau_gpuobj *playlist[2]; int cur_playlist; struct nouveau_vma user_vma; @@ -37,8 +39,8 @@ struct nvc0_fifo_priv { }; struct nvc0_fifo_chan { + struct nouveau_fifo_chan base; struct nouveau_gpuobj *user; - struct nouveau_gpuobj *ramfc; }; static void @@ -46,8 +48,7 @@ nvc0_fifo_playlist_update(struct drm_device *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 nvc0_fifo_priv *priv = pfifo->priv; + struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); struct nouveau_gpuobj *cur; int i, p; @@ -69,31 +70,20 @@ nvc0_fifo_playlist_update(struct drm_device *dev) NV_ERROR(dev, "PFIFO - playlist update failed\n"); } -int -nvc0_fifo_create_context(struct nouveau_channel *chan) +static int +nvc0_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 nvc0_fifo_priv *priv = pfifo->priv; - struct nvc0_fifo_chan *fifoch; + struct nvc0_fifo_priv *priv = nv_engine(dev, engine); + struct nvc0_fifo_chan *fctx; u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; - int ret; + int ret, 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; - - /* allocate vram for control regs, map into polling area */ - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user); - if (ret) - goto error; - - nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000, - *(struct nouveau_mem **)fifoch->user->node); chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + priv->user_vma.offset + (chan->id * 0x1000), @@ -103,175 +93,77 @@ nvc0_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); + /* allocate vram for control regs, map into polling area */ + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &fctx->user); if (ret) goto error; - nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst)); - nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst)); - 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 | + nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000, + *(struct nouveau_mem **)fctx->user->node); + + for (i = 0; i < 0x100; i += 4) + nv_wo32(chan->ramin, i, 0x00000000); + nv_wo32(chan->ramin, 0x08, lower_32_bits(fctx->user->vinst)); + nv_wo32(chan->ramin, 0x0c, upper_32_bits(fctx->user->vinst)); + 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, 0x54, 0x00000002); - nv_wo32(fifoch->ramfc, 0x84, 0x20400000); - nv_wo32(fifoch->ramfc, 0x94, 0x30000001); - nv_wo32(fifoch->ramfc, 0x9c, 0x00000100); - nv_wo32(fifoch->ramfc, 0xa4, 0x1f1f1f1f); - nv_wo32(fifoch->ramfc, 0xa8, 0x1f1f1f1f); - nv_wo32(fifoch->ramfc, 0xac, 0x0000001f); - nv_wo32(fifoch->ramfc, 0xb8, 0xf8000000); - nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */ + nv_wo32(chan->ramin, 0x54, 0x00000002); + nv_wo32(chan->ramin, 0x84, 0x20400000); + nv_wo32(chan->ramin, 0x94, 0x30000001); + nv_wo32(chan->ramin, 0x9c, 0x00000100); + nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f); + nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f); + nv_wo32(chan->ramin, 0xac, 0x0000001f); + nv_wo32(chan->ramin, 0xb8, 0xf8000000); + nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */ + nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */ pinstmem->flush(dev); nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 | (chan->ramin->vinst >> 12)); nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001); nvc0_fifo_playlist_update(dev); - return 0; error: - pfifo->destroy_context(chan); + if (ret) + priv->base.base.context_del(chan, engine); return ret; } -void -nvc0_fifo_destroy_context(struct nouveau_channel *chan) +static void +nvc0_fifo_context_del(struct nouveau_channel *chan, int engine) { + struct nvc0_fifo_chan *fctx = chan->engctx[engine]; struct drm_device *dev = chan->dev; - struct nvc0_fifo_chan *fifoch; nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); 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)); - nvc0_fifo_playlist_update(dev); - nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000); + nouveau_gpuobj_ref(NULL, &fctx->user); if (chan->user) { iounmap(chan->user); chan->user = NULL; } - fifoch = chan->fifo_priv; - chan->fifo_priv = NULL; - if (!fifoch) - return; - - nouveau_gpuobj_ref(NULL, &fifoch->ramfc); - nouveau_gpuobj_ref(NULL, &fifoch->user); - kfree(fifoch); -} - -int -nvc0_fifo_load_context(struct nouveau_channel *chan) -{ - return 0; -} - -int -nvc0_fifo_unload_context(struct drm_device *dev) -{ - int i; - - for (i = 0; i < 128; i++) { - if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1)) - continue; - - nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000); - 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 -nvc0_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 nvc0_fifo_priv *priv; - - priv = pfifo->priv; - if (!priv) - return; - - nouveau_vm_put(&priv->user_vma); - nouveau_gpuobj_ref(NULL, &priv->playlist[1]); - nouveau_gpuobj_ref(NULL, &priv->playlist[0]); - kfree(priv); -} - -void -nvc0_fifo_takedown(struct drm_device *dev) -{ - nv_wr32(dev, 0x002140, 0x00000000); - nvc0_fifo_destroy(dev); + chan->engctx[engine] = NULL; + kfree(fctx); } static int -nvc0_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 nvc0_fifo_priv *priv; - int ret; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - pfifo->priv = priv; - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, - &priv->playlist[0]); - if (ret) - goto error; - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, - &priv->playlist[1]); - if (ret) - goto error; - - ret = nouveau_vm_get(dev_priv->bar1_vm, pfifo->channels * 0x1000, - 12, NV_MEM_ACCESS_RW, &priv->user_vma); - if (ret) - goto error; - - nouveau_irq_register(dev, 8, nvc0_fifo_isr); - return 0; - -error: - nvc0_fifo_destroy(dev); - return ret; -} - -int -nvc0_fifo_init(struct drm_device *dev) +nvc0_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 nvc0_fifo_priv *priv = nv_engine(dev, engine); struct nouveau_channel *chan; - struct nvc0_fifo_priv *priv; - int ret, i; - - if (!pfifo->priv) { - ret = nvc0_fifo_create(dev); - if (ret) - return ret; - } - priv = pfifo->priv; + int i; /* reset PFIFO, enable all available PSUBFIFO areas */ nv_mask(dev, 0x000200, 0x00000100, 0x00000000); @@ -309,7 +201,7 @@ nvc0_fifo_init(struct drm_device *dev) /* restore PFIFO context table */ for (i = 0; i < 128; i++) { chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->fifo_priv) + if (!chan || !chan->engctx[engine]) continue; nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 | @@ -321,6 +213,29 @@ nvc0_fifo_init(struct drm_device *dev) return 0; } +static int +nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend) +{ + int i; + + for (i = 0; i < 128; i++) { + if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1)) + continue; + + nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000); + 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 nvc0_fifo_fault_unit[] = { { 0x00, "PGRAPH" }, { 0x03, "PEEPHOLE" }, @@ -410,13 +325,14 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) static int nvc0_fifo_page_flip(struct drm_device *dev, u32 chid) { + struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = NULL; unsigned long flags; int ret = -EINVAL; spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) { + if (likely(chid >= 0 && chid < priv->base.channels)) { chan = dev_priv->channels.ptr[chid]; if (likely(chan)) ret = nouveau_finish_page_flip(chan, NULL); @@ -505,3 +421,56 @@ nvc0_fifo_isr(struct drm_device *dev) nv_wr32(dev, 0x002140, 0); } } + +static void +nvc0_fifo_destroy(struct drm_device *dev, int engine) +{ + struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO); + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nouveau_vm_put(&priv->user_vma); + nouveau_gpuobj_ref(NULL, &priv->playlist[1]); + nouveau_gpuobj_ref(NULL, &priv->playlist[0]); + + dev_priv->eng[engine] = NULL; + kfree(priv); +} + +int +nvc0_fifo_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_fifo_priv *priv; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base.base.destroy = nvc0_fifo_destroy; + priv->base.base.init = nvc0_fifo_init; + priv->base.base.fini = nvc0_fifo_fini; + priv->base.base.context_new = nvc0_fifo_context_new; + priv->base.base.context_del = nvc0_fifo_context_del; + priv->base.channels = 128; + dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base; + + ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]); + if (ret) + goto error; + + ret = nouveau_vm_get(dev_priv->bar1_vm, priv->base.channels * 0x1000, + 12, NV_MEM_ACCESS_RW, &priv->user_vma); + if (ret) + goto error; + + nouveau_irq_register(dev, 8, nvc0_fifo_isr); +error: + if (ret) + priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO); + return ret; +} |