X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fnouveau%2Fnve0_fifo.c;h=1855ecbd843b81161245cfd15ccb1f4e7f8e2343;hb=2c757fd5d1a92086f225a75a8fac7cab242d11b0;hp=82ad47cdeab9eb0c2b78e853c5162b483ba8469a;hpb=5132f37700210740117f5163b5df7aa1c8469a55;p=karo-tx-linux.git diff --git a/drivers/gpu/drm/nouveau/nve0_fifo.c b/drivers/gpu/drm/nouveau/nve0_fifo.c index 82ad47cdeab9..1855ecbd843b 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,30 +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_channel_id(struct drm_device *dev) -{ - return 4095; -} - -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) + @@ -124,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) { @@ -181,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); @@ -316,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[] = { {} }; @@ -457,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; +}