summaryrefslogtreecommitdiffstats
path: root/fifo-nv04-remove-the-loop-from-the-interrupt-handler.patch
diff options
context:
space:
mode:
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.patch135
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
+