diff options
Diffstat (limited to 'fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch')
-rw-r--r-- | fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch b/fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch new file mode 100644 index 000000000..480ff9344 --- /dev/null +++ b/fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch @@ -0,0 +1,135 @@ +From: Ben Skeggs <bskeggs@redhat.com> +Date: Tue, 27 Jan 2015 15:09:39 +1000 +Subject: [PATCH] fifo/nv04: remove the loop from the interrupt handler + +Complete bong hit (and not the last...), the hardware will reassert the +interrupt to PMC if it's necessary. + +Also potentially harmful in the face of interrupts such as the non-stall +interrupt, which remain active in NV_PFIFO_INTR even when we don't care +about servicing it. + +It appears (hopefully, fdo#87244), that under certain loads, the methods +may pass quickly enough to hit the "100 spins and kill PFIFO" thing that +we had going on. Not ideal ;) + +Signed-off-by: Ben Skeggs <bskeggs@redhat.com> +--- + drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 85 ++++++++++--------------- + 1 file changed, 35 insertions(+), 50 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +index b038b6eb51db..043e4296084c 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c ++++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +@@ -502,72 +502,57 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) + { + struct nvkm_device *device = nv_device(subdev); + struct nv04_fifo_priv *priv = (void *)subdev; +- uint32_t status, reassign; +- int cnt = 0; ++ u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0); ++ u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask; ++ u32 reassign, chid, get, sem; + + reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1; +- while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { +- uint32_t chid, get; +- +- nv_wr32(priv, NV03_PFIFO_CACHES, 0); +- +- chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; +- get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); ++ nv_wr32(priv, NV03_PFIFO_CACHES, 0); + +- if (status & NV_PFIFO_INTR_CACHE_ERROR) { +- nv04_fifo_cache_error(device, priv, chid, get); +- status &= ~NV_PFIFO_INTR_CACHE_ERROR; +- } ++ chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; ++ get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); + +- if (status & NV_PFIFO_INTR_DMA_PUSHER) { +- nv04_fifo_dma_pusher(device, priv, chid); +- status &= ~NV_PFIFO_INTR_DMA_PUSHER; +- } ++ if (stat & NV_PFIFO_INTR_CACHE_ERROR) { ++ nv04_fifo_cache_error(device, priv, chid, get); ++ stat &= ~NV_PFIFO_INTR_CACHE_ERROR; ++ } + +- if (status & NV_PFIFO_INTR_SEMAPHORE) { +- uint32_t sem; ++ if (stat & NV_PFIFO_INTR_DMA_PUSHER) { ++ nv04_fifo_dma_pusher(device, priv, chid); ++ stat &= ~NV_PFIFO_INTR_DMA_PUSHER; ++ } + +- status &= ~NV_PFIFO_INTR_SEMAPHORE; +- nv_wr32(priv, NV03_PFIFO_INTR_0, +- NV_PFIFO_INTR_SEMAPHORE); ++ if (stat & NV_PFIFO_INTR_SEMAPHORE) { ++ stat &= ~NV_PFIFO_INTR_SEMAPHORE; ++ nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); + +- sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); +- nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); ++ sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); ++ nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + +- nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); +- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); +- } ++ nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); ++ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); ++ } + +- if (device->card_type == NV_50) { +- if (status & 0x00000010) { +- status &= ~0x00000010; +- nv_wr32(priv, 0x002100, 0x00000010); +- } +- +- if (status & 0x40000000) { +- nv_wr32(priv, 0x002100, 0x40000000); +- nvkm_fifo_uevent(&priv->base); +- status &= ~0x40000000; +- } ++ if (device->card_type == NV_50) { ++ if (stat & 0x00000010) { ++ stat &= ~0x00000010; ++ nv_wr32(priv, 0x002100, 0x00000010); + } + +- if (status) { +- nv_warn(priv, "unknown intr 0x%08x, ch %d\n", +- status, chid); +- nv_wr32(priv, NV03_PFIFO_INTR_0, status); +- status = 0; ++ if (stat & 0x40000000) { ++ nv_wr32(priv, 0x002100, 0x40000000); ++ nvkm_fifo_uevent(&priv->base); ++ stat &= ~0x40000000; + } +- +- nv_wr32(priv, NV03_PFIFO_CACHES, reassign); + } + +- if (status) { +- nv_error(priv, "still angry after %d spins, halt\n", cnt); +- nv_wr32(priv, 0x002140, 0); +- nv_wr32(priv, 0x000140, 0); ++ if (stat) { ++ nv_warn(priv, "unknown intr 0x%08x\n", stat); ++ nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); ++ nv_wr32(priv, NV03_PFIFO_INTR_0, stat); + } + +- nv_wr32(priv, 0x000100, 0x00000100); ++ nv_wr32(priv, NV03_PFIFO_CACHES, reassign); + } + + static int +-- +2.1.0 + |