drm/nouveau/fifo/gf100: fix race condition when updating engine runlists

Similar in spirit to the gk104 fix with a similar title.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs 2015-11-11 10:07:22 +10:00
Родитель 386ffd5e80
Коммит d40d0fd487
3 изменённых файлов: 26 добавлений и 7 удалений

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}
}