drm/nouveau/fifo/gk104-: reset all engines a killed channel is still active on
authorBen Skeggs <bskeggs@redhat.com>
Wed, 18 Jan 2017 05:35:16 +0000 (15:35 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 17 Feb 2017 07:38:13 +0000 (17:38 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c

index c45f732366b4e11cf9ae75f62b8767caa5c2d28e..4f174470c02b13b51b3cf054f1010987af4b0c29 100644 (file)
@@ -243,6 +243,7 @@ gk104_fifo_recover_chan(struct nvkm_fifo *base, int chid)
        const u32  stat = nvkm_rd32(device, 0x800004 + (chid * 0x08));
        const u32  runl = (stat & 0x000f0000) >> 16;
        const bool used = (stat & 0x00000001);
+       unsigned long engn, engm = fifo->runlist[runl].engm;
        struct gk104_fifo_chan *chan;
 
        assert_spin_locked(&fifo->base.lock);
@@ -262,6 +263,18 @@ gk104_fifo_recover_chan(struct nvkm_fifo *base, int chid)
        /* Disable channel. */
        nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800);
        nvkm_warn(subdev, "channel %d: killed\n", chid);
+
+       /* Block channel assignments from changing during recovery. */
+       gk104_fifo_recover_runl(fifo, runl);
+
+       /* Schedule recovery for any engines the channel is on. */
+       for_each_set_bit(engn, &engm, fifo->engine_nr) {
+               struct gk104_fifo_engine_status status;
+               gk104_fifo_engine_status(fifo, engn, &status);
+               if (!status.chan || status.chan->id != chid)
+                       continue;
+               gk104_fifo_recover_engn(fifo, engn);
+       }
 }
 
 static void