drm/nv40/gr: rewrite/split context takedown functions
authorBen Skeggs <bskeggs@redhat.com>
Sun, 17 Jul 2011 23:56:36 +0000 (09:56 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sun, 24 Jul 2011 23:42:18 +0000 (09:42 +1000)
It's completely pointless to save the PGRAPH context when destroying a
channel, so don't bother.

This commit should also fix kernel.org bug 39422, where the DRM channel
state was incorrectly being saved because we left PGRAPH FIFO access
enabled while running the ctxprog.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nv40_graph.c

index 5beb01b8ace1387bd04639a7b49be90d28bd4d9f..c7885e990937a2dfe5fa7c051a15a5712b91ce10 100644 (file)
@@ -35,89 +35,6 @@ struct nv40_graph_engine {
        u32 grctx_size;
 };
 
-static struct nouveau_channel *
-nv40_graph_channel(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *grctx;
-       uint32_t inst;
-       int i;
-
-       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
-               return NULL;
-       inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
-
-       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               if (!dev_priv->channels.ptr[i])
-                       continue;
-
-               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
-               if (grctx && grctx->pinst == inst)
-                       return dev_priv->channels.ptr[i];
-       }
-
-       return NULL;
-}
-
-static int
-nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
-{
-       uint32_t old_cp, tv = 1000, tmp;
-       int i;
-
-       old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-
-       tmp  = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310);
-       tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
-                     NV40_PGRAPH_CTXCTL_0310_XFER_LOAD;
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp);
-
-       tmp  = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304);
-       tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp);
-
-       nouveau_wait_for_idle(dev);
-
-       for (i = 0; i < tv; i++) {
-               if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0)
-                       break;
-       }
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
-
-       if (i == tv) {
-               uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT);
-               NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save);
-               NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n",
-                        ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT,
-                        ucstat  & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK);
-               NV_ERROR(dev, "0x40030C = 0x%08x\n",
-                        nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C));
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static int
-nv40_graph_unload_context(struct drm_device *dev)
-{
-       uint32_t inst;
-       int ret;
-
-       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
-
-       ret = nv40_graph_transfer_context(dev, inst, 1);
-
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
-       return ret;
-}
-
 static int
 nv40_graph_context_new(struct nouveau_channel *chan, int engine)
 {
@@ -163,16 +80,16 @@ nv40_graph_context_del(struct nouveau_channel *chan, int engine)
        struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       u32 inst = 0x01000000 | (grctx->pinst >> 4);
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv04_graph_fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (nv40_graph_channel(dev) == chan)
-               nv40_graph_unload_context(dev);
-
-       nv04_graph_fifo_access(dev, true);
+       nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
+       if (nv_rd32(dev, 0x40032c) == inst)
+               nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
+       if (nv_rd32(dev, 0x400330) == inst)
+               nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
+       nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
@@ -431,7 +348,18 @@ nv40_graph_init(struct drm_device *dev, int engine)
 static int
 nv40_graph_fini(struct drm_device *dev, int engine)
 {
-       nv40_graph_unload_context(dev);
+       u32 inst = nv_rd32(dev, 0x40032c);
+       if (inst & 0x01000000) {
+               nv_wr32(dev, 0x400720, 0x00000000);
+               nv_wr32(dev, 0x400784, inst);
+               nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
+               nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
+               if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
+                       u32 insn = nv_rd32(dev, 0x400308);
+                       NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
+               }
+               nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
+       }
        return 0;
 }