Commit b27add13 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/fifo/gf100-: protect channel preempt with subdev mutex

This avoids an issue that occurs when we're attempting to preempt multiple
channels simultaneously.  HW seems to ignore preempt requests while it's
still processing a previous one, which, well, makes sense.

Fixes random "fifo: SCHED_ERROR 0d []" + GPCCS page faults during parallel
piglit runs on (at least) GM107.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Cc: stable@vger.kernel.org
parent e137040e
...@@ -60,6 +60,7 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, ...@@ -60,6 +60,7 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
struct nvkm_gpuobj *inst = chan->base.inst; struct nvkm_gpuobj *inst = chan->base.inst;
int ret = 0; int ret = 0;
mutex_lock(&subdev->mutex);
nvkm_wr32(device, 0x002634, chan->base.chid); nvkm_wr32(device, 0x002634, chan->base.chid);
if (nvkm_msec(device, 2000, if (nvkm_msec(device, 2000,
if (nvkm_rd32(device, 0x002634) == chan->base.chid) if (nvkm_rd32(device, 0x002634) == chan->base.chid)
...@@ -67,10 +68,12 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, ...@@ -67,10 +68,12 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
) < 0) { ) < 0) {
nvkm_error(subdev, "channel %d [%s] kick timeout\n", nvkm_error(subdev, "channel %d [%s] kick timeout\n",
chan->base.chid, chan->base.object.client->name); chan->base.chid, chan->base.object.client->name);
ret = -EBUSY; ret = -ETIMEDOUT;
if (suspend)
return ret;
} }
mutex_unlock(&subdev->mutex);
if (ret && suspend)
return ret;
if (offset) { if (offset) {
nvkm_kmap(inst); nvkm_kmap(inst);
......
...@@ -40,7 +40,9 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) ...@@ -40,7 +40,9 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan)
struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
struct nvkm_device *device = subdev->device; struct nvkm_device *device = subdev->device;
struct nvkm_client *client = chan->base.object.client; struct nvkm_client *client = chan->base.object.client;
int ret = 0;
mutex_lock(&subdev->mutex);
nvkm_wr32(device, 0x002634, chan->base.chid); nvkm_wr32(device, 0x002634, chan->base.chid);
if (nvkm_msec(device, 2000, if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
...@@ -48,10 +50,10 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) ...@@ -48,10 +50,10 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan)
) < 0) { ) < 0) {
nvkm_error(subdev, "channel %d [%s] kick timeout\n", nvkm_error(subdev, "channel %d [%s] kick timeout\n",
chan->base.chid, client->name); chan->base.chid, client->name);
return -EBUSY; ret = -ETIMEDOUT;
} }
mutex_unlock(&subdev->mutex);
return 0; return ret;
} }
static u32 static u32
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment