drm/nv84: add support for the PCRYPT engine
authorBen Skeggs <bskeggs@redhat.com>
Tue, 19 Oct 2010 10:06:01 +0000 (20:06 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 3 Dec 2010 05:06:58 +0000 (15:06 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv84_crypt.c [new file with mode: 0644]

index 23fa82d667d6f060e70eba35a2834e671441c8d7..a541f5bff75dbc5f0c6f58d6831f82e18949f0c2 100644 (file)
@@ -18,6 +18,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
              nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o \
+             nv84_crypt.o \
              nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
index 76033c509d357bb56f9fafab3492a69201d11bba..8f2df6beb893f6b5a65f8bd7f39e98ce6a66f7e4 100644 (file)
@@ -112,6 +112,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        struct nouveau_channel *chan;
        unsigned long flags;
        int user, ret;
@@ -214,6 +215,14 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
                return ret;
        }
 
+       if (pcrypt->create_context) {
+               ret = pcrypt->create_context(chan);
+               if (ret) {
+                       nouveau_channel_put(&chan);
+                       return ret;
+               }
+       }
+
        /* Construct inital RAMFC for new channel */
        ret = pfifo->create_context(chan);
        if (ret) {
@@ -280,6 +289,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        unsigned long flags;
        int ret;
 
@@ -328,6 +338,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        /* destroy the engine specific contexts */
        pfifo->destroy_context(chan);
        pgraph->destroy_context(chan);
+       if (pcrypt->destroy_context)
+               pcrypt->destroy_context(chan);
 
        pfifo->reassign(dev, true);
 
index f139aa2cbe5cafbe0e0a0ec747d74a06eb064600..6dbb8818c530fdea23b0d0c56f8721e42c010f42 100644 (file)
@@ -299,6 +299,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
        engine->timer.init(dev);
        engine->fb.init(dev);
        engine->graph.init(dev);
+       engine->crypt.init(dev);
        engine->fifo.init(dev);
 
        NV_INFO(dev, "Restoring GPU objects...\n");
index 3fb87995446b922ce1dc3668d60f3690fd589e8c..d15bfd427267f3c07521590806a1782e50ffd52e 100644 (file)
@@ -132,6 +132,11 @@ enum nouveau_flags {
 
 #define NVOBJ_ENGINE_SW                0
 #define NVOBJ_ENGINE_GR                1
+#define NVOBJ_ENGINE_PPP       2
+#define NVOBJ_ENGINE_COPY      3
+#define NVOBJ_ENGINE_VP                4
+#define NVOBJ_ENGINE_CRYPT      5
+#define NVOBJ_ENGINE_BSP       6
 #define NVOBJ_ENGINE_DISPLAY   0xcafe0001
 #define NVOBJ_ENGINE_INT       0xdeadbeef
 
@@ -208,6 +213,7 @@ struct nouveau_channel {
        /* PGRAPH context */
        /* XXX may be merge 2 pointers as private data ??? */
        struct nouveau_gpuobj *ramin_grctx;
+       struct nouveau_gpuobj *crypt_ctx;
        void *pgraph_ctx;
 
        /* NV50 VM */
@@ -444,6 +450,16 @@ struct nouveau_pm_engine {
        int (*temp_get)(struct drm_device *);
 };
 
+struct nouveau_crypt_engine {
+       bool registered;
+
+       int  (*init)(struct drm_device *);
+       void (*takedown)(struct drm_device *);
+       int  (*create_context)(struct nouveau_channel *);
+       void (*destroy_context)(struct nouveau_channel *);
+       void (*tlb_flush)(struct drm_device *dev);
+};
+
 struct nouveau_engine {
        struct nouveau_instmem_engine instmem;
        struct nouveau_mc_engine      mc;
@@ -454,6 +470,7 @@ struct nouveau_engine {
        struct nouveau_display_engine display;
        struct nouveau_gpio_engine    gpio;
        struct nouveau_pm_engine      pm;
+       struct nouveau_crypt_engine   crypt;
 };
 
 struct nouveau_pll_vals {
@@ -1113,6 +1130,13 @@ extern void nvc0_graph_destroy_context(struct nouveau_channel *);
 extern int  nvc0_graph_load_context(struct nouveau_channel *);
 extern int  nvc0_graph_unload_context(struct drm_device *);
 
+/* nv84_crypt.c */
+extern int  nv84_crypt_init(struct drm_device *dev);
+extern void nv84_crypt_fini(struct drm_device *dev);
+extern int  nv84_crypt_create_context(struct nouveau_channel *);
+extern void nv84_crypt_destroy_context(struct nouveau_channel *);
+extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
 extern void nv04_instmem_takedown(struct drm_device *);
index f09151d17297e20b3b111f5cc63f4ccdcd7cf9cb..ca9b969f4f9ce3ac61f84e5c32f8e17d9c858933 100644 (file)
@@ -1230,6 +1230,22 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
                status &= ~NV_PMC_INTR_0_PGRAPH_PENDING;
        }
 
+       if (status & 0x00004000) {
+               u32 stat = nv_rd32(dev, 0x102130);
+               u32 mthd = nv_rd32(dev, 0x102190);
+               u32 data = nv_rd32(dev, 0x102194);
+               u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff;
+
+               NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       stat, mthd, data, inst);
+               nv_wr32(dev, 0x102130, stat);
+               nv_wr32(dev, 0x10200c, 0x10);
+
+               nv50_fb_vm_trap(dev, nouveau_ratelimit(), "PCRYPT");
+               status &= ~0x00004000;
+
+       }
+
        if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
                nouveau_crtc_irq_handler(dev, (status>>24)&3);
                status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
index 6226beb3613dc223f578b697aeadb858f07aa104..ee526534c6f4de24e424720bfcc38cada021a44e 100644 (file)
@@ -272,6 +272,7 @@ nouveau_gpuobj_init(struct drm_device *dev)
        NV_DEBUG(dev, "\n");
 
        INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+       INIT_LIST_HEAD(&dev_priv->classes);
        spin_lock_init(&dev_priv->ramin_lock);
        dev_priv->ramin_base = ~0;
 
@@ -686,7 +687,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
        /* Base amount for object storage (4KiB enough?) */
-       size = 0x1000;
+       size = 0x2000;
        base = 0;
 
        /* PGRAPH context */
index be28754ffd50ed2cff01048a5ad12ba4ce7cb40e..f13134aa8c4f9b3f51168b002d54391586183f83 100644 (file)
@@ -98,6 +98,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        case 0x10:
                engine->instmem.init            = nv04_instmem_init;
@@ -151,6 +153,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        case 0x20:
                engine->instmem.init            = nv04_instmem_init;
@@ -204,6 +208,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        case 0x30:
                engine->instmem.init            = nv04_instmem_init;
@@ -259,6 +265,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_set            = nv04_pm_clock_set;
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        case 0x40:
        case 0x60:
@@ -316,6 +324,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
                engine->pm.temp_get             = nv40_temp_get;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        case 0x50:
        case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -380,19 +390,23 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.set                = nv50_gpio_set;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
                switch (dev_priv->chipset) {
-               case 0xa3:
-               case 0xa5:
-               case 0xa8:
-               case 0xaf:
-                       engine->pm.clock_get    = nva3_pm_clock_get;
-                       engine->pm.clock_pre    = nva3_pm_clock_pre;
-                       engine->pm.clock_set    = nva3_pm_clock_set;
-                       break;
-               default:
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0x98:
+               case 0xa0:
+               case 0x50:
                        engine->pm.clock_get    = nv50_pm_clock_get;
                        engine->pm.clock_pre    = nv50_pm_clock_pre;
                        engine->pm.clock_set    = nv50_pm_clock_set;
                        break;
+               default:
+                       engine->pm.clock_get    = nva3_pm_clock_get;
+                       engine->pm.clock_pre    = nva3_pm_clock_pre;
+                       engine->pm.clock_set    = nva3_pm_clock_set;
+                       break;
                }
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
@@ -400,6 +414,23 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                        engine->pm.temp_get     = nv84_temp_get;
                else
                        engine->pm.temp_get     = nv40_temp_get;
+               switch (dev_priv->chipset) {
+               case 0x84:
+               case 0x86:
+               case 0x92:
+               case 0x94:
+               case 0x96:
+               case 0xa0:
+                       engine->crypt.init      = nv84_crypt_init;
+                       engine->crypt.takedown  = nv84_crypt_fini;
+                       engine->crypt.create_context = nv84_crypt_create_context;
+                       engine->crypt.destroy_context = nv84_crypt_destroy_context;
+                       break;
+               default:
+                       engine->crypt.init      = nouveau_stub_init;
+                       engine->crypt.takedown  = nouveau_stub_takedown;
+                       break;
+               }
                break;
        case 0xC0:
                engine->instmem.init            = nvc0_instmem_init;
@@ -447,6 +478,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.get                = nv50_gpio_get;
                engine->gpio.set                = nv50_gpio_set;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
+               engine->crypt.init              = nouveau_stub_init;
+               engine->crypt.takedown          = nouveau_stub_takedown;
                break;
        default:
                NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
@@ -619,10 +652,15 @@ nouveau_card_init(struct drm_device *dev)
                if (ret)
                        goto out_fb;
 
+               /* PCRYPT */
+               ret = engine->crypt.init(dev);
+               if (ret)
+                       goto out_graph;
+
                /* PFIFO */
                ret = engine->fifo.init(dev);
                if (ret)
-                       goto out_graph;
+                       goto out_crypt;
        }
 
        ret = engine->display.create(dev);
@@ -669,6 +707,9 @@ out_display:
 out_fifo:
        if (!nouveau_noaccel)
                engine->fifo.takedown(dev);
+out_crypt:
+       if (!nouveau_noaccel)
+               engine->crypt.takedown(dev);
 out_graph:
        if (!nouveau_noaccel)
                engine->graph.takedown(dev);
@@ -712,6 +753,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
 
        if (!nouveau_noaccel) {
                engine->fifo.takedown(dev);
+               engine->crypt.takedown(dev);
                engine->graph.takedown(dev);
        }
        engine->fb.takedown(dev);
diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
new file mode 100644 (file)
index 0000000..63bd6bb
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+
+int
+nv84_crypt_create_context(struct nouveau_channel *chan)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
+                                &chan->crypt_ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, 0xa0, 0x00190000);
+       nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
+       nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+       nv_wo32(ramin, 0xac, 0);
+       nv_wo32(ramin, 0xb0, 0);
+       nv_wo32(ramin, 0xb4, 0);
+
+       dev_priv->engine.instmem.flush(dev);
+       return 0;
+}
+
+void
+nv84_crypt_destroy_context(struct nouveau_channel *chan)
+{
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       if (!chan->ramin)
+               return;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x80000000;
+
+       /* mark context as invalid if still on the hardware, not
+        * doing this causes issues the next time PCRYPT is used,
+        * unsurprisingly :)
+        */
+       nv_wr32(dev, 0x10200c, 0x00000000);
+       if (nv_rd32(dev, 0x102188) == inst)
+               nv_mask(dev, 0x102188, 0x80000000, 0x00000000);
+       if (nv_rd32(dev, 0x10218c) == inst)
+               nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
+       nv_wr32(dev, 0x10200c, 0x00000010);
+
+       nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
+}
+
+void
+nv84_crypt_tlb_flush(struct drm_device *dev)
+{
+       nv50_vm_flush(dev, 0x0a);
+}
+
+int
+nv84_crypt_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+
+       if (!pcrypt->registered) {
+               NVOBJ_CLASS(dev, 0x74c1, CRYPT);
+               pcrypt->registered = true;
+       }
+
+       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+       nv_wr32(dev, 0x102130, 0xffffffff);
+       nv_wr32(dev, 0x102140, 0xffffffbf);
+       nv_wr32(dev, 0x10200c, 0x00000010);
+       return 0;
+}
+
+void
+nv84_crypt_fini(struct drm_device *dev)
+{
+       nv_wr32(dev, 0x102140, 0x00000000);
+}