drm/nouveau/fifo/nvc0-: use interrupt 31 as an event trigger
authorBen Skeggs <bskeggs@redhat.com>
Thu, 31 Jan 2013 03:51:20 +0000 (13:51 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 20 Feb 2013 06:00:46 +0000 (16:00 +1000)
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>
drivers/gpu/drm/nouveau/core/engine/fifo/base.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/include/engine/fifo.h

index ca1057a6613c462e423fc84e4bb7269ac4e5ef80..7341ebe131fabc9de63a5ae37849a7f180f3b3e7 100644 (file)
@@ -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;
index 2a9919bbf77c4a27a95d7a8eb8a688b67e171330..bf86f40b8a832e0b1ff20ffcaf594f890f954aa0 100644 (file)
@@ -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;
 }
 
index 410c6e2c9f0e8590a711fb516cbfc4735bd3b50d..4419e40d88e97ec5779dd01fc7cbc193e73714cf 100644 (file)
@@ -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;
 }
 
index 543e4ef80f6bf197d16bc7ef1b84c71bcb6cba5a..b46c197709f394c4224d57b7bcde433bb8e71c2d 100644 (file)
@@ -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;