drm/nouveau/fifo/gk104: read device topology information from hw
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:41 +0000 (10:13 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c

index 47bf23e9a8cca9d1d82f06af812ca5a2d0a172bc..26889fe65f73cdac0c557a4e1b6822b286e7e7e5 100644 (file)
@@ -202,7 +202,7 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo)
        u32 engn;
 
        spin_lock_irqsave(&fifo->base.lock, flags);
-       for (engn = 0; engn < ARRAY_SIZE(fifo->runlist); engn++) {
+       for (engn = 0; engn < fifo->engine_nr; engn++) {
                u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x08));
                u32 busy = (stat & 0x80000000);
                u32 next = (stat & 0x0fff0000) >> 16;
@@ -666,13 +666,102 @@ gk104_fifo_oneinit(struct nvkm_fifo *base)
        struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
        struct nvkm_device *device = subdev->device;
        int ret, i;
+       u32 *map;
 
        /* Determine number of PBDMAs by checking valid enable bits. */
        nvkm_wr32(device, 0x000204, 0xffffffff);
        fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x000204));
        nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr);
 
-       for (i = 0; i < ARRAY_SIZE(fifo->runlist); i++) {
+       /* Read PBDMA->runlist(s) mapping from HW. */
+       if (!(map = kzalloc(sizeof(*map) * fifo->pbdma_nr, GFP_KERNEL)))
+               return -ENOMEM;
+
+       for (i = 0; i < fifo->pbdma_nr; i++)
+               map[i] = nvkm_rd32(device, 0x002390 + (i * 0x04));
+
+       /* Read device topology from HW. */
+       for (i = 0; i < 64; i++) {
+               int type = -1, pbid = -1, engidx = -1;
+               int engn = -1, runl = -1, intr = -1, mcen = -1;
+               int fault = -1, j;
+               u32 data, addr = 0;
+
+               do {
+                       data = nvkm_rd32(device, 0x022700 + (i * 0x04));
+                       nvkm_trace(subdev, "%02x: %08x\n", i, data);
+                       switch (data & 0x00000003) {
+                       case 0x00000000: /* NOT_VALID */
+                               continue;
+                       case 0x00000001: /* DATA */
+                               addr  = (data & 0x00fff000);
+                               fault = (data & 0x000000f8) >> 3;
+                               break;
+                       case 0x00000002: /* ENUM */
+                               if (data & 0x00000020)
+                                       engn = (data & 0x3c000000) >> 26;
+                               if (data & 0x00000010)
+                                       runl = (data & 0x01e00000) >> 21;
+                               if (data & 0x00000008)
+                                       intr = (data & 0x000f8000) >> 15;
+                               if (data & 0x00000004)
+                                       mcen = (data & 0x00003e00) >> 9;
+                               break;
+                       case 0x00000003: /* ENGINE_TYPE */
+                               type = (data & 0x7ffffffc) >> 2;
+                               break;
+                       }
+               } while ((data & 0x80000000) && ++i < 64);
+
+               if (!data)
+                       continue;
+
+               /* Determine which PBDMA handles requests for this engine. */
+               for (j = 0; runl >= 0 && j < fifo->pbdma_nr; j++) {
+                       if (map[j] & (1 << runl)) {
+                               pbid = j;
+                               break;
+                       }
+               }
+
+               /* Translate engine type to NVKM engine identifier. */
+               switch (type) {
+               case 0x00000000: engidx = NVKM_ENGINE_GR; break;
+               case 0x00000001: engidx = NVKM_ENGINE_CE0; break;
+               case 0x00000002: engidx = NVKM_ENGINE_CE1; break;
+               case 0x00000003: engidx = NVKM_ENGINE_CE2; break;
+               case 0x00000008: engidx = NVKM_ENGINE_MSPDEC; break;
+               case 0x00000009: engidx = NVKM_ENGINE_MSPPP; break;
+               case 0x0000000a: engidx = NVKM_ENGINE_MSVLD; break;
+               case 0x0000000b: engidx = NVKM_ENGINE_MSENC; break;
+               case 0x0000000c: engidx = NVKM_ENGINE_VIC; break;
+               case 0x0000000d: engidx = NVKM_ENGINE_SEC; break;
+                       break;
+               default:
+                       break;
+               }
+
+               nvkm_debug(subdev, "%02x (%8s): engine %2d runlist %2d "
+                                  "pbdma %2d intr %2d reset %2d "
+                                  "fault %2d addr %06x\n", type,
+                          engidx < 0 ? NULL : nvkm_subdev_name[engidx],
+                          engn, runl, pbid, intr, mcen, fault, addr);
+
+               /* Mark the engine as supported if everything checks out. */
+               if (engn >= 0 && runl >= 0) {
+                       fifo->engine[engn].engine = engidx < 0 ? NULL :
+                               nvkm_device_engine(device, engidx);
+                       fifo->engine[engn].runl = runl;
+                       fifo->engine[engn].pbid = pbid;
+                       fifo->engine_nr = max(fifo->engine_nr, engn + 1);
+                       fifo->runlist[runl].engm |= 1 << engn;
+                       fifo->runlist_nr = max(fifo->runlist_nr, runl + 1);
+               }
+       }
+
+       kfree(map);
+
+       for (i = 0; i < fifo->runlist_nr; i++) {
                ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
                                      0x8000, 0x1000, false,
                                      &fifo->runlist[i].mem[0]);
@@ -742,7 +831,7 @@ gk104_fifo_dtor(struct nvkm_fifo *base)
        nvkm_vm_put(&fifo->user.bar);
        nvkm_memory_del(&fifo->user.mem);
 
-       for (i = 0; i < ARRAY_SIZE(fifo->runlist); i++) {
+       for (i = 0; i < fifo->runlist_nr; i++) {
                nvkm_memory_del(&fifo->runlist[i].mem[1]);
                nvkm_memory_del(&fifo->runlist[i].mem[0]);
        }
index 809b19927d62ba72f88b8b8317ec23c3b1c4c067..cfd0f8ef95511047c07f3e59568e6724da0bf215 100644 (file)
@@ -16,12 +16,21 @@ struct gk104_fifo {
 
        int pbdma_nr;
 
+       struct {
+               struct nvkm_engine *engine;
+               int runl;
+               int pbid;
+       } engine[16];
+       int engine_nr;
+
        struct {
                struct nvkm_memory *mem[2];
                int next;
                wait_queue_head_t wait;
                struct list_head chan;
-       } runlist[7];
+               u32 engm;
+       } runlist[16];
+       int runlist_nr;
 
        struct {
                struct nvkm_memory *mem;
index c8093417c64bbf140e6ab1fa4e957bb447ba4a92..dcc1445bce1a091f688f4aeb953911cdeee36af5 100644 (file)
@@ -227,7 +227,7 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
                return ret;
 
        /* determine which downstream engines are present */
-       for (i = 0, engines = 0; i < ARRAY_SIZE(fifo->runlist); i++) {
+       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;