drm/nouveau: working towards a common way to represent engines
authorBen Skeggs <bskeggs@redhat.com>
Thu, 31 Mar 2011 05:40:43 +0000 (15:40 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 16 May 2011 00:48:01 +0000 (10:48 +1000)
There's lots of more-or-less independant engines present on NVIDIA GPUs
these days, and we generally want to perform the same operations on them.
Implementing new ones requires hooking into lots of different places,
the aim of this work is to make this simpler and cleaner.

NV84:NV98 PCRYPT moved over as a test.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
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_object.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_vm.h
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nv84_crypt.c

index 4cea35c57d15a4582ac0dfbd76add6b9934e9317..3a047ec1ead3f8b2681226f448b6b24eac15aeaa 100644 (file)
@@ -269,8 +269,8 @@ 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 i;
 
        /* decrement the refcount, and we're done if there's still refs */
        if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -305,8 +305,10 @@ 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);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (chan->engctx[i])
+                       dev_priv->eng[i]->context_del(chan, i);
+       }
 
        pfifo->reassign(dev, true);
 
index 155ebdcbf06fe2ab1d41f047733a307dd9656389..30b9e89a3a2a266ec08e463ae704c8be2f346235 100644 (file)
@@ -208,6 +208,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
 
        pgraph->fifo_access(dev, false);
        nouveau_wait_for_idle(dev);
+
+       for (i = NVOBJ_ENGINE_NR - 1; i >= 0; i--) {
+               if (dev_priv->eng[i])
+                       dev_priv->eng[i]->fini(dev, i);
+       }
+
        pfifo->reassign(dev, false);
        pfifo->disable(dev);
        pfifo->unload_context(dev);
@@ -299,8 +305,11 @@ nouveau_pci_resume(struct pci_dev *pdev)
        engine->mc.init(dev);
        engine->timer.init(dev);
        engine->fb.init(dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (dev_priv->eng[i])
+                       dev_priv->eng[i]->init(dev, i);
+       }
        engine->graph.init(dev);
-       engine->crypt.init(dev);
        engine->fifo.init(dev);
 
        nouveau_irq_postinstall(dev);
index 31e34ae16daeaff7b5c4886adfbf3d6a55f58124..6b43cb02dce09fea5bf0d296e8aa812239f02b6c 100644 (file)
@@ -150,13 +150,9 @@ 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
+#define NVOBJ_ENGINE_CRYPT     2
+#define NVOBJ_ENGINE_DISPLAY   15
+#define NVOBJ_ENGINE_NR                16
 
 #define NVOBJ_FLAG_DONT_MAP             (1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC          (1 << 1)
@@ -248,8 +244,8 @@ 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;
+       void *engctx[NVOBJ_ENGINE_NR];
 
        /* NV50 VM */
        struct nouveau_vm     *vm;
@@ -298,6 +294,17 @@ struct nouveau_channel {
        } debugfs;
 };
 
+struct nouveau_exec_engine {
+       void (*destroy)(struct drm_device *, int engine);
+       int  (*init)(struct drm_device *, int engine);
+       int  (*fini)(struct drm_device *, int engine);
+       int  (*context_new)(struct nouveau_channel *, int engine);
+       void (*context_del)(struct nouveau_channel *, int engine);
+       int  (*object_new)(struct nouveau_channel *, int engine,
+                          u32 handle, u16 class);
+       void (*tlb_flush)(struct drm_device *, int engine);
+};
+
 struct nouveau_instmem_engine {
        void    *priv;
 
@@ -501,17 +508,6 @@ 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 *);
-       int  (*object_new)(struct nouveau_channel *, u32 handle, u16 class);
-       void (*tlb_flush)(struct drm_device *dev);
-};
-
 struct nouveau_vram_engine {
        int  (*init)(struct drm_device *);
        int  (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -531,7 +527,6 @@ 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_vram_engine    vram;
 };
 
@@ -651,6 +646,7 @@ struct drm_nouveau_private {
        u32 ramin_base;
        bool ramin_available;
        struct drm_mm ramin_heap;
+       struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
        struct list_head gpuobj_list;
        struct list_head classes;
 
@@ -881,6 +877,16 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
 extern void nouveau_channel_idle(struct nouveau_channel *chan);
 
 /* nouveau_object.c */
+#define NVOBJ_ENGINE_ADD(d, e, p) do {                                         \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = (p);                                 \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do {                                            \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = NULL;                                \
+} while (0)
+
 #define NVOBJ_CLASS(d, c, e) do {                                              \
        int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e);        \
        if (ret)                                                               \
@@ -1209,12 +1215,7 @@ extern int  nvc0_graph_unload_context(struct drm_device *);
 extern int  nvc0_graph_object_new(struct nouveau_channel *, u32, u16);
 
 /* 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);
-extern int  nv84_crypt_object_new(struct nouveau_channel *, u32, u16);
+extern int  nv84_crypt_create(struct drm_device *);
 
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
@@ -1582,6 +1583,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
                dev->pdev->subsystem_device == sub_device;
 }
 
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       return (void *)dev_priv->eng[engine];
+}
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */
index f7b806f26f2ff996dff7eb80b6f686355186a8fb..4fb05b6c6985d1fd891495b9677bace016782c62 100644 (file)
@@ -621,7 +621,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj_class *oc;
        int ret;
@@ -649,17 +648,15 @@ found:
                }
 
                return pgraph->object_new(chan, handle, class);
-       case NVOBJ_ENGINE_CRYPT:
-               if (!chan->crypt_ctx) {
-                       ret = pcrypt->create_context(chan);
-                       if (ret)
-                               return ret;
-               }
+       }
 
-               return pcrypt->object_new(chan, handle, class);
+       if (!chan->engctx[oc->engine]) {
+               ret = dev_priv->eng[oc->engine]->context_new(chan, oc->engine);
+               if (ret)
+                       return ret;
        }
 
-       BUG_ON(1);
+       return dev_priv->eng[oc->engine]->object_new(chan, oc->engine, handle, class);
 }
 
 static int
index fa81b9017b3520bd241bb944d5c9c63e91f52a10..a1a25ea7cc7e4bcbb85cba5548bcebdc84521ca3 100644 (file)
@@ -99,8 +99,6 @@ 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;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -159,8 +157,6 @@ 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;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -219,8 +215,6 @@ 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;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -281,8 +275,6 @@ 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;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -345,8 +337,6 @@ 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;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -438,25 +428,6 @@ 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;
-                       engine->crypt.object_new = nv84_crypt_object_new;
-                       engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
-                       break;
-               default:
-                       engine->crypt.init      = nouveau_stub_init;
-                       engine->crypt.takedown  = nouveau_stub_takedown;
-                       break;
-               }
                engine->vram.init               = nv50_vram_init;
                engine->vram.get                = nv50_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -511,8 +482,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.irq_register       = nv50_gpio_irq_register;
                engine->gpio.irq_unregister     = nv50_gpio_irq_unregister;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nvc0_vram_init;
                engine->vram.get                = nvc0_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -601,7 +570,7 @@ nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
-       int ret;
+       int ret, e;
 
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
        vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -666,23 +635,37 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_timer;
 
+       switch (dev_priv->chipset) {
+       case 0x84:
+       case 0x86:
+       case 0x92:
+       case 0x94:
+       case 0x96:
+       case 0xa0:
+               nv84_crypt_create(dev);
+               break;
+       }
+
        if (nouveau_noaccel)
                engine->graph.accel_blocked = true;
        else {
+               for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+                       if (dev_priv->eng[e]) {
+                               ret = dev_priv->eng[e]->init(dev, e);
+                               if (ret)
+                                       goto out_engine;
+                       }
+               }
+
                /* PGRAPH */
                ret = engine->graph.init(dev);
                if (ret)
-                       goto out_fb;
-
-               /* PCRYPT */
-               ret = engine->crypt.init(dev);
-               if (ret)
-                       goto out_graph;
+                       goto out_engine;
 
                /* PFIFO */
                ret = engine->fifo.init(dev);
                if (ret)
-                       goto out_crypt;
+                       goto out_graph;
        }
 
        ret = engine->display.create(dev);
@@ -723,13 +706,17 @@ out_vblank:
 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);
-out_fb:
+out_engine:
+       if (!nouveau_noaccel) {
+               for (e = e - 1; e >= 0; e--) {
+                       dev_priv->eng[e]->fini(dev, e);
+                       dev_priv->eng[e]->destroy(dev, e);
+               }
+       }
+
        engine->fb.takedown(dev);
 out_timer:
        engine->timer.takedown(dev);
@@ -759,6 +746,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
+       int e;
 
        if (!engine->graph.accel_blocked) {
                nouveau_fence_fini(dev);
@@ -767,8 +755,13 @@ static void nouveau_card_takedown(struct drm_device *dev)
 
        if (!nouveau_noaccel) {
                engine->fifo.takedown(dev);
-               engine->crypt.takedown(dev);
                engine->graph.takedown(dev);
+               for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+                       if (dev_priv->eng[e]) {
+                               dev_priv->eng[e]->fini(dev, e);
+                               dev_priv->eng[e]->destroy(dev,e );
+                       }
+               }
        }
        engine->fb.takedown(dev);
        engine->timer.takedown(dev);
index 2e06b55cfdc1844eb4e1a376890fa35912fb10ca..16ffc4cceebf86868474e2eadf716b3db02bfafe 100644 (file)
@@ -54,7 +54,7 @@ struct nouveau_vm {
 
        struct list_head pgd_list;
        atomic_t pgraph_refs;
-       atomic_t pcrypt_refs;
+       atomic_t engref[16];
 
        struct nouveau_vm_pgt *pgt;
        u32 fpde;
index 6c26944907418b0d090d35758b8e22d7ce9de06c..1f58b0d62796b0df826aaabbf562c366a8d32c47 100644 (file)
@@ -152,7 +152,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        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;
+       int i;
 
        pinstmem->flush(vm->dev);
 
@@ -166,8 +166,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
 
        if (atomic_read(&vm->pgraph_refs))
                pgraph->tlb_flush(vm->dev);
-       if (atomic_read(&vm->pcrypt_refs))
-               pcrypt->tlb_flush(vm->dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (atomic_read(&vm->engref[i]))
+                       dev_priv->eng[i]->tlb_flush(vm->dev, i);
+       }
 }
 
 void
index 4918f4e60babf717a12fabfe18a93e4f58abb382..75b809a51748e09eaa78cd8e07d5a7b754b3e408 100644 (file)
 #include "nouveau_vm.h"
 #include "nouveau_ramht.h"
 
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+       struct nouveau_exec_engine base;
+};
 
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx;
        int ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, 256, 0,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &chan->crypt_ctx);
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &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, 0xa4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xa8, ctx->vinst);
        nv_wo32(ramin, 0xac, 0);
        nv_wo32(ramin, 0xb0, 0);
        nv_wo32(ramin, 0xb4, 0);
-
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pcrypt_refs);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
        return 0;
 }
 
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        u32 inst;
 
-       if (!chan->crypt_ctx)
-               return;
-
        inst  = (chan->ramin->vinst >> 12);
        inst |= 0x80000000;
 
@@ -81,12 +82,15 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
                nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
        nv_wr32(dev, 0x10200c, 0x00000010);
 
-       nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
-       atomic_dec(&chan->vm->pcrypt_refs);
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
-int
-nv84_crypt_object_new(struct nouveau_channel *chan, u32 handle, u16 class)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -107,27 +111,45 @@ nv84_crypt_object_new(struct nouveau_channel *chan, u32 handle, u16 class)
        return ret;
 }
 
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
 {
        nv50_vm_flush_engine(dev, 0x0a);
 }
 
-int
-nv84_crypt_init(struct drm_device *dev)
+static void
+nv84_crypt_isr(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+       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;
+       int show = nouveau_ratelimit();
 
-       if (!pcrypt->registered) {
-               NVOBJ_CLASS(dev, 0x74c1, CRYPT);
-               pcrypt->registered = true;
+       if (show) {
+               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, show);
+}
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x102140, 0x00000000);
+       return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
        nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
        nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
 
-       nouveau_irq_register(dev, 14, nv84_crypt_isr);
        nv_wr32(dev, 0x102130, 0xffffffff);
        nv_wr32(dev, 0x102140, 0xffffffbf);
 
@@ -135,29 +157,37 @@ nv84_crypt_init(struct drm_device *dev)
        return 0;
 }
 
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x102140, 0x00000000);
+       struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, CRYPT);
+
        nouveau_irq_unregister(dev, 14);
+       kfree(pcrypt);
 }
 
-static void
-nv84_crypt_isr(struct drm_device *dev)
+int
+nv84_crypt_create(struct drm_device *dev)
 {
-       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;
-       int show = nouveau_ratelimit();
+       struct nv84_crypt_engine *pcrypt;
 
-       if (show) {
-               NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                            stat, mthd, data, inst);
-       }
+       pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+       if (!pcrypt)
+               return -ENOMEM;
 
-       nv_wr32(dev, 0x102130, stat);
-       nv_wr32(dev, 0x10200c, 0x10);
+       pcrypt->base.destroy = nv84_crypt_destroy;
+       pcrypt->base.init = nv84_crypt_init;
+       pcrypt->base.fini = nv84_crypt_fini;
+       pcrypt->base.context_new = nv84_crypt_context_new;
+       pcrypt->base.context_del = nv84_crypt_context_del;
+       pcrypt->base.object_new = nv84_crypt_object_new;
+       pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
 
-       nv50_fb_vm_trap(dev, show);
+       nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+       NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+       NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+       return 0;
 }