From 9bd2ddbaa241274cd11191838d080fc308ecf6c7 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Thu, 31 Jan 2013 13:51:20 +1000
Subject: [PATCH] drm/nouveau/fifo/nvc0-: use interrupt 31 as an event trigger

Generated if you try and use fifo method 0x20 on any subchannel, appears
that it can be safely masked off without stalling the whole GPU.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
---
 .../gpu/drm/nouveau/core/engine/fifo/base.c   |  6 +++++
 .../gpu/drm/nouveau/core/engine/fifo/nvc0.c   | 24 +++++++++++++++--
 .../gpu/drm/nouveau/core/engine/fifo/nve0.c   | 27 ++++++++++++++++++-
 .../drm/nouveau/core/include/engine/fifo.h    |  2 ++
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
index ca1057a6613c4..7341ebe131fab 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
@@ -25,6 +25,7 @@
 #include <core/client.h>
 #include <core/object.h>
 #include <core/handle.h>
+#include <core/event.h>
 #include <core/class.h>
 
 #include <engine/dmaobj.h>
@@ -165,6 +166,7 @@ void
 nouveau_fifo_destroy(struct nouveau_fifo *priv)
 {
 	kfree(priv->channel);
+	nouveau_event_destroy(&priv->uevent);
 	nouveau_engine_destroy(&priv->base);
 }
 
@@ -189,6 +191,10 @@ nouveau_fifo_create_(struct nouveau_object *parent,
 	if (!priv->channel)
 		return -ENOMEM;
 
+	ret = nouveau_event_create(1, &priv->uevent);
+	if (ret)
+		return ret;
+
 	priv->chid = nouveau_fifo_chid;
 	spin_lock_init(&priv->lock);
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index 2a9919bbf77c4..bf86f40b8a832 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -27,6 +27,7 @@
 #include <core/namedb.h>
 #include <core/gpuobj.h>
 #include <core/engctx.h>
+#include <core/event.h>
 #include <core/class.h>
 #include <core/math.h>
 #include <core/enum.h>
@@ -583,7 +584,8 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
 
 	if (stat & 0x80000000) {
 		u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000);
-		nv_warn(priv, "INTR 0x80000000: 0x%08x\n", intr);
+		nouveau_event_trigger(priv->base.uevent, 0);
+		nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr);
 		stat &= ~0x80000000;
 	}
 
@@ -594,6 +596,20 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
 	}
 }
 
+static void
+nvc0_fifo_uevent_enable(struct nouveau_event *event, int index)
+{
+	struct nvc0_fifo_priv *priv = event->priv;
+	nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+nvc0_fifo_uevent_disable(struct nouveau_event *event, int index)
+{
+	struct nvc0_fifo_priv *priv = event->priv;
+	nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
+}
+
 static int
 nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	       struct nouveau_oclass *oclass, void *data, u32 size,
@@ -627,6 +643,10 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	if (ret)
 		return ret;
 
+	priv->base.uevent->enable = nvc0_fifo_uevent_enable;
+	priv->base.uevent->disable = nvc0_fifo_uevent_disable;
+	priv->base.uevent->priv = priv;
+
 	nv_subdev(priv)->unit = 0x00000100;
 	nv_subdev(priv)->intr = nvc0_fifo_intr;
 	nv_engine(priv)->cclass = &nvc0_fifo_cclass;
@@ -685,7 +705,7 @@ nvc0_fifo_init(struct nouveau_object *object)
 
 	nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
 	nv_wr32(priv, 0x002100, 0xffffffff);
-	nv_wr32(priv, 0x002140, 0xbfffffff);
+	nv_wr32(priv, 0x002140, 0x3fffffff);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 410c6e2c9f0e8..4419e40d88e97 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -27,6 +27,7 @@
 #include <core/namedb.h>
 #include <core/gpuobj.h>
 #include <core/engctx.h>
+#include <core/event.h>
 #include <core/class.h>
 #include <core/math.h>
 #include <core/enum.h>
@@ -554,6 +555,12 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
 		stat &= ~0x40000000;
 	}
 
+	if (stat & 0x80000000) {
+		nouveau_event_trigger(priv->base.uevent, 0);
+		nv_wr32(priv, 0x002100, 0x80000000);
+		stat &= ~0x80000000;
+	}
+
 	if (stat) {
 		nv_fatal(priv, "unhandled status 0x%08x\n", stat);
 		nv_wr32(priv, 0x002100, stat);
@@ -561,6 +568,20 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
 	}
 }
 
+static void
+nve0_fifo_uevent_enable(struct nouveau_event *event, int index)
+{
+	struct nve0_fifo_priv *priv = event->priv;
+	nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+nve0_fifo_uevent_disable(struct nouveau_event *event, int index)
+{
+	struct nve0_fifo_priv *priv = event->priv;
+	nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
+}
+
 static int
 nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	       struct nouveau_oclass *oclass, void *data, u32 size,
@@ -584,6 +605,10 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	if (ret)
 		return ret;
 
+	priv->base.uevent->enable = nve0_fifo_uevent_enable;
+	priv->base.uevent->disable = nve0_fifo_uevent_disable;
+	priv->base.uevent->priv = priv;
+
 	nv_subdev(priv)->unit = 0x00000100;
 	nv_subdev(priv)->intr = nve0_fifo_intr;
 	nv_engine(priv)->cclass = &nve0_fifo_cclass;
@@ -634,7 +659,7 @@ nve0_fifo_init(struct nouveau_object *object)
 
 	nv_wr32(priv, 0x002a00, 0xffffffff);
 	nv_wr32(priv, 0x002100, 0xffffffff);
-	nv_wr32(priv, 0x002140, 0xbfffffff);
+	nv_wr32(priv, 0x002140, 0x3fffffff);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
index 543e4ef80f6bf..b46c197709f39 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
@@ -65,6 +65,8 @@ struct nouveau_fifo_base {
 struct nouveau_fifo {
 	struct nouveau_engine base;
 
+	struct nouveau_event *uevent;
+
 	struct nouveau_object **channel;
 	spinlock_t lock;
 	u16 min;
-- 
GitLab