drm/nouveau/fifo/gf100: fix race condition when updating engine runlists
authorBen Skeggs <bskeggs@redhat.com>
Wed, 11 Nov 2015 00:07:22 +0000 (10:07 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 11 Jan 2016 01:17:40 +0000 (11:17 +1000)
Similar in spirit to the gk104 fix with a similar title.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c

index ff6fcbda615b07be29f8b6d7fd14e57332bc6228..6f276dab4a25d0739cd1a792a5763f7e010356b8 100644 (file)
@@ -47,7 +47,7 @@ gf100_fifo_uevent_fini(struct nvkm_fifo *fifo)
 }
 
 void
-gf100_fifo_runlist_update(struct gf100_fifo *fifo)
+gf100_fifo_runlist_commit(struct gf100_fifo *fifo)
 {
        struct gf100_fifo_chan *chan;
        struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
@@ -77,6 +77,22 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo)
        mutex_unlock(&subdev->mutex);
 }
 
+void
+gf100_fifo_runlist_remove(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+{
+       mutex_lock(&fifo->base.engine.subdev.mutex);
+       list_del_init(&chan->head);
+       mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
+void
+gf100_fifo_runlist_insert(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
+{
+       mutex_lock(&fifo->base.engine.subdev.mutex);
+       list_add_tail(&chan->head, &fifo->chan);
+       mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
 static inline int
 gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn)
 {
@@ -139,7 +155,7 @@ gf100_fifo_recover_work(struct work_struct *work)
                }
        }
 
-       gf100_fifo_runlist_update(fifo);
+       gf100_fifo_runlist_commit(fifo);
        nvkm_wr32(device, 0x00262c, engm);
        nvkm_mask(device, 0x002630, engm, 0x00000000);
 }
index c649ca9b53e3ee2206ad865351a4073a636af00a..08c33c3ceaf73781f9518b1ce92c6db4df1c22a5 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <subdev/mmu.h>
 
+struct gf100_fifo_chan;
 struct gf100_fifo {
        struct nvkm_fifo base;
 
@@ -27,5 +28,7 @@ struct gf100_fifo {
 };
 
 void gf100_fifo_intr_engine(struct gf100_fifo *);
-void gf100_fifo_runlist_update(struct gf100_fifo *);
+void gf100_fifo_runlist_insert(struct gf100_fifo *, struct gf100_fifo_chan *);
+void gf100_fifo_runlist_remove(struct gf100_fifo *, struct gf100_fifo_chan *);
+void gf100_fifo_runlist_commit(struct gf100_fifo *);
 #endif
index e7cbc139c1d4fb831bdf7a1a47f649c45ce121a0..3f3767518558b1b2e93b8251d226925870bb6cc6 100644 (file)
@@ -138,9 +138,9 @@ gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
        u32 coff = chan->base.chid * 8;
 
        if (!list_empty(&chan->head) && !chan->killed) {
-               list_del_init(&chan->head);
+               gf100_fifo_runlist_remove(fifo, chan);
                nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000);
-               gf100_fifo_runlist_update(fifo);
+               gf100_fifo_runlist_commit(fifo);
        }
 
        gf100_fifo_intr_engine(fifo);
@@ -160,9 +160,9 @@ gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
        nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr);
 
        if (list_empty(&chan->head) && !chan->killed) {
-               list_add_tail(&chan->head, &fifo->chan);
+               gf100_fifo_runlist_insert(fifo, chan);
                nvkm_wr32(device, 0x003004 + coff, 0x001f0001);
-               gf100_fifo_runlist_update(fifo);
+               gf100_fifo_runlist_commit(fifo);
        }
 }