| From b27add13f500469127afdf011dbcc9c649e16e54 Mon Sep 17 00:00:00 2001 |
| From: Ben Skeggs <bskeggs@redhat.com> |
| Date: Sat, 5 Nov 2016 14:33:14 +1000 |
| Subject: drm/nouveau/fifo/gf100-: protect channel preempt with subdev mutex |
| |
| From: Ben Skeggs <bskeggs@redhat.com> |
| |
| commit b27add13f500469127afdf011dbcc9c649e16e54 upstream. |
| |
| 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: Ben Skeggs <bskeggs@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c | 9 ++++++--- |
| drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c | 8 +++++--- |
| 2 files changed, 11 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c |
| +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c |
| @@ -60,6 +60,7 @@ gf100_fifo_gpfifo_engine_fini(struct nvk |
| struct nvkm_gpuobj *inst = chan->base.inst; |
| int ret = 0; |
| |
| + mutex_lock(&subdev->mutex); |
| nvkm_wr32(device, 0x002634, chan->base.chid); |
| if (nvkm_msec(device, 2000, |
| if (nvkm_rd32(device, 0x002634) == chan->base.chid) |
| @@ -67,10 +68,12 @@ gf100_fifo_gpfifo_engine_fini(struct nvk |
| ) < 0) { |
| nvkm_error(subdev, "channel %d [%s] kick timeout\n", |
| chan->base.chid, chan->base.object.client->name); |
| - ret = -EBUSY; |
| - if (suspend) |
| - return ret; |
| + ret = -ETIMEDOUT; |
| } |
| + mutex_unlock(&subdev->mutex); |
| + |
| + if (ret && suspend) |
| + return ret; |
| |
| if (offset) { |
| nvkm_kmap(inst); |
| --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c |
| +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c |
| @@ -40,7 +40,9 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo |
| struct nvkm_subdev *subdev = &fifo->base.engine.subdev; |
| struct nvkm_device *device = subdev->device; |
| struct nvkm_client *client = chan->base.object.client; |
| + int ret = 0; |
| |
| + mutex_lock(&subdev->mutex); |
| nvkm_wr32(device, 0x002634, chan->base.chid); |
| if (nvkm_msec(device, 2000, |
| if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) |
| @@ -48,10 +50,10 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo |
| ) < 0) { |
| nvkm_error(subdev, "channel %d [%s] kick timeout\n", |
| chan->base.chid, client->name); |
| - return -EBUSY; |
| + ret = -ETIMEDOUT; |
| } |
| - |
| - return 0; |
| + mutex_unlock(&subdev->mutex); |
| + return ret; |
| } |
| |
| static u32 |