drm/nouveau/fifo/gk104: make use of topology info during gpfifo construction
authorBen Skeggs <bskeggs@redhat.com>
Fri, 11 Mar 2016 03:09:28 +0000 (13:09 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 14 Mar 2016 00:13:42 +0000 (10:13 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvif/cla06f.h
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c

index 85b7827..6febc82 100644 (file)
@@ -3,19 +3,22 @@
 
 struct kepler_channel_gpfifo_a_v0 {
        __u8  version;
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR                               0x01
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC                           0x02
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP                            0x04
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD                            0x08
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0                              0x10
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1                              0x20
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC                              0x40
-       __u8  engine;
+       __u8  pad01[5];
        __u16 chid;
+#define NVA06F_V0_ENGINE_SW                                          0x00000001
+#define NVA06F_V0_ENGINE_GR                                          0x00000002
+#define NVA06F_V0_ENGINE_MSVLD                                       0x00000010
+#define NVA06F_V0_ENGINE_MSPDEC                                      0x00000020
+#define NVA06F_V0_ENGINE_MSPPP                                       0x00000040
+#define NVA06F_V0_ENGINE_MSENC                                       0x00000080
+#define NVA06F_V0_ENGINE_CE0                                         0x00010000
+#define NVA06F_V0_ENGINE_CE1                                         0x00020000
+#define NVA06F_V0_ENGINE_CE2                                         0x00040000
+       __u32 engines;
        __u32 ilength;
        __u64 ioffset;
        __u64 vm;
 };
 
-#define KEPLER_CHANNEL_GPFIFO_A_V0_NTFY_UEVENT                             0x00
+#define NVA06F_V0_NTFY_UEVENT                                              0x00
 #endif
index 50f52ff..a59e524 100644 (file)
@@ -263,13 +263,23 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
        /* hack to allow channel engine type specification on kepler */
        if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
                if (init->fb_ctxdma_handle != ~0)
-                       init->fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR;
-               else
-                       init->fb_ctxdma_handle = init->tt_ctxdma_handle;
+                       init->fb_ctxdma_handle = NVA06F_V0_ENGINE_GR;
+               else {
+                       init->fb_ctxdma_handle = 0;
+#define _(A,B) if (init->tt_ctxdma_handle & (A)) init->fb_ctxdma_handle |= (B)
+                       _(0x01, NVA06F_V0_ENGINE_GR);
+                       _(0x02, NVA06F_V0_ENGINE_MSPDEC);
+                       _(0x04, NVA06F_V0_ENGINE_MSPPP);
+                       _(0x08, NVA06F_V0_ENGINE_MSVLD);
+                       _(0x10, NVA06F_V0_ENGINE_CE0);
+                       _(0x20, NVA06F_V0_ENGINE_CE1);
+                       _(0x40, NVA06F_V0_ENGINE_MSENC);
+#undef _
+               }
 
                /* allow flips to be executed if this is a graphics channel */
                init->tt_ctxdma_handle = 0;
-               if (init->fb_ctxdma_handle == KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR)
+               if (init->fb_ctxdma_handle == NVA06F_V0_ENGINE_GR)
                        init->tt_ctxdma_handle = 1;
        }
 
index 3f804a8..9b62311 100644 (file)
@@ -217,7 +217,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
        do {
                if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
                        args.kepler.version = 0;
-                       args.kepler.engine  = engine;
+                       args.kepler.engines = engine;
                        args.kepler.ilength = 0x02000;
                        args.kepler.ioffset = 0x10000 + chan->push.vma.offset;
                        args.kepler.vm = 0;
index 30b5958..fcc83b7 100644 (file)
@@ -215,13 +215,13 @@ nouveau_accel_init(struct nouveau_drm *drm)
 
        if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
                ret = nouveau_channel_new(drm, &drm->device,
-                                         KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0|
-                                         KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1,
+                                         NVA06F_V0_ENGINE_CE0 |
+                                         NVA06F_V0_ENGINE_CE1,
                                          0, &drm->cechan);
                if (ret)
                        NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
 
-               arg0 = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR;
+               arg0 = NVA06F_V0_ENGINE_GR;
                arg1 = 1;
        } else
        if (device->info.chipset >= 0xa3 &&
index dcc1445..1c930dc 100644 (file)
@@ -202,73 +202,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 < fifo->runlist_nr; 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->runl = __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->runl),
+                                 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;
@@ -284,10 +290,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)
@@ -316,6 +321,51 @@ 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_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_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,