From d635711daa98be86d4c7fd01499c34f566b54ccb Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 10 Jun 2016 05:30:17 -0300 Subject: Linux-libre 4.6.2-gnu --- .../gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c | 186 ++++++++++++++------- 1 file changed, 129 insertions(+), 57 deletions(-) (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index 2e1df01bd..ed4351032 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -63,9 +63,15 @@ gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) case NVKM_ENGINE_CE1 : case NVKM_ENGINE_CE2 : return 0x0000; case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_SEC : return 0x0220; case NVKM_ENGINE_MSPDEC: return 0x0250; case NVKM_ENGINE_MSPPP : return 0x0260; case NVKM_ENGINE_MSVLD : return 0x0270; + case NVKM_ENGINE_VIC : return 0x0280; + case NVKM_ENGINE_MSENC : return 0x0290; + case NVKM_ENGINE_NVDEC : return 0x02100270; + case NVKM_ENGINE_NVENC0: return 0x02100290; + case NVKM_ENGINE_NVENC1: return 0x0210; default: WARN_ON(1); return 0; @@ -76,9 +82,9 @@ static int gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, struct nvkm_engine *engine, bool suspend) { - const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); struct gk104_fifo_chan *chan = gk104_fifo_chan(base); struct nvkm_gpuobj *inst = chan->base.inst; + u32 offset = gk104_fifo_gpfifo_engine_addr(engine); int ret; ret = gk104_fifo_gpfifo_kick(chan); @@ -87,8 +93,12 @@ gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, if (offset) { nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, 0x00000000); - nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_wo32(inst, (offset & 0xffff) + 0x00, 0x00000000); + nvkm_wo32(inst, (offset & 0xffff) + 0x04, 0x00000000); + if ((offset >>= 16)) { + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + } nvkm_done(inst); } @@ -99,15 +109,21 @@ static int gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, struct nvkm_engine *engine) { - const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); struct gk104_fifo_chan *chan = gk104_fifo_chan(base); struct nvkm_gpuobj *inst = chan->base.inst; + u32 offset = gk104_fifo_gpfifo_engine_addr(engine); if (offset) { - u64 addr = chan->engn[engine->subdev.index].vma.offset; + u64 addr = chan->engn[engine->subdev.index].vma.offset; + u32 datalo = lower_32_bits(addr) | 0x00000004; + u32 datahi = upper_32_bits(addr); nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); - nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_wo32(inst, (offset & 0xffff) + 0x00, datalo); + nvkm_wo32(inst, (offset & 0xffff) + 0x04, datahi); + if ((offset >>= 16)) { + nvkm_wo32(inst, offset + 0x00, datalo); + nvkm_wo32(inst, offset + 0x04, datahi); + } nvkm_done(inst); } @@ -154,7 +170,8 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) if (!list_empty(&chan->head)) { gk104_fifo_runlist_remove(fifo, chan); nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800); - gk104_fifo_runlist_commit(fifo, chan->engine); + gk104_fifo_gpfifo_kick(chan); + gk104_fifo_runlist_commit(fifo, chan->runl); } nvkm_wr32(device, 0x800000 + coff, 0x00000000); @@ -169,13 +186,13 @@ gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base) u32 addr = chan->base.inst->addr >> 12; u32 coff = chan->base.chid * 8; - nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->engine << 16); + nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->runl << 16); nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr); if (list_empty(&chan->head) && !chan->killed) { gk104_fifo_runlist_insert(fifo, chan); nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); - gk104_fifo_runlist_commit(fifo, chan->engine); + gk104_fifo_runlist_commit(fifo, chan->runl); nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); } } @@ -201,73 +218,79 @@ gk104_fifo_gpfifo_func = { .engine_fini = gk104_fifo_gpfifo_engine_fini, }; -int -gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) +struct gk104_fifo_chan_func { + u32 engine; + u64 subdev; +}; + +static int +gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func, + struct gk104_fifo *fifo, u32 *engmask, u16 *chid, + u64 vm, u64 ioffset, u64 ilength, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) { - union { - struct kepler_channel_gpfifo_a_v0 v0; - } *args = data; - struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_object *parent = oclass->parent; struct gk104_fifo_chan *chan; - u64 usermem, ioffset, ilength; - u32 engines; - int ret = -ENOSYS, i; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " - "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.vm, args->v0.ioffset, - args->v0.ilength, args->v0.engine); - } else - return ret; - - /* determine which downstream engines are present */ - for (i = 0, engines = 0; i < ARRAY_SIZE(fifo->engine); i++) { - u64 subdevs = gk104_fifo_engine_subdev(i); - if (!nvkm_device_engine(device, __ffs64(subdevs))) - continue; - engines |= (1 << i); + int runlist = -1, ret = -ENOSYS, i, j; + u32 engines = 0, present = 0; + u64 subdevs = 0; + u64 usermem; + + /* Determine which downstream engines are present */ + for (i = 0; i < fifo->engine_nr; i++) { + struct nvkm_engine *engine = fifo->engine[i].engine; + if (engine) { + u64 submask = BIT_ULL(engine->subdev.index); + for (j = 0; func[j].subdev; j++) { + if (func[j].subdev & submask) { + present |= func[j].engine; + break; + } + } + + if (!func[j].subdev) + continue; + + if (runlist < 0 && (*engmask & present)) + runlist = fifo->engine[i].runl; + if (runlist == fifo->engine[i].runl) { + engines |= func[j].engine; + subdevs |= func[j].subdev; + } + } } - /* if this is an engine mask query, we're done */ - if (!args->v0.engine) { - args->v0.engine = engines; + /* Just an engine mask query? All done here! */ + if (!*engmask) { + *engmask = present; return nvkm_object_new(oclass, NULL, 0, pobject); } - /* check that we support a requested engine - note that the user - * argument is a mask in order to allow the user to request (for - * example) *any* copy engine, but doesn't matter which. - */ - args->v0.engine &= engines; - if (!args->v0.engine) { - nvif_ioctl(parent, "no supported engine\n"); + /* No runlist? No supported engines. */ + *engmask = present; + if (runlist < 0) return -ENODEV; - } + *engmask = engines; - /* allocate the channel */ + /* Allocate the channel. */ if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) return -ENOMEM; *pobject = &chan->base.object; chan->fifo = fifo; - chan->engine = __ffs(args->v0.engine); + chan->runl = runlist; INIT_LIST_HEAD(&chan->head); ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base, - 0x1000, 0x1000, true, args->v0.vm, 0, - gk104_fifo_engine_subdev(chan->engine), + 0x1000, 0x1000, true, vm, 0, subdevs, 1, fifo->user.bar.offset, 0x200, oclass, &chan->base); if (ret) return ret; - args->v0.chid = chan->base.chid; + *chid = chan->base.chid; - /* page directory */ + /* Page directory. */ ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); if (ret) return ret; @@ -283,10 +306,9 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, if (ret) return ret; - /* clear channel control registers */ + /* Clear channel control registers. */ usermem = chan->base.chid * 0x200; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); + ilength = order_base_2(ilength / 8); nvkm_kmap(fifo->user.mem); for (i = 0; i < 0x200; i += 4) @@ -315,6 +337,56 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, return 0; } +static const struct gk104_fifo_chan_func +gk104_fifo_gpfifo[] = { + { NVA06F_V0_ENGINE_SW | NVA06F_V0_ENGINE_GR, + BIT_ULL(NVKM_ENGINE_SW) | BIT_ULL(NVKM_ENGINE_GR) + }, + { NVA06F_V0_ENGINE_SEC , BIT_ULL(NVKM_ENGINE_SEC ) }, + { NVA06F_V0_ENGINE_MSVLD , BIT_ULL(NVKM_ENGINE_MSVLD ) }, + { NVA06F_V0_ENGINE_MSPDEC, BIT_ULL(NVKM_ENGINE_MSPDEC) }, + { NVA06F_V0_ENGINE_MSPPP , BIT_ULL(NVKM_ENGINE_MSPPP ) }, + { NVA06F_V0_ENGINE_MSENC , BIT_ULL(NVKM_ENGINE_MSENC ) }, + { NVA06F_V0_ENGINE_VIC , BIT_ULL(NVKM_ENGINE_VIC ) }, + { NVA06F_V0_ENGINE_NVDEC , BIT_ULL(NVKM_ENGINE_NVDEC ) }, + { NVA06F_V0_ENGINE_NVENC0, BIT_ULL(NVKM_ENGINE_NVENC0) }, + { NVA06F_V0_ENGINE_NVENC1, BIT_ULL(NVKM_ENGINE_NVENC1) }, + { NVA06F_V0_ENGINE_CE0 , BIT_ULL(NVKM_ENGINE_CE0 ) }, + { NVA06F_V0_ENGINE_CE1 , BIT_ULL(NVKM_ENGINE_CE1 ) }, + { NVA06F_V0_ENGINE_CE2 , BIT_ULL(NVKM_ENGINE_CE2 ) }, + {} +}; + +int +gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct kepler_channel_gpfifo_a_v0 v0; + } *args = data; + struct gk104_fifo *fifo = gk104_fifo(base); + int ret = -ENOSYS; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength, args->v0.engines); + return gk104_fifo_gpfifo_new_(gk104_fifo_gpfifo, fifo, + &args->v0.engines, + &args->v0.chid, + args->v0.vm, + args->v0.ioffset, + args->v0.ilength, + oclass, pobject); + + } + + return ret; +} + const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass = { .base.oclass = KEPLER_CHANNEL_GPFIFO_A, -- cgit v1.2.3-54-g00ecf