summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2015-11-11 09:37:05 +1000
committerBen Skeggs <bskeggs@redhat.com>2015-11-11 10:20:48 +1000
commit02f877ab165e7249ff3162bf99f764dc798628c2 (patch)
tree139c516e2858e77aa644abb2947dd364068443f5
parent2f3a56ad019e378a352e9cb7a559f478826f1a87 (diff)
downloadnouveau-02f877ab165e7249ff3162bf99f764dc798628c2.tar.gz
fifo/gk104: fix race condition when updating engine runlists
The CPU-side tracking of engine runlists was not protected by a lock, leading to list corruption, eventually causing runlist_update() to overrun the GPU-side runlist, triggering an OOPS. Fixes some of the issues noticed during parallel piglit runs. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drm/nouveau/nvkm/engine/fifo/gk104.c20
-rw-r--r--drm/nouveau/nvkm/engine/fifo/gk104.h5
-rw-r--r--drm/nouveau/nvkm/engine/fifo/gpfifogk104.c8
3 files changed, 26 insertions, 7 deletions
diff --git a/drm/nouveau/nvkm/engine/fifo/gk104.c b/drm/nouveau/nvkm/engine/fifo/gk104.c
index 98970a0b7..8d5db6d5a 100644
--- a/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -47,7 +47,7 @@ gk104_fifo_uevent_init(struct nvkm_fifo *fifo)
}
void
-gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine)
+gk104_fifo_runlist_commit(struct gk104_fifo *fifo, u32 engine)
{
struct gk104_fifo_engn *engn = &fifo->engine[engine];
struct gk104_fifo_chan *chan;
@@ -78,6 +78,22 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine)
mutex_unlock(&subdev->mutex);
}
+void
+gk104_fifo_runlist_remove(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_del_init(&chan->head);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
+void
+gk104_fifo_runlist_insert(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan)
+{
+ mutex_lock(&fifo->base.engine.subdev.mutex);
+ list_add_tail(&chan->head, &fifo->engine[chan->engine].chan);
+ mutex_unlock(&fifo->base.engine.subdev.mutex);
+}
+
static inline struct nvkm_engine *
gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn)
{
@@ -112,7 +128,7 @@ gk104_fifo_recover_work(struct work_struct *work)
nvkm_subdev_fini(&engine->subdev, false);
WARN_ON(nvkm_subdev_init(&engine->subdev));
}
- gk104_fifo_runlist_update(fifo, gk104_fifo_subdev_engine(engn));
+ gk104_fifo_runlist_commit(fifo, gk104_fifo_subdev_engine(engn));
}
nvkm_wr32(device, 0x00262c, engm);
diff --git a/drm/nouveau/nvkm/engine/fifo/gk104.h b/drm/nouveau/nvkm/engine/fifo/gk104.h
index 5afd9b5ec..bec519d8f 100644
--- a/drm/nouveau/nvkm/engine/fifo/gk104.h
+++ b/drm/nouveau/nvkm/engine/fifo/gk104.h
@@ -5,6 +5,7 @@
#include <subdev/mmu.h>
+struct gk104_fifo_chan;
struct gk104_fifo_engn {
struct nvkm_memory *runlist[2];
int cur_runlist;
@@ -35,7 +36,9 @@ void gk104_fifo_fini(struct nvkm_fifo *);
void gk104_fifo_intr(struct nvkm_fifo *);
void gk104_fifo_uevent_init(struct nvkm_fifo *);
void gk104_fifo_uevent_fini(struct nvkm_fifo *);
-void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine);
+void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *);
+void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *);
+void gk104_fifo_runlist_commit(struct gk104_fifo *, u32 engine);
static inline u64
gk104_fifo_engine_subdev(int engine)
diff --git a/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
index 0b817540a..500e7d2f2 100644
--- a/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
+++ b/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
@@ -151,9 +151,9 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
u32 coff = chan->base.chid * 8;
if (!list_empty(&chan->head)) {
- list_del_init(&chan->head);
+ gk104_fifo_runlist_remove(fifo, chan);
nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800);
- gk104_fifo_runlist_update(fifo, chan->engine);
+ gk104_fifo_runlist_commit(fifo, chan->engine);
}
nvkm_wr32(device, 0x800000 + coff, 0x00000000);
@@ -172,9 +172,9 @@ gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr);
if (list_empty(&chan->head) && !chan->killed) {
- list_add_tail(&chan->head, &fifo->engine[chan->engine].chan);
+ gk104_fifo_runlist_insert(fifo, chan);
nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
- gk104_fifo_runlist_update(fifo, chan->engine);
+ gk104_fifo_runlist_commit(fifo, chan->engine);
nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
}
}