#include <core/engine.h>
 
 struct nvkm_sw {
-       struct nvkm_engine engine;
        const struct nvkm_sw_func *func;
+       struct nvkm_engine engine;
+
        struct list_head chan;
 };
 
 bool nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data);
 
-#define nvkm_sw_create(p,e,c,d)                                       \
-       nvkm_sw_ctor((p), (e), (c), sizeof(**d), (void **)d)
-int
-nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-            struct nvkm_oclass *oclass, int length, void **pobject);
-#define nvkm_sw_destroy(d)                                            \
-       nvkm_engine_destroy(&(d)->engine)
-#define nvkm_sw_init(d)                                               \
-       nvkm_engine_init_old(&(d)->engine)
-#define nvkm_sw_fini(d,s)                                             \
-       nvkm_engine_fini_old(&(d)->engine, (s))
-
-#define _nvkm_sw_dtor _nvkm_engine_dtor
-#define _nvkm_sw_init _nvkm_engine_init
-#define _nvkm_sw_fini _nvkm_engine_fini
-
-extern struct nvkm_oclass *nv04_sw_oclass;
-extern struct nvkm_oclass *nv10_sw_oclass;
-extern struct nvkm_oclass *nv50_sw_oclass;
-extern struct nvkm_oclass *gf100_sw_oclass;
-
-void nv04_sw_intr(struct nvkm_subdev *);
+int nv04_sw_new(struct nvkm_device *, int, struct nvkm_sw **);
+int nv10_sw_new(struct nvkm_device *, int, struct nvkm_sw **);
+int nv50_sw_new(struct nvkm_device *, int, struct nvkm_sw **);
+int gf100_sw_new(struct nvkm_device *, int, struct nvkm_sw **);
 #endif
 
        .dma = nv04_dma_new,
        .fifo = nv04_fifo_new,
        .gr = nv04_gr_new,
-//     .sw = nv04_sw_new,
+       .sw = nv04_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv04_fifo_new,
        .gr = nv04_gr_new,
-//     .sw = nv04_sw_new,
+       .sw = nv04_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv10_fifo_new,
        .gr = nv15_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv10_fifo_new,
        .gr = nv15_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv17_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv17_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv10_fifo_new,
        .gr = nv15_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv17_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv20_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv25_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv25_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv2a_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv30_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .fifo = nv17_fifo_new,
        .gr = nv30_gr_new,
 //     .mpeg = nv31_mpeg_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .fifo = nv17_fifo_new,
        .gr = nv34_gr_new,
 //     .mpeg = nv31_mpeg_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = nv04_dma_new,
        .fifo = nv17_fifo_new,
        .gr = nv35_gr_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .fifo = nv17_fifo_new,
        .gr = nv35_gr_new,
 //     .mpeg = nv31_mpeg_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv40_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv40_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv40_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv40_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv40_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv50_gr_new,
 //     .mpeg = nv50_mpeg_new,
        .pm = nv50_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = nv44_gr_new,
 //     .mpeg = nv44_mpeg_new,
        .pm = nv40_pm_new,
-//     .sw = nv10_sw_new,
+       .sw = nv10_sw_new,
 };
 
 static const struct nvkm_device_chip
        .gr = g84_gr_new,
 //     .mpeg = g84_mpeg_new,
        .pm = g84_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
        .vp = g84_vp_new,
 };
 
        .gr = g84_gr_new,
 //     .mpeg = g84_mpeg_new,
        .pm = g84_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
        .vp = g84_vp_new,
 };
 
        .gr = g84_gr_new,
 //     .mpeg = g84_mpeg_new,
        .pm = g84_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
        .vp = g84_vp_new,
 };
 
        .gr = g84_gr_new,
 //     .mpeg = g84_mpeg_new,
        .pm = g84_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
        .vp = g84_vp_new,
 };
 
        .volt = nv40_volt_new,
        .dma = nv50_dma_new,
        .fifo = g84_fifo_new,
-//     .sw = nv50_sw_new,
        .gr = g84_gr_new,
+       .gr = nv50_gr_new,
 //     .mpeg = g84_mpeg_new,
        .vp = g84_vp_new,
        .cipher = g84_cipher_new,
        .volt = nv40_volt_new,
        .dma = nv50_dma_new,
        .fifo = g84_fifo_new,
-//     .sw = nv50_sw_new,
        .gr = g84_gr_new,
+       .sw = nv50_sw_new,
        .mspdec = g98_mspdec_new,
        .sec = g98_sec_new,
        .msvld = g98_msvld_new,
        .gr = gt200_gr_new,
 //     .mpeg = g84_mpeg_new,
        .pm = gt200_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
        .vp = g84_vp_new,
 };
 
        .msppp = gt215_msppp_new,
        .msvld = gt215_msvld_new,
        .pm = gt215_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gt215_msppp_new,
        .msvld = gt215_msvld_new,
        .pm = gt215_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gt215_msppp_new,
        .msvld = gt215_msvld_new,
        .pm = gt215_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msvld = g98_msvld_new,
        .pm = g84_pm_new,
        .sec = g98_sec_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msvld = g98_msvld_new,
        .pm = g84_pm_new,
        .sec = g98_sec_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gt215_msppp_new,
        .msvld = mcp89_msvld_new,
        .pm = gt215_pm_new,
-//     .sw = nv50_sw_new,
+       .sw = nv50_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf108_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf100_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf117_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gf100_msvld_new,
        .pm = gf117_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
        .pm = gk104_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
        .pm = gk104_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
        .pm = gk104_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .fifo = gk20a_fifo_new,
        .gr = gk20a_gr_new,
        .pm = gk104_pm_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .mspdec = gk104_mspdec_new,
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .mspdec = gk104_mspdec_new,
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .mspdec = gk104_mspdec_new,
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .mspdec = gk104_mspdec_new,
        .msppp = gf100_msppp_new,
        .msvld = gk104_msvld_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = gf119_dma_new,
        .fifo = gk208_fifo_new,
        .gr = gm107_gr_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = gf119_dma_new,
        .fifo = gm204_fifo_new,
        .gr = gm204_gr_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = gf119_dma_new,
        .fifo = gm204_fifo_new,
        .gr = gm206_gr_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 static const struct nvkm_device_chip
        .dma = gf119_dma_new,
        .fifo = gm20b_fifo_new,
        .gr = gm20b_gr_new,
-//     .sw = gf100_sw_new,
+       .sw = gf100_sw_new,
 };
 
 #include <core/client.h>
 
 {
        switch (device->chipset) {
        case 0xc0:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xc4:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xc3:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xce:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xcf:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xc1:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xc8:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xd9:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xd7:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        default:
                return -EINVAL;
 
 {
        switch (device->chipset) {
        case 0xe4:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xe7:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xe6:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xea:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xf0:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0xf1:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0x106:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        case 0x108:
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        default:
                return -EINVAL;
 
 
 #if 0
 #endif
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
 #if 0
 #endif
 #if 0
 #endif
 #if 0
 #endif
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
 #if 0
 #endif
                break;
 #endif
 #if 0
 #endif
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
 #if 0
 #endif
                break;
        case 0x12b:
 
-               device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
                break;
        default:
                return -EINVAL;
 
 {
        switch (device->chipset) {
        case 0x04:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
                break;
        case 0x05:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
                break;
        default:
                return -EINVAL;
 
        case 0x10:
                break;
        case 0x15:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x16:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x1a:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x11:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x17:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x1f:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x18:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        default:
                return -EINVAL;
 
 {
        switch (device->chipset) {
        case 0x20:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x25:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x28:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x2a:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        default:
                return -EINVAL;
 
 {
        switch (device->chipset) {
        case 0x30:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x35:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                break;
        case 0x31:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                break;
        case 0x36:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                break;
        case 0x34:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
                break;
        default:
 
 {
        switch (device->chipset) {
        case 0x40:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                break;
        case 0x41:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                break;
        case 0x42:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                break;
        case 0x43:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
                break;
        case 0x45:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x47:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x49:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x4b:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x44:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x46:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x4a:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x4c:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x4e:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x63:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x67:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        case 0x68:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
                break;
        default:
 
 {
        switch (device->chipset) {
        case 0x50:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
                break;
        case 0x84:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0x86:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0x92:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0x94:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0x96:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0x98:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        case 0xa0:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0xaa:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        case 0xac:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        case 0xa3:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
                break;
        case 0xa5:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        case 0xa8:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        case 0xaf:
-               device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
                break;
        default:
                return -EINVAL;
 
        return sw->func->chan_new(sw, fifoch, oclass, pobject);
 }
 
+static void *
+nvkm_sw_dtor(struct nvkm_engine *engine)
+{
+       return nvkm_sw(engine);
+}
+
 static const struct nvkm_engine_func
 nvkm_sw = {
+       .dtor = nvkm_sw_dtor,
        .fifo.cclass = nvkm_sw_cclass_get,
        .fifo.sclass = nvkm_sw_oclass_get,
 };
 
 int
-nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-            struct nvkm_oclass *oclass, int length, void **pobject)
+nvkm_sw_new_(const struct nvkm_sw_func *func, struct nvkm_device *device,
+            int index, struct nvkm_sw **psw)
 {
        struct nvkm_sw *sw;
-       int ret;
 
-       ret = nvkm_engine_create_(parent, engine, oclass, true, "sw",
-                                 "sw", length, pobject);
-       sw = *pobject;
-       if (ret)
-               return ret;
-
-       sw->engine.func = &nvkm_sw;
+       if (!(sw = *psw = kzalloc(sizeof(*sw), GFP_KERNEL)))
+               return -ENOMEM;
        INIT_LIST_HEAD(&sw->chan);
-       return 0;
+       sw->func = func;
+
+       return nvkm_engine_ctor(&nvkm_sw, device, index, 0, true, &sw->engine);
 }
 
  ******************************************************************************/
 
 static const struct nvkm_sw_func
-gf100_sw_func = {
+gf100_sw = {
        .chan_new = gf100_sw_chan_new,
        .sclass = {
                { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_GF100 } },
        }
 };
 
-struct nvkm_oclass *
-gf100_sw_oclass = &(struct nv50_sw_oclass) {
-       .base.handle = NV_ENGINE(SW, 0xc0),
-       .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_sw_ctor,
-               .dtor = _nvkm_sw_dtor,
-               .init = _nvkm_sw_init,
-               .fini = _nvkm_sw_fini,
-       },
-       .func = &gf100_sw_func,
-}.base;
+int
+gf100_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw)
+{
+       return nvkm_sw_new_(&gf100_sw, device, index, psw);
+}
 
  * software engine/subdev functions
  ******************************************************************************/
 
-void
-nv04_sw_intr(struct nvkm_subdev *subdev)
-{
-       nvkm_mask(subdev->device, 0x000100, 0x80000000, 0x00000000);
-}
-
 static const struct nvkm_sw_func
 nv04_sw = {
        .chan_new = nv04_sw_chan_new,
        }
 };
 
-static int
-nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-            struct nvkm_oclass *oclass, void *data, u32 size,
-            struct nvkm_object **pobject)
+int
+nv04_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw)
 {
-       struct nvkm_sw *sw;
-       int ret;
-
-       ret = nvkm_sw_create(parent, engine, oclass, &sw);
-       *pobject = nv_object(sw);
-       if (ret)
-               return ret;
-
-       sw->func = &nv04_sw;
-       nv_subdev(sw)->intr = nv04_sw_intr;
-       return 0;
+       return nvkm_sw_new_(&nv04_sw, device, index, psw);
 }
-
-struct nvkm_oclass *
-nv04_sw_oclass = &(struct nvkm_oclass) {
-       .handle = NV_ENGINE(SW, 0x04),
-       .ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv04_sw_ctor,
-               .dtor = _nvkm_sw_dtor,
-               .init = _nvkm_sw_init,
-               .fini = _nvkm_sw_fini,
-       },
-};
 
        }
 };
 
-static int
-nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-            struct nvkm_oclass *oclass, void *data, u32 size,
-            struct nvkm_object **pobject)
+int
+nv10_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw)
 {
-       struct nvkm_sw *sw;
-       int ret;
-
-       ret = nvkm_sw_create(parent, engine, oclass, &sw);
-       *pobject = nv_object(sw);
-       if (ret)
-               return ret;
-
-       sw->func = &nv10_sw;
-       nv_subdev(sw)->intr = nv04_sw_intr;
-       return 0;
+       return nvkm_sw_new_(&nv10_sw, device, index, psw);
 }
-
-struct nvkm_oclass *
-nv10_sw_oclass = &(struct nvkm_oclass) {
-       .handle = NV_ENGINE(SW, 0x10),
-       .ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv10_sw_ctor,
-               .dtor = _nvkm_sw_dtor,
-               .init = _nvkm_sw_init,
-               .fini = _nvkm_sw_fini,
-       },
-};
 
        nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma);
        nvkm_bar_flush(device->bar);
 
-       if (nv_device(sw)->chipset == 0x50) {
+       if (device->chipset == 0x50) {
                nvkm_wr32(device, 0x001570, chan->vblank.offset);
                nvkm_wr32(device, 0x001574, chan->vblank.value);
        } else {
  * software engine/subdev functions
  ******************************************************************************/
 
-int
-nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-            struct nvkm_oclass *oclass, void *data, u32 size,
-            struct nvkm_object **pobject)
-{
-       struct nv50_sw_oclass *pclass = (void *)oclass;
-       struct nvkm_sw *sw;
-       int ret;
-
-       ret = nvkm_sw_create(parent, engine, oclass, &sw);
-       *pobject = nv_object(sw);
-       if (ret)
-               return ret;
-
-       sw->func = pclass->func;
-       nv_subdev(sw)->intr = nv04_sw_intr;
-       return 0;
-}
-
 static const struct nvkm_sw_func
-nv50_sw_func = {
+nv50_sw = {
        .chan_new = nv50_sw_chan_new,
        .sclass = {
                { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } },
        }
 };
 
-struct nvkm_oclass *
-nv50_sw_oclass = &(struct nv50_sw_oclass) {
-       .base.handle = NV_ENGINE(SW, 0x50),
-       .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = nv50_sw_ctor,
-               .dtor = _nvkm_sw_dtor,
-               .init = _nvkm_sw_init,
-               .fini = _nvkm_sw_fini,
-       },
-       .func = &nv50_sw_func,
-}.base;
+int
+nv50_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw)
+{
+       return nvkm_sw_new_(&nv50_sw, device, index, psw);
+}
 
 #include "nvsw.h"
 #include <core/notify.h>
 
-struct nv50_sw_oclass {
-       struct nvkm_oclass base;
-       const struct nvkm_sw_func *func;
-};
-
-int  nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *,
-                       struct nvkm_oclass *, void *, u32,
-                       struct nvkm_object **);
-
-struct nv50_sw_cclass {
-       struct nvkm_oclass base;
-       int (*vblank)(struct nvkm_notify *);
-       const struct nvkm_sw_chan_func *chan;
-};
-
 struct nv50_sw_chan {
        struct nvkm_sw_chan base;
        struct {
 
 #include <nvif/class.h>
 
 static int
-nvkm_nvsw_mthd_(struct nvkm_object *base, u32 mthd, void *data, u32 size)
+nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
 {
-       struct nvkm_nvsw *nvsw = nvkm_nvsw(base);
+       struct nvkm_nvsw *nvsw = nvkm_nvsw(object);
        if (nvsw->func->mthd)
                return nvsw->func->mthd(nvsw, mthd, data, size);
        return -ENODEV;
 }
 
 static int
-nvkm_nvsw_ntfy_(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent)
+nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd,
+               struct nvkm_event **pevent)
 {
-       struct nvkm_nvsw *nvsw = nvkm_nvsw(base);
+       struct nvkm_nvsw *nvsw = nvkm_nvsw(object);
        switch (mthd) {
        case NVSW_NTFY_UEVENT:
                *pevent = &nvsw->chan->event;
 
 #include <engine/sw.h>
 struct nvkm_sw_chan;
 
+int nvkm_sw_new_(const struct nvkm_sw_func *, struct nvkm_device *,
+                int index, struct nvkm_sw **);
+
 struct nvkm_sw_chan_sclass {
        int (*ctor)(struct nvkm_sw_chan *, const struct nvkm_oclass *,
                    void *data, u32 size, struct nvkm_object **);