drm/nouveau: port all engines to new engine module format

This is a HUGE commit, but it's not nearly as bad as it looks - any problems
can be isolated to a particular chipset and engine combination.  It was
simply too difficult to port each one at a time, the compat layers are
*already* ridiculous.

Most of the changes here are simply to the glue, the process for each of the
engine modules was to start with a standard skeleton and copy+paste the old
code into the appropriate places, fixing up variable names etc as needed.

v2: Marcin Slusarz <marcin.slusarz@gmail.com>
- fix find/replace bug in license header

v3: Ben Skeggs <bskeggs@redhat.com>
- bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and
  left no space for kernel's requirements during GEM pushbuf submission.
- fix duplicate assignments noticed by clang

v4: Marcin Slusarz <marcin.slusarz@gmail.com>
- add sparse annotations to nv04_fifo_pause/nv04_fifo_start
- use ioread32_native/iowrite32_native for fifo control registers

v5: Ben Skeggs <bskeggs@redhat.com>
- rebase on v3.6-rc4, modified to keep copy engine fix intact
- nv10/fence: unmap fence bo before destroying
- fixed fermi regression when using nvidia gr fuc
- fixed typo in supported dma_mask checking

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1855699..d8f3ad4 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -4,9 +4,11 @@
 
 ccflags-y := -Iinclude/drm -DCONFIG_NOUVEAU_DEBUG=7 -DCONFIG_NOUVEAU_DEBUG_DEFAULT=3
 ccflags-y += -I$(src)/core/include
+ccflags-y += -I$(src)/core
 ccflags-y += -I$(src)
 
 nouveau-y := core/core/client.o
+nouveau-y += core/core/engctx.o
 nouveau-y += core/core/engine.o
 nouveau-y += core/core/enum.o
 nouveau-y += core/core/gpuobj.o
@@ -90,12 +92,20 @@
 nouveau-y += core/subdev/vm/nv50.o
 nouveau-y += core/subdev/vm/nvc0.o
 
+nouveau-y += core/engine/dmaobj/base.o
+nouveau-y += core/engine/dmaobj/nv04.o
+nouveau-y += core/engine/dmaobj/nv50.o
+nouveau-y += core/engine/dmaobj/nvc0.o
 nouveau-y += core/engine/bsp/nv84.o
 nouveau-y += core/engine/copy/nva3.o
 nouveau-y += core/engine/copy/nvc0.o
 nouveau-y += core/engine/crypt/nv84.o
 nouveau-y += core/engine/crypt/nv98.o
+nouveau-y += core/engine/disp/nv04.o
+nouveau-y += core/engine/disp/nv50.o
+nouveau-y += core/engine/disp/nvd0.o
 nouveau-y += core/engine/disp/vga.o
+nouveau-y += core/engine/fifo/base.o
 nouveau-y += core/engine/fifo/nv04.o
 nouveau-y += core/engine/fifo/nv10.o
 nouveau-y += core/engine/fifo/nv17.o
@@ -111,41 +121,82 @@
 nouveau-y += core/engine/graph/nv04.o
 nouveau-y += core/engine/graph/nv10.o
 nouveau-y += core/engine/graph/nv20.o
+nouveau-y += core/engine/graph/nv25.o
+nouveau-y += core/engine/graph/nv2a.o
+nouveau-y += core/engine/graph/nv30.o
+nouveau-y += core/engine/graph/nv34.o
+nouveau-y += core/engine/graph/nv35.o
 nouveau-y += core/engine/graph/nv40.o
 nouveau-y += core/engine/graph/nv50.o
 nouveau-y += core/engine/graph/nvc0.o
 nouveau-y += core/engine/graph/nve0.o
 nouveau-y += core/engine/mpeg/nv31.o
+nouveau-y += core/engine/mpeg/nv40.o
 nouveau-y += core/engine/mpeg/nv50.o
+nouveau-y += core/engine/mpeg/nv84.o
 nouveau-y += core/engine/ppp/nv98.o
+nouveau-y += core/engine/software/nv04.o
+nouveau-y += core/engine/software/nv10.o
+nouveau-y += core/engine/software/nv50.o
+nouveau-y += core/engine/software/nvc0.o
 nouveau-y += core/engine/vp/nv84.o
 
-nouveau-y += nouveau_drm.o nouveau_compat.o \
-	     nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
-             nouveau_gpuobj.o nouveau_irq.o nouveau_notifier.o \
-             nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
-             nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
-             nouveau_hw.o nouveau_calc.o \
-             nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
-             nouveau_hdmi.o nouveau_dp.o \
-	     nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
-	     nouveau_mxm.o nouveau_agp.o \
-	     nouveau_abi16.o \
-	     nouveau_bios.o \
-             nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o \
-             nv04_software.o nv50_software.o nvc0_software.o \
-             nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
-             nv04_crtc.o nv04_display.o nv04_cursor.o \
-             nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
-             nv50_cursor.o nv50_display.o \
-             nvd0_display.o \
-             nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
-	     nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
-	     nouveau_prime.o
+# drm/compat - will go away
+nouveau-y += nouveau_compat.o nouveau_revcompat.o
 
-nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
+# drm/core
+nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
+nouveau-y += nouveau_agp.o
+nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
+
+nouveau-y += nouveau_abi16.o
+nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
+
+# drm/kms/common
+nouveau-y += nouveau_fbcon.o
+
+# drm/kms/nv04:nv50
+nouveau-y += nv04_fbcon.o
+
+# drm/kms/nv50:nvd9
+nouveau-y += nv50_fbcon.o nvc0_fbcon.o
+
+# drm/kms/nvd9-
+
+##
+## unported bits below
+##
+
+# drm/core
+nouveau-y += nouveau_drv.o nouveau_state.o nouveau_irq.o
+nouveau-y += nouveau_prime.o
+
+# drm/kms/bios
+nouveau-y += nouveau_mxm.o nouveau_bios.o
+
+# drm/kms/common
+nouveau-y += nouveau_display.o nouveau_connector.o
+nouveau-y += nouveau_hdmi.o nouveau_dp.o
+
+# drm/kms/nv04:nv50
+nouveau-y += nouveau_hw.o nouveau_calc.o
+nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
+nouveau-y += nv04_crtc.o nv04_display.o nv04_cursor.o
+
+# drm/kms/nv50-
+nouveau-y += nv50_display.o nvd0_display.o
+nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
+nouveau-y += nv50_evo.o
+
+# drm/pm
+nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o
+nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
+nouveau-y += nouveau_mem.o
+
+# optional stuff
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
 nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
 nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
 
+
 obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
diff --git a/drivers/gpu/drm/nouveau/core/core/ramht.c b/drivers/gpu/drm/nouveau/core/core/ramht.c
index 5c22864..86a6404 100644
--- a/drivers/gpu/drm/nouveau/core/core/ramht.c
+++ b/drivers/gpu/drm/nouveau/core/core/ramht.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -18,289 +18,92 @@
  * 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"
+#include <core/object.h>
 #include <core/ramht.h>
+#include <core/math.h>
+
+#include <subdev/bar.h>
 
 static u32
-nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
+nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_ramht *ramht = chan->ramht;
 	u32 hash = 0;
-	int i;
 
-	NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
-
-	for (i = 32; i > 0; i -= ramht->bits) {
+	while (handle) {
 		hash ^= (handle & ((1 << ramht->bits) - 1));
 		handle >>= ramht->bits;
 	}
 
-	if (dev_priv->card_type < NV_50)
-		hash ^= chan->id << (ramht->bits - 4);
-	hash <<= 3;
-
-	NV_DEBUG(dev, "hash=0x%08x\n", hash);
+	hash ^= chid << (ramht->bits - 4);
+	hash  = hash << 3;
 	return hash;
 }
 
-static int
-nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
-			  u32 offset)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 ctx = nv_ro32(ramht, offset + 4);
-
-	if (dev_priv->card_type < NV_40)
-		return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
-	return (ctx != 0);
-}
-
-static int
-nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
-				 struct nouveau_gpuobj *ramht, u32 offset)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	u32 ctx = nv_ro32(ramht, offset + 4);
-
-	if (dev_priv->card_type >= NV_50)
-		return true;
-	else if (dev_priv->card_type >= NV_40)
-		return chan->id ==
-			((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
-	else
-		return chan->id ==
-			((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
-}
-
 int
-nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
-		     struct nouveau_gpuobj *gpuobj)
+nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
+		     u32 handle, u32 context)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_ramht_entry *entry;
-	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
-	unsigned long flags;
-	u32 ctx, co, ho;
+	struct nouveau_bar *bar = nouveau_bar(ramht);
+	u32 co, ho;
 
-	if (nouveau_ramht_find(chan, handle))
-		return -EEXIST;
-
-	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-	if (!entry)
-		return -ENOMEM;
-	entry->channel = chan;
-	entry->gpuobj = NULL;
-	entry->handle = handle;
-	nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
-
-	if (dev_priv->card_type < NV_40) {
-		ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->addr >> 4) |
-		      (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-		      (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
-	} else
-	if (dev_priv->card_type < NV_50) {
-		ctx = (gpuobj->addr >> 4) |
-		      (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-		      (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
-	} else {
-		if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
-			ctx = (gpuobj->node->offset << 10) |
-			      (chan->id << 28) |
-			      chan->id; /* HASH_TAG */
-		} else {
-			ctx = (gpuobj->node->offset >> 4) |
-			      ((gpuobj->engine <<
-				NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
-		}
-	}
-
-	spin_lock_irqsave(&chan->ramht->lock, flags);
-	list_add(&entry->head, &chan->ramht->entries);
-
-	co = ho = nouveau_ramht_hash_handle(chan, handle);
+	co = ho = nouveau_ramht_hash(ramht, chid, handle);
 	do {
-		if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
-			NV_DEBUG(dev,
-				 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-				 chan->id, co, handle, ctx);
+		if (!nv_ro32(ramht, co + 4)) {
 			nv_wo32(ramht, co + 0, handle);
-			nv_wo32(ramht, co + 4, ctx);
-
-			spin_unlock_irqrestore(&chan->ramht->lock, flags);
-			nvimem_flush(dev);
-			return 0;
+			nv_wo32(ramht, co + 4, context);
+			if (bar)
+				bar->flush(bar);
+			return co;
 		}
-		NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
-			 chan->id, co, nv_ro32(ramht, co));
 
 		co += 8;
-		if (co >= ramht->size)
+		if (co >= nv_gpuobj(ramht)->size)
 			co = 0;
 	} while (co != ho);
 
-	NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
-	list_del(&entry->head);
-	spin_unlock_irqrestore(&chan->ramht->lock, flags);
-	kfree(entry);
 	return -ENOMEM;
 }
 
-static struct nouveau_ramht_entry *
-nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
-{
-	struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
-	struct nouveau_ramht_entry *entry;
-	unsigned long flags;
-
-	if (!ramht)
-		return NULL;
-
-	spin_lock_irqsave(&ramht->lock, flags);
-	list_for_each_entry(entry, &ramht->entries, head) {
-		if (entry->channel == chan &&
-		    (!handle || entry->handle == handle)) {
-			list_del(&entry->head);
-			spin_unlock_irqrestore(&ramht->lock, flags);
-
-			return entry;
-		}
-	}
-	spin_unlock_irqrestore(&ramht->lock, flags);
-
-	return NULL;
-}
-
-static void
-nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
-	unsigned long flags;
-	u32 co, ho;
-
-	spin_lock_irqsave(&chan->ramht->lock, flags);
-	co = ho = nouveau_ramht_hash_handle(chan, handle);
-	do {
-		if (nouveau_ramht_entry_valid(dev, ramht, co) &&
-		    nouveau_ramht_entry_same_channel(chan, ramht, co) &&
-		    (handle == nv_ro32(ramht, co))) {
-			NV_DEBUG(dev,
-				 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-				 chan->id, co, handle, nv_ro32(ramht, co + 4));
-			nv_wo32(ramht, co + 0, 0x00000000);
-			nv_wo32(ramht, co + 4, 0x00000000);
-			nvimem_flush(dev);
-			goto out;
-		}
-
-		co += 8;
-		if (co >= ramht->size)
-			co = 0;
-	} while (co != ho);
-
-	NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
-		 chan->id, handle);
-out:
-	spin_unlock_irqrestore(&chan->ramht->lock, flags);
-}
-
-int
-nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
-{
-	struct nouveau_ramht_entry *entry;
-
-	entry = nouveau_ramht_remove_entry(chan, handle);
-	if (!entry)
-		return -ENOENT;
-
-	nouveau_ramht_remove_hash(chan, entry->handle);
-	nouveau_gpuobj_ref(NULL, &entry->gpuobj);
-	kfree(entry);
-	return 0;
-}
-
-struct nouveau_gpuobj *
-nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
-{
-	struct nouveau_ramht *ramht = chan->ramht;
-	struct nouveau_ramht_entry *entry;
-	struct nouveau_gpuobj *gpuobj = NULL;
-	unsigned long flags;
-
-	if (unlikely(!chan->ramht))
-		return NULL;
-
-	spin_lock_irqsave(&ramht->lock, flags);
-	list_for_each_entry(entry, &chan->ramht->entries, head) {
-		if (entry->channel == chan && entry->handle == handle) {
-			gpuobj = entry->gpuobj;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&ramht->lock, flags);
-
-	return gpuobj;
-}
-
-int
-nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
-		  struct nouveau_ramht **pramht)
-{
-	struct nouveau_ramht *ramht;
-
-	ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
-	if (!ramht)
-		return -ENOMEM;
-
-	ramht->dev = dev;
-	kref_init(&ramht->refcount);
-	ramht->bits = drm_order(gpuobj->size / 8);
-	INIT_LIST_HEAD(&ramht->entries);
-	spin_lock_init(&ramht->lock);
-	nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
-
-	*pramht = ramht;
-	return 0;
-}
-
-static void
-nouveau_ramht_del(struct kref *ref)
-{
-	struct nouveau_ramht *ramht =
-		container_of(ref, struct nouveau_ramht, refcount);
-
-	nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
-	kfree(ramht);
-}
-
 void
-nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
-		  struct nouveau_channel *chan)
+nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
 {
-	struct nouveau_ramht_entry *entry;
+	struct nouveau_bar *bar = nouveau_bar(ramht);
+	nv_wo32(ramht, cookie + 0, 0x00000000);
+	nv_wo32(ramht, cookie + 4, 0x00000000);
+	if (bar)
+		bar->flush(bar);
+}
+
+static struct nouveau_oclass
+nouveau_ramht_oclass = {
+	.handle = 0x0000abcd,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = NULL,
+		.dtor = _nouveau_gpuobj_dtor,
+		.init = _nouveau_gpuobj_init,
+		.fini = _nouveau_gpuobj_fini,
+		.rd32 = _nouveau_gpuobj_rd32,
+		.wr32 = _nouveau_gpuobj_wr32,
+	},
+};
+
+int
+nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
+		  u32 size, u32 align, struct nouveau_ramht **pramht)
+{
 	struct nouveau_ramht *ramht;
+	int ret;
 
-	if (ref)
-		kref_get(&ref->refcount);
+	ret = nouveau_gpuobj_create(parent, parent->engine ?
+				    parent->engine : parent, /* <nv50 ramht */
+				    &nouveau_ramht_oclass, 0, pargpu, size,
+				    align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+	*pramht = ramht;
+	if (ret)
+		return ret;
 
-	ramht = *ptr;
-	if (ramht) {
-		while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
-			nouveau_ramht_remove_hash(chan, entry->handle);
-			nouveau_gpuobj_ref(NULL, &entry->gpuobj);
-			kfree(entry);
-		}
-
-		kref_put(&ramht->refcount, nouveau_ramht_del);
-	}
-	*ptr = ref;
+	ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3);
+	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
index 4b80931..66f7dfd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,61 +22,154 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 
-/*XXX: This stub is currently used on NV98+ also, as soon as this becomes
- *     more than just an enable/disable stub this needs to be split out to
- *     nv98_bsp.c...
- */
+#include <engine/bsp.h>
 
-struct nv84_bsp_engine {
-	struct nouveau_exec_engine base;
+struct nv84_bsp_priv {
+	struct nouveau_bsp base;
 };
 
-static int
-nv84_bsp_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	if (!(nv_rd32(dev, 0x000200) & 0x00008000))
-		return 0;
+struct nv84_bsp_chan {
+	struct nouveau_bsp_chan base;
+};
 
-	nv_mask(dev, 0x000200, 0x00008000, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * BSP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv84_bsp_sclass[] = {
+	{},
+};
+
+/*******************************************************************************
+ * BSP context
+ ******************************************************************************/
 
 static int
-nv84_bsp_init(struct drm_device *dev, int engine)
+nv84_bsp_context_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
 {
-	nv_mask(dev, 0x000200, 0x00008000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00008000, 0x00008000);
+	struct nv84_bsp_chan *priv;
+	int ret;
+
+	ret = nouveau_bsp_context_create(parent, engine, oclass, NULL,
+					 0, 0, 0, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
 static void
-nv84_bsp_destroy(struct drm_device *dev, int engine)
+nv84_bsp_context_dtor(struct nouveau_object *object)
 {
-	struct nv84_bsp_engine *pbsp = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, BSP);
-
-	kfree(pbsp);
+	struct nv84_bsp_chan *priv = (void *)object;
+	nouveau_bsp_context_destroy(&priv->base);
 }
 
-int
-nv84_bsp_create(struct drm_device *dev)
+static int
+nv84_bsp_context_init(struct nouveau_object *object)
 {
-	struct nv84_bsp_engine *pbsp;
+	struct nv84_bsp_chan *priv = (void *)object;
+	int ret;
 
-	pbsp = kzalloc(sizeof(*pbsp), GFP_KERNEL);
-	if (!pbsp)
-		return -ENOMEM;
+	ret = nouveau_bsp_context_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pbsp->base.destroy = nv84_bsp_destroy;
-	pbsp->base.init = nv84_bsp_init;
-	pbsp->base.fini = nv84_bsp_fini;
-
-	NVOBJ_ENGINE_ADD(dev, BSP, &pbsp->base);
 	return 0;
 }
+
+static int
+nv84_bsp_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv84_bsp_chan *priv = (void *)object;
+	return nouveau_bsp_context_fini(&priv->base, suspend);
+}
+
+static struct nouveau_oclass
+nv84_bsp_cclass = {
+	.handle = NV_ENGCTX(BSP, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_bsp_context_ctor,
+		.dtor = nv84_bsp_context_dtor,
+		.init = nv84_bsp_context_init,
+		.fini = nv84_bsp_context_fini,
+		.rd32 = _nouveau_bsp_context_rd32,
+		.wr32 = _nouveau_bsp_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * BSP engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv84_bsp_intr(struct nouveau_subdev *subdev)
+{
+}
+
+static int
+nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv84_bsp_priv *priv;
+	int ret;
+
+	ret = nouveau_bsp_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x04008000;
+	nv_subdev(priv)->intr = nv84_bsp_intr;
+	nv_engine(priv)->cclass = &nv84_bsp_cclass;
+	nv_engine(priv)->sclass = nv84_bsp_sclass;
+	return 0;
+}
+
+static void
+nv84_bsp_dtor(struct nouveau_object *object)
+{
+	struct nv84_bsp_priv *priv = (void *)object;
+	nouveau_bsp_destroy(&priv->base);
+}
+
+static int
+nv84_bsp_init(struct nouveau_object *object)
+{
+	struct nv84_bsp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_bsp_init(&priv->base);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv84_bsp_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv84_bsp_priv *priv = (void *)object;
+	return nouveau_bsp_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv84_bsp_oclass = {
+	.handle = NV_ENGINE(BSP, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_bsp_ctor,
+		.dtor = nv84_bsp_dtor,
+		.init = nv84_bsp_init,
+		.fini = nv84_bsp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
index 9150c5e..debb828 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,112 +22,75 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+
+#include <engine/copy.h>
+
 #include "fuc/nva3.fuc.h"
 
-struct nva3_copy_engine {
-	struct nouveau_exec_engine base;
+struct nva3_copy_priv {
+	struct nouveau_copy base;
 };
 
+struct nva3_copy_chan {
+	struct nouveau_copy_chan base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nva3_copy_sclass[] = {
+	{ 0x85b5, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PCOPY context
+ ******************************************************************************/
+
 static int
-nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+nva3_copy_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *ramin = chan->ramin;
-	struct nouveau_gpuobj *ctx = NULL;
+	struct nva3_copy_chan *priv;
 	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, &ctx);
+	ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0,
+					  NVOBJ_FLAG_ZERO_ALLOC, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	nv_wo32(ramin, 0xc0, 0x00190000);
-	nv_wo32(ramin, 0xc4, ctx->addr + ctx->size - 1);
-	nv_wo32(ramin, 0xc8, ctx->addr);
-	nv_wo32(ramin, 0xcc, 0x00000000);
-	nv_wo32(ramin, 0xd0, 0x00000000);
-	nv_wo32(ramin, 0xd4, 0x00000000);
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, 1);
-	chan->engctx[engine] = ctx;
 	return 0;
 }
 
-static int
-nva3_copy_object_new(struct nouveau_channel *chan, int engine,
-		     u32 handle, u16 class)
-{
-	struct nouveau_gpuobj *ctx = chan->engctx[engine];
+static struct nouveau_oclass
+nva3_copy_cclass = {
+	.handle = NV_ENGCTX(COPY0, 0xa3),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nva3_copy_context_ctor,
+		.dtor = _nouveau_copy_context_dtor,
+		.init = _nouveau_copy_context_init,
+		.fini = _nouveau_copy_context_fini,
+		.rd32 = _nouveau_copy_context_rd32,
+		.wr32 = _nouveau_copy_context_wr32,
 
-	/* fuc engine doesn't need an object, our ramht code does.. */
-	ctx->engine = 3;
-	ctx->class  = class;
-	return nouveau_ramht_insert(chan, handle, ctx);
-}
+	},
+};
 
-static void
-nva3_copy_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nouveau_gpuobj *ctx = chan->engctx[engine];
-	int i;
-
-	for (i = 0xc0; i <= 0xd4; i += 4)
-		nv_wo32(chan->ramin, i, 0x00000000);
-
-	nvvm_engref(chan->vm, engine, -1);
-	nouveau_gpuobj_ref(NULL, &ctx);
-	chan->engctx[engine] = ctx;
-}
-
-static void
-nva3_copy_tlb_flush(struct drm_device *dev, int engine)
-{
-	nv50_vm_flush_engine(dev, 0x0d);
-}
-
-static int
-nva3_copy_init(struct drm_device *dev, int engine)
-{
-	int i;
-
-	nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
-	nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
-
-	/* upload ucode */
-	nv_wr32(dev, 0x1041c0, 0x01000000);
-	for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
-		nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
-
-	nv_wr32(dev, 0x104180, 0x01000000);
-	for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, 0x104188, i >> 6);
-		nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
-	}
-
-	/* start it running */
-	nv_wr32(dev, 0x10410c, 0x00000000);
-	nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
-	nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
-	return 0;
-}
-
-static int
-nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
-	nv_wr32(dev, 0x104014, 0xffffffff);
-	return 0;
-}
+/*******************************************************************************
+ * PCOPY engine/subdev functions
+ ******************************************************************************/
 
 static struct nouveau_enum nva3_copy_isr_error_name[] = {
 	{ 0x0001, "ILLEGAL_MTHD" },
@@ -137,65 +100,114 @@
 };
 
 static void
-nva3_copy_isr(struct drm_device *dev)
+nva3_copy_intr(struct nouveau_subdev *subdev)
 {
-	u32 dispatch = nv_rd32(dev, 0x10401c);
-	u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
-	u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
-	u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
-	u32 addr = nv_rd32(dev, 0x104040) >> 16;
+	struct nva3_copy_priv *priv = (void *)subdev;
+	u32 dispatch = nv_rd32(priv, 0x10401c);
+	u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16);
+	u32 inst = nv_rd32(priv, 0x104050) & 0x3fffffff;
+	u32 ssta = nv_rd32(priv, 0x104040) & 0x0000ffff;
+	u32 addr = nv_rd32(priv, 0x104040) >> 16;
 	u32 mthd = (addr & 0x07ff) << 2;
 	u32 subc = (addr & 0x3800) >> 11;
-	u32 data = nv_rd32(dev, 0x104044);
-	int chid = nv50_graph_isr_chid(dev, inst);
+	u32 data = nv_rd32(priv, 0x104044);
 
 	if (stat & 0x00000040) {
-		NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+		nv_error(priv, "DISPATCH_ERROR [");
 		nouveau_enum_print(nva3_copy_isr_error_name, ssta);
-		printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, mthd, data);
-		nv_wr32(dev, 0x104004, 0x00000040);
+		printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n",
+		       inst, subc, mthd, data);
+		nv_wr32(priv, 0x104004, 0x00000040);
 		stat &= ~0x00000040;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
-		nv_wr32(dev, 0x104004, stat);
+		nv_error(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x104004, stat);
 	}
-	nv50_fb_vm_trap(dev, 1);
+
+	nv50_fb_trap(nouveau_fb(priv), 1);
 }
 
-static void
-nva3_copy_destroy(struct drm_device *dev, int engine)
+static int
+nva3_copy_tlb_flush(struct nouveau_engine *engine)
 {
-	struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 22);
-
-	NVOBJ_ENGINE_DEL(dev, COPY0);
-	kfree(pcopy);
-}
-
-int
-nva3_copy_create(struct drm_device *dev)
-{
-	struct nva3_copy_engine *pcopy;
-
-	pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
-	if (!pcopy)
-		return -ENOMEM;
-
-	pcopy->base.destroy = nva3_copy_destroy;
-	pcopy->base.init = nva3_copy_init;
-	pcopy->base.fini = nva3_copy_fini;
-	pcopy->base.context_new = nva3_copy_context_new;
-	pcopy->base.context_del = nva3_copy_context_del;
-	pcopy->base.object_new = nva3_copy_object_new;
-	pcopy->base.tlb_flush = nva3_copy_tlb_flush;
-
-	nouveau_irq_register(dev, 22, nva3_copy_isr);
-
-	NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
-	NVOBJ_CLASS(dev, 0x85b5, COPY0);
+	nv50_vm_flush_engine(&engine->base, 0x0d);
 	return 0;
 }
+
+static int
+nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	bool enable = (nv_device(parent)->chipset != 0xaf);
+	struct nva3_copy_priv *priv;
+	int ret;
+
+	ret = nouveau_copy_create(parent, engine, oclass, enable, 0, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00802000;
+	nv_subdev(priv)->intr = nva3_copy_intr;
+	nv_engine(priv)->cclass = &nva3_copy_cclass;
+	nv_engine(priv)->sclass = nva3_copy_sclass;
+	nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
+	return 0;
+}
+
+static int
+nva3_copy_init(struct nouveau_object *object)
+{
+	struct nva3_copy_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nouveau_copy_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* disable all interrupts */
+	nv_wr32(priv, 0x104014, 0xffffffff);
+
+	/* upload ucode */
+	nv_wr32(priv, 0x1041c0, 0x01000000);
+	for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+		nv_wr32(priv, 0x1041c4, nva3_pcopy_data[i]);
+
+	nv_wr32(priv, 0x104180, 0x01000000);
+	for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x104188, i >> 6);
+		nv_wr32(priv, 0x104184, nva3_pcopy_code[i]);
+	}
+
+	/* start it running */
+	nv_wr32(priv, 0x10410c, 0x00000000);
+	nv_wr32(priv, 0x104104, 0x00000000); /* ENTRY */
+	nv_wr32(priv, 0x104100, 0x00000002); /* TRIGGER */
+	return 0;
+}
+
+static int
+nva3_copy_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nva3_copy_priv *priv = (void *)object;
+
+	nv_mask(priv, 0x104048, 0x00000003, 0x00000000);
+	nv_wr32(priv, 0x104014, 0xffffffff);
+
+	return nouveau_copy_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nva3_copy_oclass = {
+	.handle = NV_ENGINE(COPY0, 0xa3),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nva3_copy_ctor,
+		.dtor = _nouveau_copy_dtor,
+		.init = nva3_copy_init,
+		.fini = nva3_copy_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
index f39de5a..ecc8faa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,138 +22,86 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <engine/copy.h>
+
 #include "fuc/nvc0.fuc.h"
 
-struct nvc0_copy_engine {
-	struct nouveau_exec_engine base;
-	u32 irq;
-	u32 pmc;
-	u32 fuc;
-	u32 ctx;
+struct nvc0_copy_priv {
+	struct nouveau_copy base;
 };
 
 struct nvc0_copy_chan {
-	struct nouveau_gpuobj *mem;
-	struct nouveau_vma vma;
+	struct nouveau_copy_chan base;
 };
 
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nvc0_copy0_sclass[] = {
+	{ 0x90b5, &nouveau_object_ofuncs },
+	{},
+};
+
+static struct nouveau_oclass
+nvc0_copy1_sclass[] = {
+	{ 0x90b8, &nouveau_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PCOPY context
+ ******************************************************************************/
+
 static int
-nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+nvc0_copy_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
-	struct nvc0_copy_chan *cctx;
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *ramin = chan->ramin;
+	struct nvc0_copy_chan *priv;
 	int ret;
 
-	cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
-	if (!cctx)
-		return -ENOMEM;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
-				 NVOBJ_FLAG_ZERO_ALLOC, &cctx->mem);
+	ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
+					  256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_map_vm(cctx->mem, chan->vm, NV_MEM_ACCESS_RW,
-				   &cctx->vma);
-	if (ret)
-		return ret;
-
-	nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(cctx->vma.offset));
-	nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(cctx->vma.offset));
-	nvimem_flush(dev);
 	return 0;
 }
 
-static int
-nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
-		     u32 handle, u16 class)
-{
-	return 0;
-}
+static struct nouveau_ofuncs
+nvc0_copy_context_ofuncs = {
+	.ctor = nvc0_copy_context_ctor,
+	.dtor = _nouveau_copy_context_dtor,
+	.init = _nouveau_copy_context_init,
+	.fini = _nouveau_copy_context_fini,
+	.rd32 = _nouveau_copy_context_rd32,
+	.wr32 = _nouveau_copy_context_wr32,
+};
 
-static void
-nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
-	struct nvc0_copy_chan *cctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	u32 inst;
+static struct nouveau_oclass
+nvc0_copy0_cclass = {
+	.handle = NV_ENGCTX(COPY0, 0xc0),
+	.ofuncs = &nvc0_copy_context_ofuncs,
+};
 
-	inst  = (chan->ramin->addr >> 12);
-	inst |= 0x40000000;
+static struct nouveau_oclass
+nvc0_copy1_cclass = {
+	.handle = NV_ENGCTX(COPY1, 0xc0),
+	.ofuncs = &nvc0_copy_context_ofuncs,
+};
 
-	/* disable fifo access */
-	nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
-	/* mark channel as unloaded if it's currently active */
-	if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
-		nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
-	/* mark next channel as invalid if it's about to be loaded */
-	if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
-		nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
-	/* restore fifo access */
-	nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
-
-	nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
-	nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
-
-	nouveau_gpuobj_unmap(&cctx->vma);
-	nouveau_gpuobj_ref(NULL, &cctx->mem);
-
-	kfree(cctx);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nvc0_copy_init(struct drm_device *dev, int engine)
-{
-	struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
-	int i;
-
-	nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
-	nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
-	nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
-
-	nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
-		nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
-
-	nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
-		nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
-	}
-
-	nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
-	nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
-	nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
-	nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
-	return 0;
-}
-
-static int
-nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
-
-	nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
-
-	/* trigger fuc context unload */
-	nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
-	nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
-	nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
-	nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
-
-	nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
-	return 0;
-}
+/*******************************************************************************
+ * PCOPY engine/subdev functions
+ ******************************************************************************/
 
 static struct nouveau_enum nvc0_copy_isr_error_name[] = {
 	{ 0x0001, "ILLEGAL_MTHD" },
@@ -163,93 +111,145 @@
 };
 
 static void
-nvc0_copy_isr(struct drm_device *dev, int engine)
+nvc0_copy_intr(struct nouveau_subdev *subdev)
 {
-	struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
-	u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
-	u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
-	u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
-	u32 chid = nvc0_graph_isr_chid(dev, inst);
-	u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
-	u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+	int idx = nv_engidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
+	struct nvc0_copy_priv *priv = (void *)subdev;
+	u32 disp = nv_rd32(priv, 0x10401c + (idx * 0x1000));
+	u32 intr = nv_rd32(priv, 0x104008 + (idx * 0x1000));
+	u32 stat = intr & disp & ~(disp >> 16);
+	u64 inst = nv_rd32(priv, 0x104050 + (idx * 0x1000)) & 0x0fffffff;
+	u32 ssta = nv_rd32(priv, 0x104040 + (idx * 0x1000)) & 0x0000ffff;
+	u32 addr = nv_rd32(priv, 0x104040 + (idx * 0x1000)) >> 16;
 	u32 mthd = (addr & 0x07ff) << 2;
 	u32 subc = (addr & 0x3800) >> 11;
-	u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+	u32 data = nv_rd32(priv, 0x104044 + (idx * 0x1000));
 
 	if (stat & 0x00000040) {
-		NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+		nv_error(priv, "DISPATCH_ERROR [");
 		nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
-		printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, mthd, data);
-		nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+		printk("] ch 0x%010llx subc %d mthd 0x%04x data 0x%08x\n",
+		       (u64)inst << 12, subc, mthd, data);
+		nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040);
 		stat &= ~0x00000040;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
-		nv_wr32(dev, pcopy->fuc + 0x004, stat);
+		nv_error(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x104004 + (idx * 0x1000), stat);
 	}
 }
 
-static void
-nvc0_copy_isr_0(struct drm_device *dev)
+static int
+nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
 {
-	nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
-}
+	struct nvc0_copy_priv *priv;
+	int ret;
 
-static void
-nvc0_copy_isr_1(struct drm_device *dev)
-{
-	nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
-}
+	if (nv_rd32(parent, 0x022500) & 0x00000100)
+		return -ENODEV;
 
-static void
-nvc0_copy_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+	ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	nouveau_irq_unregister(dev, pcopy->irq);
-
-	if (engine == NVOBJ_ENGINE_COPY0)
-		NVOBJ_ENGINE_DEL(dev, COPY0);
-	else
-		NVOBJ_ENGINE_DEL(dev, COPY1);
-	kfree(pcopy);
-}
-
-int
-nvc0_copy_create(struct drm_device *dev, int engine)
-{
-	struct nvc0_copy_engine *pcopy;
-
-	pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
-	if (!pcopy)
-		return -ENOMEM;
-
-	pcopy->base.destroy = nvc0_copy_destroy;
-	pcopy->base.init = nvc0_copy_init;
-	pcopy->base.fini = nvc0_copy_fini;
-	pcopy->base.context_new = nvc0_copy_context_new;
-	pcopy->base.context_del = nvc0_copy_context_del;
-	pcopy->base.object_new = nvc0_copy_object_new;
-
-	if (engine == 0) {
-		pcopy->irq = 5;
-		pcopy->pmc = 0x00000040;
-		pcopy->fuc = 0x104000;
-		pcopy->ctx = 0x0230;
-		nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
-		NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
-		NVOBJ_CLASS(dev, 0x90b5, COPY0);
-	} else {
-		pcopy->irq = 6;
-		pcopy->pmc = 0x00000080;
-		pcopy->fuc = 0x105000;
-		pcopy->ctx = 0x0240;
-		nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
-		NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
-		NVOBJ_CLASS(dev, 0x90b8, COPY1);
-	}
-
+	nv_subdev(priv)->unit = 0x00000040;
+	nv_subdev(priv)->intr = nvc0_copy_intr;
+	nv_engine(priv)->cclass = &nvc0_copy0_cclass;
+	nv_engine(priv)->sclass = nvc0_copy0_sclass;
 	return 0;
 }
+
+static int
+nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nvc0_copy_priv *priv;
+	int ret;
+
+	if (nv_rd32(parent, 0x022500) & 0x00000200)
+		return -ENODEV;
+
+	ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000080;
+	nv_subdev(priv)->intr = nvc0_copy_intr;
+	nv_engine(priv)->cclass = &nvc0_copy1_cclass;
+	nv_engine(priv)->sclass = nvc0_copy1_sclass;
+	return 0;
+}
+
+static int
+nvc0_copy_init(struct nouveau_object *object)
+{
+	int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
+	struct nvc0_copy_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nouveau_copy_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* disable all interrupts */
+	nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
+
+	/* upload ucode */
+	nv_wr32(priv, 0x1041c0 + (idx * 0x1000), 0x01000000);
+	for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+		nv_wr32(priv, 0x1041c4 + (idx * 0x1000), nvc0_pcopy_data[i]);
+
+	nv_wr32(priv, 0x104180 + (idx * 0x1000), 0x01000000);
+	for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x104188 + (idx * 0x1000), i >> 6);
+		nv_wr32(priv, 0x104184 + (idx * 0x1000), nvc0_pcopy_code[i]);
+	}
+
+	/* start it running */
+	nv_wr32(priv, 0x104084 + (idx * 0x1000), idx);
+	nv_wr32(priv, 0x10410c + (idx * 0x1000), 0x00000000);
+	nv_wr32(priv, 0x104104 + (idx * 0x1000), 0x00000000); /* ENTRY */
+	nv_wr32(priv, 0x104100 + (idx * 0x1000), 0x00000002); /* TRIGGER */
+	return 0;
+}
+
+static int
+nvc0_copy_fini(struct nouveau_object *object, bool suspend)
+{
+	int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
+	struct nvc0_copy_priv *priv = (void *)object;
+
+	nv_mask(priv, 0x104048 + (idx * 0x1000), 0x00000003, 0x00000000);
+	nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
+
+	return nouveau_copy_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nvc0_copy0_oclass = {
+	.handle = NV_ENGINE(COPY0, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_copy0_ctor,
+		.dtor = _nouveau_copy_dtor,
+		.init = nvc0_copy_init,
+		.fini = nvc0_copy_fini,
+	},
+};
+
+struct nouveau_oclass
+nvc0_copy1_oclass = {
+	.handle = NV_ENGINE(COPY1, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_copy1_ctor,
+		.dtor = _nouveau_copy_dtor,
+		.init = nvc0_copy_init,
+		.fini = nvc0_copy_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
index 63051ab..a0e5e39 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,99 +22,106 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/gpuobj.h>
 
-struct nv84_crypt_engine {
-	struct nouveau_exec_engine base;
+#include <subdev/fb.h>
+
+#include <engine/crypt.h>
+
+struct nv84_crypt_priv {
+	struct nouveau_crypt base;
 };
 
+struct nv84_crypt_chan {
+	struct nouveau_crypt_chan base;
+};
+
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
 static int
-nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
+nv84_crypt_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *ramin = chan->ramin;
-	struct nouveau_gpuobj *ctx;
+	struct nouveau_gpuobj *obj;
 	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, &ctx);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
 
-	nv_wo32(ramin, 0xa0, 0x00190000);
-	nv_wo32(ramin, 0xa4, ctx->addr + ctx->size - 1);
-	nv_wo32(ramin, 0xa8, ctx->addr);
-	nv_wo32(ramin, 0xac, 0);
-	nv_wo32(ramin, 0xb0, 0);
-	nv_wo32(ramin, 0xb4, 0);
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, 1);
-	chan->engctx[engine] = ctx;
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
 	return 0;
 }
 
-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;
+static struct nouveau_ofuncs
+nv84_crypt_ofuncs = {
+	.ctor = nv84_crypt_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
 
-	inst  = (chan->ramin->addr >> 12);
-	inst |= 0x80000000;
+static struct nouveau_oclass
+nv84_crypt_sclass[] = {
+	{ 0x74c1, &nv84_crypt_ofuncs },
+	{}
+};
 
-	/* 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, &ctx);
-
-	nvvm_engref(chan->vm, engine, -1);
-	chan->engctx[engine] = NULL;
-}
+/*******************************************************************************
+ * PCRYPT context
+ ******************************************************************************/
 
 static int
-nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
+nv84_crypt_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
+	struct nv84_crypt_chan *priv;
 	int ret;
 
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+	ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
+					   0, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
-	obj->engine = 5;
-	obj->class  = class;
 
-	nv_wo32(obj, 0x00, class);
-	nvimem_flush(dev);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
+	return 0;
 }
 
-static void
-nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
-{
-	nv50_vm_flush_engine(dev, 0x0a);
-}
+static struct nouveau_oclass
+nv84_crypt_cclass = {
+	.handle = NV_ENGCTX(CRYPT, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_crypt_context_ctor,
+		.dtor = _nouveau_crypt_context_dtor,
+		.init = _nouveau_crypt_context_init,
+		.fini = _nouveau_crypt_context_fini,
+		.rd32 = _nouveau_crypt_context_rd32,
+		.wr32 = _nouveau_crypt_context_wr32,
+	},
+};
 
-static struct nouveau_bitfield nv84_crypt_intr[] = {
+/*******************************************************************************
+ * PCRYPT engine/subdev functions
+ ******************************************************************************/
+
+static struct nouveau_bitfield nv84_crypt_intr_mask[] = {
 	{ 0x00000001, "INVALID_STATE" },
 	{ 0x00000002, "ILLEGAL_MTHD" },
 	{ 0x00000004, "ILLEGAL_CLASS" },
@@ -124,79 +131,78 @@
 };
 
 static void
-nv84_crypt_isr(struct drm_device *dev)
+nv84_crypt_intr(struct nouveau_subdev *subdev)
 {
-	u32 stat = nv_rd32(dev, 0x102130);
-	u32 mthd = nv_rd32(dev, 0x102190);
-	u32 data = nv_rd32(dev, 0x102194);
-	u64 inst = (u64)(nv_rd32(dev, 0x102188) & 0x7fffffff) << 12;
-	int show = nouveau_ratelimit();
-	int chid = nv50_graph_isr_chid(dev, inst);
+	struct nv84_crypt_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x102130);
+	u32 mthd = nv_rd32(priv, 0x102190);
+	u32 data = nv_rd32(priv, 0x102194);
+	u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
 
-	if (show) {
-		NV_INFO(dev, "PCRYPT:");
-		nouveau_bitfield_print(nv84_crypt_intr, stat);
-		printk(KERN_CONT " ch %d (0x%010llx) mthd 0x%04x data 0x%08x\n",
-			chid, inst, mthd, data);
+	if (stat) {
+		nv_error(priv, "");
+		nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
+		printk(" ch 0x%010llx mthd 0x%04x data 0x%08x\n",
+		       (u64)inst << 12, mthd, data);
 	}
 
-	nv_wr32(dev, 0x102130, stat);
-	nv_wr32(dev, 0x10200c, 0x10);
+	nv_wr32(priv, 0x102130, stat);
+	nv_wr32(priv, 0x10200c, 0x10);
 
-	nv50_fb_vm_trap(dev, show);
+	nv50_fb_trap(nouveau_fb(priv), 1);
 }
 
 static int
-nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend)
+nv84_crypt_tlb_flush(struct nouveau_engine *engine)
 {
-	nv_wr32(dev, 0x102140, 0x00000000);
+	nv50_vm_flush_engine(&engine->base, 0x0a);
 	return 0;
 }
 
 static int
-nv84_crypt_init(struct drm_device *dev, int engine)
+nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+	struct nv84_crypt_priv *priv;
+	int ret;
 
-	nv_wr32(dev, 0x102130, 0xffffffff);
-	nv_wr32(dev, 0x102140, 0xffffffbf);
+	ret = nouveau_crypt_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, 0x10200c, 0x00000010);
+	nv_subdev(priv)->unit = 0x00004000;
+	nv_subdev(priv)->intr = nv84_crypt_intr;
+	nv_engine(priv)->cclass = &nv84_crypt_cclass;
+	nv_engine(priv)->sclass = nv84_crypt_sclass;
+	nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush;
 	return 0;
 }
 
-static void
-nv84_crypt_destroy(struct drm_device *dev, int engine)
+static int
+nv84_crypt_init(struct nouveau_object *object)
 {
-	struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+	struct nv84_crypt_priv *priv = (void *)object;
+	int ret;
 
-	NVOBJ_ENGINE_DEL(dev, CRYPT);
+	ret = nouveau_crypt_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nouveau_irq_unregister(dev, 14);
-	kfree(pcrypt);
-}
-
-int
-nv84_crypt_create(struct drm_device *dev)
-{
-	struct nv84_crypt_engine *pcrypt;
-
-	pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
-	if (!pcrypt)
-		return -ENOMEM;
-
-	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;
-
-	nouveau_irq_register(dev, 14, nv84_crypt_isr);
-
-	NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
-	NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+	nv_wr32(priv, 0x102130, 0xffffffff);
+	nv_wr32(priv, 0x102140, 0xffffffbf);
+	nv_wr32(priv, 0x10200c, 0x00000010);
 	return 0;
 }
+
+struct nouveau_oclass
+nv84_crypt_oclass = {
+	.handle = NV_ENGINE(CRYPT, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_crypt_ctor,
+		.dtor = _nouveau_crypt_dtor,
+		.init = nv84_crypt_init,
+		.fini = _nouveau_crypt_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
index c9adc1b..559a1b1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,124 +22,74 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
+#include <core/os.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/engctx.h>
 
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/crypt.h>
 
 #include "fuc/nv98.fuc.h"
 
 struct nv98_crypt_priv {
-	struct nouveau_exec_engine base;
+	struct nouveau_crypt base;
 };
 
 struct nv98_crypt_chan {
-	struct nouveau_gpuobj *mem;
+	struct nouveau_crypt_chan base;
 };
 
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_crypt_sclass[] = {
+	{ 0x88b4, &nouveau_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PCRYPT context
+ ******************************************************************************/
+
 static int
-nv98_crypt_context_new(struct nouveau_channel *chan, int engine)
+nv98_crypt_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nv98_crypt_priv *priv = nv_engine(dev, engine);
-	struct nv98_crypt_chan *cctx;
+	struct nv98_crypt_chan *priv;
 	int ret;
 
-	cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
-	if (!cctx)
-		return -ENOMEM;
-
-	nvvm_engref(chan->vm, engine, 1);
-
-	ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &cctx->mem);
+	ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
+					   256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
-		goto error;
+		return ret;
 
-	nv_wo32(chan->ramin, 0xa0, 0x00190000);
-	nv_wo32(chan->ramin, 0xa4, cctx->mem->addr + cctx->mem->size - 1);
-	nv_wo32(chan->ramin, 0xa8, cctx->mem->addr);
-	nv_wo32(chan->ramin, 0xac, 0x00000000);
-	nv_wo32(chan->ramin, 0xb0, 0x00000000);
-	nv_wo32(chan->ramin, 0xb4, 0x00000000);
-	nvimem_flush(dev);
-
-error:
-	if (ret)
-		priv->base.context_del(chan, engine);
-	return ret;
-}
-
-static void
-nv98_crypt_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv98_crypt_chan *cctx = chan->engctx[engine];
-	int i;
-
-	for (i = 0xa0; i < 0xb4; i += 4)
-		nv_wo32(chan->ramin, i, 0x00000000);
-
-	nouveau_gpuobj_ref(NULL, &cctx->mem);
-
-	nvvm_engref(chan->vm, engine, -1);
-	chan->engctx[engine] = NULL;
-	kfree(cctx);
-}
-
-static int
-nv98_crypt_object_new(struct nouveau_channel *chan, int engine,
-		     u32 handle, u16 class)
-{
-	struct nv98_crypt_chan *cctx = chan->engctx[engine];
-
-	/* fuc engine doesn't need an object, our ramht code does.. */
-	cctx->mem->engine = 5;
-	cctx->mem->class  = class;
-	return nouveau_ramht_insert(chan, handle, cctx->mem);
-}
-
-static void
-nv98_crypt_tlb_flush(struct drm_device *dev, int engine)
-{
-	nv50_vm_flush_engine(dev, 0x0a);
-}
-
-static int
-nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
 	return 0;
 }
 
-static int
-nv98_crypt_init(struct drm_device *dev, int engine)
-{
-	int i;
+static struct nouveau_oclass
+nv98_crypt_cclass = {
+	.handle = NV_ENGCTX(CRYPT, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_crypt_context_ctor,
+		.dtor = _nouveau_crypt_context_dtor,
+		.init = _nouveau_crypt_context_init,
+		.fini = _nouveau_crypt_context_fini,
+		.rd32 = _nouveau_crypt_context_rd32,
+		.wr32 = _nouveau_crypt_context_wr32,
+	},
+};
 
-	/* reset! */
-	nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
-
-	/* wait for exit interrupt to signal */
-	nv_wait(dev, 0x087008, 0x00000010, 0x00000010);
-	nv_wr32(dev, 0x087004, 0x00000010);
-
-	/* upload microcode code and data segments */
-	nv_wr32(dev, 0x087ff8, 0x00100000);
-	for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
-		nv_wr32(dev, 0x087ff4, nv98_pcrypt_code[i]);
-
-	nv_wr32(dev, 0x087ff8, 0x00000000);
-	for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
-		nv_wr32(dev, 0x087ff4, nv98_pcrypt_data[i]);
-
-	/* start it running */
-	nv_wr32(dev, 0x08710c, 0x00000000);
-	nv_wr32(dev, 0x087104, 0x00000000); /* ENTRY */
-	nv_wr32(dev, 0x087100, 0x00000002); /* TRIGGER */
-	return 0;
-}
+/*******************************************************************************
+ * PCRYPT engine/subdev functions
+ ******************************************************************************/
 
 static struct nouveau_enum nv98_crypt_isr_error_name[] = {
 	{ 0x0000, "ILLEGAL_MTHD" },
@@ -150,65 +100,100 @@
 };
 
 static void
-nv98_crypt_isr(struct drm_device *dev)
+nv98_crypt_intr(struct nouveau_subdev *subdev)
 {
-	u32 disp = nv_rd32(dev, 0x08701c);
-	u32 stat = nv_rd32(dev, 0x087008) & disp & ~(disp >> 16);
-	u32 inst = nv_rd32(dev, 0x087050) & 0x3fffffff;
-	u32 ssta = nv_rd32(dev, 0x087040) & 0x0000ffff;
-	u32 addr = nv_rd32(dev, 0x087040) >> 16;
+	struct nv98_crypt_priv *priv = (void *)subdev;
+	u32 disp = nv_rd32(priv, 0x08701c);
+	u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
+	u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
+	u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
+	u32 addr = nv_rd32(priv, 0x087040) >> 16;
 	u32 mthd = (addr & 0x07ff) << 2;
 	u32 subc = (addr & 0x3800) >> 11;
-	u32 data = nv_rd32(dev, 0x087044);
-	int chid = nv50_graph_isr_chid(dev, inst);
+	u32 data = nv_rd32(priv, 0x087044);
 
 	if (stat & 0x00000040) {
-		NV_INFO(dev, "PCRYPT: DISPATCH_ERROR [");
+		nv_error(priv, "DISPATCH_ERROR [");
 		nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
-		printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, mthd, data);
-		nv_wr32(dev, 0x087004, 0x00000040);
+		printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n",
+		       inst, subc, mthd, data);
+		nv_wr32(priv, 0x087004, 0x00000040);
 		stat &= ~0x00000040;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PCRYPT: unhandled intr 0x%08x\n", stat);
-		nv_wr32(dev, 0x087004, stat);
+		nv_error(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x087004, stat);
 	}
 
-	nv50_fb_vm_trap(dev, 1);
+	nv50_fb_trap(nouveau_fb(priv), 1);
 }
 
-static void
-nv98_crypt_destroy(struct drm_device *dev, int engine)
+static int
+nv98_crypt_tlb_flush(struct nouveau_engine *engine)
 {
-	struct nv98_crypt_priv *priv = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 14);
-	NVOBJ_ENGINE_DEL(dev, CRYPT);
-	kfree(priv);
-}
-
-int
-nv98_crypt_create(struct drm_device *dev)
-{
-	struct nv98_crypt_priv *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.destroy = nv98_crypt_destroy;
-	priv->base.init = nv98_crypt_init;
-	priv->base.fini = nv98_crypt_fini;
-	priv->base.context_new = nv98_crypt_context_new;
-	priv->base.context_del = nv98_crypt_context_del;
-	priv->base.object_new = nv98_crypt_object_new;
-	priv->base.tlb_flush = nv98_crypt_tlb_flush;
-
-	nouveau_irq_register(dev, 14, nv98_crypt_isr);
-
-	NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base);
-	NVOBJ_CLASS(dev, 0x88b4, CRYPT);
+	nv50_vm_flush_engine(&engine->base, 0x0a);
 	return 0;
 }
+
+static int
+nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv98_crypt_priv *priv;
+	int ret;
+
+	ret = nouveau_crypt_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00004000;
+	nv_subdev(priv)->intr = nv98_crypt_intr;
+	nv_engine(priv)->cclass = &nv98_crypt_cclass;
+	nv_engine(priv)->sclass = nv98_crypt_sclass;
+	nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
+	return 0;
+}
+
+static int
+nv98_crypt_init(struct nouveau_object *object)
+{
+	struct nv98_crypt_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nouveau_crypt_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* wait for exit interrupt to signal */
+	nv_wait(priv, 0x087008, 0x00000010, 0x00000010);
+	nv_wr32(priv, 0x087004, 0x00000010);
+
+	/* upload microcode code and data segments */
+	nv_wr32(priv, 0x087ff8, 0x00100000);
+	for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
+		nv_wr32(priv, 0x087ff4, nv98_pcrypt_code[i]);
+
+	nv_wr32(priv, 0x087ff8, 0x00000000);
+	for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
+		nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]);
+
+	/* start it running */
+	nv_wr32(priv, 0x08710c, 0x00000000);
+	nv_wr32(priv, 0x087104, 0x00000000); /* ENTRY */
+	nv_wr32(priv, 0x087100, 0x00000002); /* TRIGGER */
+	return 0;
+}
+
+struct nouveau_oclass
+nv98_crypt_oclass = {
+	.handle = NV_ENGINE(CRYPT, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_crypt_ctor,
+		.dtor = _nouveau_crypt_dtor,
+		.init = nv98_crypt_init,
+		.fini = _nouveau_crypt_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
new file mode 100644
index 0000000..1c919f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 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 <engine/disp.h>
+
+struct nv04_disp_priv {
+	struct nouveau_disp base;
+};
+
+static struct nouveau_oclass
+nv04_disp_sclass[] = {
+	{},
+};
+
+static void
+nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
+{
+	struct nouveau_disp *disp = &priv->base;
+	if (disp->vblank.notify)
+		disp->vblank.notify(disp->vblank.data, crtc);
+}
+
+static void
+nv04_disp_intr(struct nouveau_subdev *subdev)
+{
+	struct nv04_disp_priv *priv = (void *)subdev;
+	u32 crtc0 = nv_rd32(priv, 0x600100);
+	u32 crtc1 = nv_rd32(priv, 0x602100);
+
+	if (crtc0 & 0x00000001) {
+		nv04_disp_intr_vblank(priv, 0);
+		nv_wr32(priv, 0x600100, 0x00000001);
+	}
+
+	if (crtc1 & 0x00000001) {
+		nv04_disp_intr_vblank(priv, 1);
+		nv_wr32(priv, 0x602100, 0x00000001);
+	}
+}
+
+static int
+nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nv04_disp_priv *priv;
+	int ret;
+
+	ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
+				  "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = nv04_disp_sclass;
+	nv_subdev(priv)->intr = nv04_disp_intr;
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_disp_oclass = {
+	.handle = NV_ENGINE(DISP, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_disp_ctor,
+		.dtor = _nouveau_disp_dtor,
+		.init = _nouveau_disp_init,
+		.fini = _nouveau_disp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
new file mode 100644
index 0000000..16a9afb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 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 <engine/software.h>
+#include <engine/disp.h>
+
+struct nv50_disp_priv {
+	struct nouveau_disp base;
+};
+
+static struct nouveau_oclass
+nv50_disp_sclass[] = {
+	{},
+};
+
+static void
+nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
+{
+	struct nouveau_disp *disp = &priv->base;
+	struct nouveau_software_chan *chan, *temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&disp->vblank.lock, flags);
+	list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
+		if (chan->vblank.crtc != crtc)
+			continue;
+
+		nv_wr32(priv, 0x001704, chan->vblank.channel);
+		nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+
+		if (nv_device(priv)->chipset == 0x50) {
+			nv_wr32(priv, 0x001570, chan->vblank.offset);
+			nv_wr32(priv, 0x001574, chan->vblank.value);
+		} else {
+			if (nv_device(priv)->chipset >= 0xc0) {
+				nv_wr32(priv, 0x06000c,
+					upper_32_bits(chan->vblank.offset));
+			}
+			nv_wr32(priv, 0x060010, chan->vblank.offset);
+			nv_wr32(priv, 0x060014, chan->vblank.value);
+		}
+
+		list_del(&chan->vblank.head);
+		if (disp->vblank.put)
+			disp->vblank.put(disp->vblank.data, crtc);
+	}
+	spin_unlock_irqrestore(&disp->vblank.lock, flags);
+
+	if (disp->vblank.notify)
+		disp->vblank.notify(disp->vblank.data, crtc);
+}
+
+static void
+nv50_disp_intr(struct nouveau_subdev *subdev)
+{
+	struct nv50_disp_priv *priv = (void *)subdev;
+	u32 stat1 = nv_rd32(priv, 0x610024);
+
+	if (stat1 & 0x00000004) {
+		nv50_disp_intr_vblank(priv, 0);
+		nv_wr32(priv, 0x610024, 0x00000004);
+		stat1 &= ~0x00000004;
+	}
+
+	if (stat1 & 0x00000008) {
+		nv50_disp_intr_vblank(priv, 1);
+		nv_wr32(priv, 0x610024, 0x00000008);
+		stat1 &= ~0x00000008;
+	}
+
+}
+
+static int
+nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+				  "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = nv50_disp_sclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+
+	INIT_LIST_HEAD(&priv->base.vblank.list);
+	spin_lock_init(&priv->base.vblank.lock);
+	return 0;
+}
+
+struct nouveau_oclass
+nv50_disp_oclass = {
+	.handle = NV_ENGINE(DISP, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_disp_ctor,
+		.dtor = _nouveau_disp_dtor,
+		.init = _nouveau_disp_init,
+		.fini = _nouveau_disp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
new file mode 100644
index 0000000..d93efbc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012 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 <subdev/bar.h>
+
+#include <engine/software.h>
+#include <engine/disp.h>
+
+struct nvd0_disp_priv {
+	struct nouveau_disp base;
+};
+
+static struct nouveau_oclass
+nvd0_disp_sclass[] = {
+	{},
+};
+
+static void
+nvd0_disp_intr_vblank(struct nvd0_disp_priv *priv, int crtc)
+{
+	struct nouveau_bar *bar = nouveau_bar(priv);
+	struct nouveau_disp *disp = &priv->base;
+	struct nouveau_software_chan *chan, *temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&disp->vblank.lock, flags);
+	list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
+		if (chan->vblank.crtc != crtc)
+			continue;
+
+		nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
+		bar->flush(bar);
+		nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
+		nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
+		nv_wr32(priv, 0x060014, chan->vblank.value);
+
+		list_del(&chan->vblank.head);
+		if (disp->vblank.put)
+			disp->vblank.put(disp->vblank.data, crtc);
+	}
+	spin_unlock_irqrestore(&disp->vblank.lock, flags);
+
+	if (disp->vblank.notify)
+		disp->vblank.notify(disp->vblank.data, crtc);
+}
+
+static void
+nvd0_disp_intr(struct nouveau_subdev *subdev)
+{
+	struct nvd0_disp_priv *priv = (void *)subdev;
+	u32 intr = nv_rd32(priv, 0x610088);
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		u32 mask = 0x01000000 << i;
+		if (mask & intr) {
+			u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
+			if (stat & 0x00000001)
+				nvd0_disp_intr_vblank(priv, i);
+			nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
+			nv_rd32(priv, 0x6100c0 + (i * 0x800));
+		}
+	}
+}
+
+static int
+nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nvd0_disp_priv *priv;
+	int ret;
+
+	ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
+				  "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = nvd0_disp_sclass;
+	nv_subdev(priv)->intr = nvd0_disp_intr;
+
+	INIT_LIST_HEAD(&priv->base.vblank.list);
+	spin_lock_init(&priv->base.vblank.lock);
+	return 0;
+}
+
+struct nouveau_oclass
+nvd0_disp_oclass = {
+	.handle = NV_ENGINE(DISP, 0xd0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvd0_disp_ctor,
+		.dtor = _nouveau_disp_dtor,
+		.init = _nouveau_disp_init,
+		.fini = _nouveau_disp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
new file mode 100644
index 0000000..e1f013d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 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 <core/object.h>
+#include <core/class.h>
+
+#include <subdev/fb.h>
+#include <engine/dmaobj.h>
+
+int
+nouveau_dmaobj_create_(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass,
+		       void *data, u32 size, int len, void **pobject)
+{
+	struct nv_dma_class *args = data;
+	struct nouveau_dmaobj *object;
+	int ret;
+
+	if (size < sizeof(*args))
+		return -EINVAL;
+
+	ret = nouveau_object_create_(parent, engine, oclass, 0, len, pobject);
+	object = *pobject;
+	if (ret)
+		return ret;
+
+	switch (args->flags & NV_DMA_TARGET_MASK) {
+	case NV_DMA_TARGET_VM:
+		object->target = NV_MEM_TARGET_VM;
+		break;
+	case NV_DMA_TARGET_VRAM:
+		object->target = NV_MEM_TARGET_VRAM;
+		break;
+	case NV_DMA_TARGET_PCI:
+		object->target = NV_MEM_TARGET_PCI;
+		break;
+	case NV_DMA_TARGET_PCI_US:
+	case NV_DMA_TARGET_AGP:
+		object->target = NV_MEM_TARGET_PCI_NOSNOOP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (args->flags & NV_DMA_ACCESS_MASK) {
+	case NV_DMA_ACCESS_VM:
+		object->access = NV_MEM_ACCESS_VM;
+		break;
+	case NV_DMA_ACCESS_RD:
+		object->access = NV_MEM_ACCESS_RO;
+		break;
+	case NV_DMA_ACCESS_WR:
+		object->access = NV_MEM_ACCESS_WO;
+		break;
+	case NV_DMA_ACCESS_RDWR:
+		object->access = NV_MEM_ACCESS_RW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	object->start = args->start;
+	object->limit = args->limit;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
new file mode 100644
index 0000000..b0d3651
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 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 <core/gpuobj.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm/nv04.h>
+
+#include <engine/dmaobj.h>
+
+struct nv04_dmaeng_priv {
+	struct nouveau_dmaeng base;
+};
+
+struct nv04_dmaobj_priv {
+	struct nouveau_dmaobj base;
+};
+
+static int
+nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
+		 struct nouveau_object *parent,
+		 struct nouveau_dmaobj *dmaobj,
+		 struct nouveau_gpuobj **pgpuobj)
+{
+	struct nouveau_gpuobj *gpuobj;
+	u32 flags0 = nv_mclass(dmaobj);
+	u32 flags2 = 0x00000000;
+	u32 offset = (dmaobj->start & 0xfffff000);
+	u32 adjust = (dmaobj->start & 0x00000fff);
+	u32 length = dmaobj->limit - dmaobj->start;
+	int ret;
+
+	if (dmaobj->target == NV_MEM_TARGET_VM) {
+		gpuobj = nv04_vmmgr(dmaeng)->vm->pgt[0].obj[0];
+		if (dmaobj->start == 0)
+			return nouveau_gpuobj_dup(parent, gpuobj, pgpuobj);
+
+		offset  = nv_ro32(gpuobj, 8 + (offset >> 10));
+		offset &= 0xfffff000;
+		dmaobj->target = NV_MEM_TARGET_PCI;
+		dmaobj->access = NV_MEM_ACCESS_RW;
+	}
+
+	switch (dmaobj->target) {
+	case NV_MEM_TARGET_VRAM:
+		flags0 |= 0x00003000;
+		break;
+	case NV_MEM_TARGET_PCI:
+		flags0 |= 0x00023000;
+		break;
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		flags0 |= 0x00033000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dmaobj->access) {
+	case NV_MEM_ACCESS_RO:
+		flags0 |= 0x00004000;
+		break;
+	case NV_MEM_ACCESS_WO:
+		flags0 |= 0x00008000;
+	case NV_MEM_ACCESS_RW:
+		flags2 |= 0x00000002;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
+	*pgpuobj = gpuobj;
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20));
+		nv_wo32(*pgpuobj, 0x04, length);
+		nv_wo32(*pgpuobj, 0x08, flags2 | offset);
+		nv_wo32(*pgpuobj, 0x0c, flags2 | offset);
+	}
+
+	return ret;
+}
+
+static int
+nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nouveau_dmaeng *dmaeng = (void *)engine;
+	struct nv04_dmaobj_priv *dmaobj;
+	struct nouveau_gpuobj *gpuobj;
+	int ret;
+
+	ret = nouveau_dmaobj_create(parent, engine, oclass,
+				    data, size, &dmaobj);
+	*pobject = nv_object(dmaobj);
+	if (ret)
+		return ret;
+
+	switch (nv_mclass(parent)) {
+	case 0x006e:
+		ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
+		nouveau_object_ref(NULL, pobject);
+		*pobject = nv_object(gpuobj);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct nouveau_ofuncs
+nv04_dmaobj_ofuncs = {
+	.ctor = nv04_dmaobj_ctor,
+	.dtor = _nouveau_dmaobj_dtor,
+	.init = _nouveau_dmaobj_init,
+	.fini = _nouveau_dmaobj_fini,
+};
+
+static struct nouveau_oclass
+nv04_dmaobj_sclass[] = {
+	{ 0x0002, &nv04_dmaobj_ofuncs },
+	{ 0x0003, &nv04_dmaobj_ofuncs },
+	{ 0x003d, &nv04_dmaobj_ofuncs },
+	{}
+};
+
+static int
+nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nv04_dmaeng_priv *priv;
+	int ret;
+
+	ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.sclass = nv04_dmaobj_sclass;
+	priv->base.bind = nv04_dmaobj_bind;
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_dmaeng_oclass = {
+	.handle = NV_ENGINE(DMAOBJ, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_dmaeng_ctor,
+		.dtor = _nouveau_dmaeng_dtor,
+		.init = _nouveau_dmaeng_init,
+		.fini = _nouveau_dmaeng_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
new file mode 100644
index 0000000..8207ac9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2012 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 <core/gpuobj.h>
+
+#include <subdev/fb.h>
+#include <engine/dmaobj.h>
+
+struct nv50_dmaeng_priv {
+	struct nouveau_dmaeng base;
+};
+
+struct nv50_dmaobj_priv {
+	struct nouveau_dmaobj base;
+};
+
+static int
+nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
+		 struct nouveau_object *parent,
+		 struct nouveau_dmaobj *dmaobj,
+		 struct nouveau_gpuobj **pgpuobj)
+{
+	u32 flags = nv_mclass(dmaobj);
+	int ret;
+
+	switch (dmaobj->target) {
+	case NV_MEM_TARGET_VM:
+		flags |= 0x00000000;
+		flags |= 0x60000000; /* COMPRESSION_USEVM */
+		flags |= 0x1fc00000; /* STORAGE_TYPE_USEVM */
+		break;
+	case NV_MEM_TARGET_VRAM:
+		flags |= 0x00010000;
+		flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
+		break;
+	case NV_MEM_TARGET_PCI:
+		flags |= 0x00020000;
+		flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
+		break;
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		flags |= 0x00030000;
+		flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dmaobj->access) {
+	case NV_MEM_ACCESS_VM:
+		break;
+	case NV_MEM_ACCESS_RO:
+		flags |= 0x00040000;
+		break;
+	case NV_MEM_ACCESS_WO:
+	case NV_MEM_ACCESS_RW:
+		flags |= 0x00080000;
+		break;
+	}
+
+	ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, flags);
+		nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
+		nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
+		nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
+					upper_32_bits(dmaobj->start));
+		nv_wo32(*pgpuobj, 0x10, 0x00000000);
+		nv_wo32(*pgpuobj, 0x14, 0x00000000);
+	}
+
+	return ret;
+}
+
+static int
+nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nouveau_dmaeng *dmaeng = (void *)engine;
+	struct nv50_dmaobj_priv *dmaobj;
+	struct nouveau_gpuobj *gpuobj;
+	int ret;
+
+	ret = nouveau_dmaobj_create(parent, engine, oclass,
+				    data, size, &dmaobj);
+	*pobject = nv_object(dmaobj);
+	if (ret)
+		return ret;
+
+	switch (nv_mclass(parent)) {
+	case 0x506f:
+	case 0x826f:
+		ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
+		nouveau_object_ref(NULL, pobject);
+		*pobject = nv_object(gpuobj);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct nouveau_ofuncs
+nv50_dmaobj_ofuncs = {
+	.ctor = nv50_dmaobj_ctor,
+	.dtor = _nouveau_dmaobj_dtor,
+	.init = _nouveau_dmaobj_init,
+	.fini = _nouveau_dmaobj_fini,
+};
+
+static struct nouveau_oclass
+nv50_dmaobj_sclass[] = {
+	{ 0x0002, &nv50_dmaobj_ofuncs },
+	{ 0x0003, &nv50_dmaobj_ofuncs },
+	{ 0x003d, &nv50_dmaobj_ofuncs },
+	{}
+};
+
+static int
+nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nv50_dmaeng_priv *priv;
+	int ret;
+
+	ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.sclass = nv50_dmaobj_sclass;
+	priv->base.bind = nv50_dmaobj_bind;
+	return 0;
+}
+
+struct nouveau_oclass
+nv50_dmaeng_oclass = {
+	.handle = NV_ENGINE(DMAOBJ, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_dmaeng_ctor,
+		.dtor = _nouveau_dmaeng_dtor,
+		.init = _nouveau_dmaeng_init,
+		.fini = _nouveau_dmaeng_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
new file mode 100644
index 0000000..5baa086
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012 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 <core/gpuobj.h>
+
+#include <subdev/fb.h>
+#include <engine/dmaobj.h>
+
+struct nvc0_dmaeng_priv {
+	struct nouveau_dmaeng base;
+};
+
+struct nvc0_dmaobj_priv {
+	struct nouveau_dmaobj base;
+};
+
+static int
+nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nvc0_dmaobj_priv *dmaobj;
+	int ret;
+
+	ret = nouveau_dmaobj_create(parent, engine, oclass, data, size, &dmaobj);
+	*pobject = nv_object(dmaobj);
+	if (ret)
+		return ret;
+
+	if (dmaobj->base.target != NV_MEM_TARGET_VM || dmaobj->base.start)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct nouveau_ofuncs
+nvc0_dmaobj_ofuncs = {
+	.ctor = nvc0_dmaobj_ctor,
+	.dtor = _nouveau_dmaobj_dtor,
+	.init = _nouveau_dmaobj_init,
+	.fini = _nouveau_dmaobj_fini,
+};
+
+static struct nouveau_oclass
+nvc0_dmaobj_sclass[] = {
+	{ 0x0002, &nvc0_dmaobj_ofuncs },
+	{ 0x0003, &nvc0_dmaobj_ofuncs },
+	{ 0x003d, &nvc0_dmaobj_ofuncs },
+	{}
+};
+
+static int
+nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		 struct nouveau_oclass *oclass, void *data, u32 size,
+		 struct nouveau_object **pobject)
+{
+	struct nvc0_dmaeng_priv *priv;
+	int ret;
+
+	ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.sclass = nvc0_dmaobj_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_dmaeng_oclass = {
+	.handle = NV_ENGINE(DMAOBJ, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_dmaeng_ctor,
+		.dtor = _nouveau_dmaeng_dtor,
+		.init = _nouveau_dmaeng_init,
+		.fini = _nouveau_dmaeng_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
new file mode 100644
index 0000000..edeb76e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 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 <core/object.h>
+#include <core/handle.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+
+int
+nouveau_fifo_channel_create_(struct nouveau_object *parent,
+			     struct nouveau_object *engine,
+			     struct nouveau_oclass *oclass,
+			     int bar, u32 addr, u32 size, u32 pushbuf,
+			     u32 engmask, int len, void **ptr)
+{
+	struct nouveau_device *device = nv_device(engine);
+	struct nouveau_fifo *priv = (void *)engine;
+	struct nouveau_fifo_chan *chan;
+	struct nouveau_dmaeng *dmaeng;
+	unsigned long flags;
+	int ret;
+
+	/* create base object class */
+	ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
+				     engmask, len, ptr);
+	chan = *ptr;
+	if (ret)
+		return ret;
+
+	/* validate dma object representing push buffer */
+	chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
+	if (!chan->pushdma)
+		return -ENOENT;
+
+	dmaeng = (void *)chan->pushdma->base.engine;
+	switch (chan->pushdma->base.oclass->handle) {
+	case 0x0002:
+	case 0x003d:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dmaeng->bind) {
+		ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu);
+		if (ret)
+			return ret;
+	}
+
+	/* find a free fifo channel */
+	spin_lock_irqsave(&priv->lock, flags);
+	for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
+		if (!priv->channel[chan->chid]) {
+			priv->channel[chan->chid] = nv_object(chan);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (chan->chid == priv->max) {
+		nv_error(priv, "no free channels\n");
+		return -ENOSPC;
+	}
+
+	/* map fifo control registers */
+	chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
+			     (chan->chid * size), size);
+	if (!chan->user)
+		return -EFAULT;
+
+	chan->size = size;
+	return 0;
+}
+
+void
+nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
+{
+	struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
+	unsigned long flags;
+
+	iounmap(chan->user);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->channel[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nouveau_gpuobj_ref(NULL, &chan->pushgpu);
+	nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
+	nouveau_namedb_destroy(&chan->base);
+}
+
+void
+_nouveau_fifo_channel_dtor(struct nouveau_object *object)
+{
+	struct nouveau_fifo_chan *chan = (void *)object;
+	nouveau_fifo_channel_destroy(chan);
+}
+
+u32
+_nouveau_fifo_channel_rd32(struct nouveau_object *object, u32 addr)
+{
+	struct nouveau_fifo_chan *chan = (void *)object;
+	return ioread32_native(chan->user + addr);
+}
+
+void
+_nouveau_fifo_channel_wr32(struct nouveau_object *object, u32 addr, u32 data)
+{
+	struct nouveau_fifo_chan *chan = (void *)object;
+	iowrite32_native(data, chan->user + addr);
+}
+
+void
+nouveau_fifo_destroy(struct nouveau_fifo *priv)
+{
+	kfree(priv->channel);
+	nouveau_engine_destroy(&priv->base);
+}
+
+int
+nouveau_fifo_create_(struct nouveau_object *parent,
+		     struct nouveau_object *engine,
+		     struct nouveau_oclass *oclass,
+		     int min, int max, int length, void **pobject)
+{
+	struct nouveau_fifo *priv;
+	int ret;
+
+	ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
+				     "fifo", length, pobject);
+	priv = *pobject;
+	if (ret)
+		return ret;
+
+	priv->min = min;
+	priv->max = max;
+	priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
+	if (!priv->channel)
+		return -ENOMEM;
+
+	spin_lock_init(&priv->lock);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
index 6ab7eb0..8b7513f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
@@ -1,44 +1,45 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/namedb.h>
+#include <core/handle.h>
 #include <core/ramht.h>
-#include "nouveau_software.h"
 
-static struct ramfc_desc {
-	unsigned bits:6;
-	unsigned ctxs:5;
-	unsigned ctxp:8;
-	unsigned regs:5;
-	unsigned regp;
-} nv04_ramfc[] = {
+#include <subdev/instmem.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+
+#include "nv04.h"
+
+static struct ramfc_desc
+nv04_ramfc[] = {
 	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
 	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
 	{ 16,  0, 0x08,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
@@ -50,259 +51,284 @@
 	{}
 };
 
-struct nv04_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct ramfc_desc *ramfc_desc;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
-struct nv04_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 ramfc;
-};
-
-bool
-nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
+int
+nv04_fifo_object_attach(struct nouveau_object *parent,
+			struct nouveau_object *object, u32 handle)
 {
-	int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	u32 context, chid = chan->base.chid;
+	int ret;
 
-	if (!enable) {
-		/* In some cases the PFIFO puller may be left in an
-		 * inconsistent state if you try to stop it when it's
-		 * busy translating handles. Sometimes you get a
-		 * PFIFO_CACHE_ERROR, sometimes it just fails silently
-		 * sending incorrect instance offsets to PGRAPH after
-		 * it's started up again. To avoid the latter we
-		 * invalidate the most recently calculated instance.
-		 */
-		if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
-				  NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
-			NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->addr >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
 
-		if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
-				 NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
-			nv_wr32(dev, NV03_PFIFO_INTR_0,
-				     NV_PFIFO_INTR_CACHE_ERROR);
-
-		nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW:
+		context |= 0x00000000;
+		break;
+	case NVDEV_ENGINE_GR:
+		context |= 0x00010000;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		context |= 0x00020000;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	return pull & 1;
+	context |= 0x80000000; /* valid */
+	context |= chid << 24;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+	return ret;
+}
+
+void
+nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	mutex_lock(&nv_subdev(priv)->mutex);
+	nouveau_ramht_remove(priv->ramht, cookie);
+	mutex_unlock(&nv_subdev(priv)->mutex);
 }
 
 static int
-nv04_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv04_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv = nv_engine(dev, engine);
-	struct nv04_fifo_chan *fctx;
-	unsigned long flags;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	struct nv_channel_dma_class *args = data;
 	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
+	if (size < sizeof(*args))
+		return -EINVAL;
 
-	fctx->ramfc = chan->id * 32;
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+					  0x10000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	/* map channel control registers */
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV03_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	chan->ramfc = chan->base.chid * 32;
 
-	/* initialise default fifo context */
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x08, chan->pushbuf->addr >> 4);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x10,
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x10,
 			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 #ifdef __BIG_ENDIAN
 			     NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
 			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-
-	/* enable dma mode on the channel */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-error:
-	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+	return 0;
 }
 
 void
-nv04_fifo_context_del(struct nouveau_channel *chan, int engine)
+nv04_fifo_chan_dtor(struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv = nv_engine(chan->dev, engine);
-	struct nv04_fifo_chan *fctx = chan->engctx[engine];
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
 	struct ramfc_desc *c = priv->ramfc_desc;
-	unsigned long flags;
-	int chid;
 
-	/* prevent fifo context switches */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+	do {
+		nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
+	} while ((++c)->bits);
 
-	/* if this channel is active, replace it with a null context */
-	chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
-	if (chid == chan->id) {
-		nv_mask(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
-		nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
-		nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
-
-		do {
-			u32 mask = ((1ULL << c->bits) - 1) << c->regs;
-			nv_mask(dev, c->regp, mask, 0x00000000);
-			nv_wo32(priv->ramfc, fctx->ramfc + c->ctxp, 0x00000000);
-		} while ((++c)->bits);
-
-		nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
-		nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
-		nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
-		nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
-		nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-	}
-
-	/* restore normal operation, after disabling dma mode */
-	nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 1);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* clean up */
-	nouveau_gpuobj_ref(NULL, &chan->ramfc); /*XXX: nv40 */
-	if (chan->user) {
-		iounmap(chan->user);
-		chan->user = NULL;
-	}
+	nouveau_fifo_channel_destroy(&chan->base);
 }
 
 int
-nv04_fifo_init(struct drm_device *dev, int engine)
+nv04_fifo_chan_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
+	u32 mask = 1 << chan->base.chid;
+	unsigned long flags;
+	int ret;
 
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
+	ret = nouveau_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
-	nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
-
-	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht->bits - 9) << 16) |
-				       (dev_priv->ramht->gpuobj->addr >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-	nv_wr32(dev, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
-
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
-
-	nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 1);
-
-	for (i = 0; i < priv->base.channels; i++) {
-		if (dev_priv->channels.ptr[i])
-			nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
-	}
-
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
 	return 0;
 }
 
 int
-nv04_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv = nv_engine(dev, engine);
-	struct nouveau_channel *chan;
-	int chid;
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
+	struct nouveau_gpuobj *fctx = priv->ramfc;
+	struct ramfc_desc *c;
+	unsigned long flags;
+	u32 data = chan->ramfc;
+	u32 chid;
 
-	/* prevent context switches and halt fifo operation */
-	nv_wr32(dev, NV03_PFIFO_CACHES, 0);
-	nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
-	nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 0);
+	/* prevent fifo context switches */
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-	/* store current fifo context in ramfc */
-	chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
-	chan = dev_priv->channels.ptr[chid];
-	if (suspend && chid != priv->base.channels && chan) {
-		struct nv04_fifo_chan *fctx = chan->engctx[engine];
-		struct nouveau_gpuobj *ctx = priv->ramfc;
-		struct ramfc_desc *c = priv->ramfc_desc;
+	/* if this channel is active, replace it with a null context */
+	chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+	if (chid == chan->base.chid) {
+		nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
+		nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
+
+		c = priv->ramfc_desc;
 		do {
 			u32 rm = ((1ULL << c->bits) - 1) << c->regs;
 			u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
-			u32 rv = (nv_rd32(dev, c->regp) &  rm) >> c->regs;
-			u32 cv = (nv_ro32(ctx, c->ctxp + fctx->ramfc) & ~cm);
-			nv_wo32(ctx, c->ctxp + fctx->ramfc, cv | (rv << c->ctxs));
+			u32 rv = (nv_rd32(priv, c->regp) &  rm) >> c->regs;
+			u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
+			nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
 		} while ((++c)->bits);
+
+		c = priv->ramfc_desc;
+		do {
+			nv_wr32(priv, c->regp, 0x00000000);
+		} while ((++c)->bits);
+
+		nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+		nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
 	}
 
-	nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0x00000000);
+	/* restore normal operation, after disabling dma mode */
+	nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+
+	return nouveau_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nouveau_ofuncs
+nv04_fifo_ofuncs = {
+	.ctor = nv04_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
+
+static struct nouveau_oclass
+nv04_fifo_sclass[] = {
+	{ 0x006e, &nv04_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+int
+nv04_fifo_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nv04_fifo_base *base;
+	int ret;
+
+	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				          0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-static bool
-nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
+static struct nouveau_oclass
+nv04_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nouveau_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+void
+nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
+__acquires(priv->base.lock)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
-	struct nouveau_gpuobj *obj;
+	struct nv04_fifo_priv *priv = (void *)pfifo;
 	unsigned long flags;
-	const int subc = (addr >> 13) & 0x7;
-	const int mthd = addr & 0x1ffc;
-	bool handled = false;
-	u32 engine;
 
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	if (likely(chid >= 0 && chid < pfifo->channels))
-		chan = dev_priv->channels.ptr[chid];
-	if (unlikely(!chan))
-		goto out;
+	spin_lock_irqsave(&priv->base.lock, flags);
+	*pflags = flags;
 
-	switch (mthd) {
-	case 0x0000: /* bind object to subchannel */
-		obj = nouveau_ramht_find(chan, data);
-		if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW))
-			break;
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
+	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
 
-		engine = 0x0000000f << (subc * 4);
+	/* in some cases the puller may be left in an inconsistent state
+	 * if you try to stop it while it's busy translating handles.
+	 * sometimes you get a CACHE_ERROR, sometimes it just fails
+	 * silently; sending incorrect instance offsets to PGRAPH after
+	 * it's started up again.
+	 *
+	 * to avoid this, we invalidate the most recently calculated
+	 * instance.
+	 */
+	if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
+			   NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
+		nv_warn(priv, "timeout idling puller\n");
 
-		nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000);
-		handled = true;
-		break;
-	default:
-		engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE);
-		if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
-			break;
+	if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
+			  NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+		nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
 
-		if (!nouveau_gpuobj_mthd_call(chan, nouveau_software_class(dev),
-					      mthd, data))
-			handled = true;
-		break;
-	}
-
-out:
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return handled;
+	nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
 }
 
-static const char *nv_dma_state_err(u32 state)
+void
+nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
+__releases(priv->base.lock)
+{
+	struct nv04_fifo_priv *priv = (void *)pfifo;
+	unsigned long flags = *pflags;
+
+	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
+
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+}
+
+static const char *
+nv_dma_state_err(u32 state)
 {
 	static const char * const desc[] = {
 		"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
@@ -311,22 +337,74 @@
 	return desc[(state >> 29) & 0x7];
 }
 
-void
-nv04_fifo_isr(struct drm_device *dev)
+static bool
+nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nv04_fifo_chan *chan = NULL;
+	struct nouveau_handle *bind;
+	const int subc = (addr >> 13) & 0x7;
+	const int mthd = addr & 0x1ffc;
+	bool handled = false;
+	unsigned long flags;
+	u32 engine;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	switch (mthd) {
+	case 0x0000:
+		bind = nouveau_namedb_get(nv_namedb(chan), data);
+		if (unlikely(!bind))
+			break;
+
+		if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
+			engine = 0x0000000f << (subc * 4);
+			chan->subc[subc] = data;
+			handled = true;
+
+			nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
+		}
+
+		nouveau_namedb_put(bind);
+		break;
+	default:
+		engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
+		if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
+			break;
+
+		bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
+		if (likely(bind)) {
+			if (!nv_call(bind->object, mthd, data))
+				handled = true;
+			nouveau_namedb_put(bind);
+		}
+		break;
+	}
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return handled;
+}
+
+void
+nv04_fifo_intr(struct nouveau_subdev *subdev)
+{
+	struct nouveau_device *device = nv_device(subdev);
+	struct nv04_fifo_priv *priv = (void *)subdev;
 	uint32_t status, reassign;
 	int cnt = 0;
 
-	reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
-	while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
+	reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
+	while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
 		uint32_t chid, get;
 
-		nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHES, 0);
 
-		chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & pfifo->channels;
-		get  = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
+		chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+		get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
 
 		if (status & NV_PFIFO_INTR_CACHE_ERROR) {
 			uint32_t mthd, data;
@@ -340,86 +418,85 @@
 			 */
 			ptr = (get & 0x7ff) >> 2;
 
-			if (dev_priv->card_type < NV_40) {
-				mthd = nv_rd32(dev,
+			if (device->card_type < NV_40) {
+				mthd = nv_rd32(priv,
 					NV04_PFIFO_CACHE1_METHOD(ptr));
-				data = nv_rd32(dev,
+				data = nv_rd32(priv,
 					NV04_PFIFO_CACHE1_DATA(ptr));
 			} else {
-				mthd = nv_rd32(dev,
+				mthd = nv_rd32(priv,
 					NV40_PFIFO_CACHE1_METHOD(ptr));
-				data = nv_rd32(dev,
+				data = nv_rd32(priv,
 					NV40_PFIFO_CACHE1_DATA(ptr));
 			}
 
-			if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) {
-				NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
-					     "Mthd 0x%04x Data 0x%08x\n",
+			if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
+				nv_info(priv, "CACHE_ERROR - Ch %d/%d "
+					      "Mthd 0x%04x Data 0x%08x\n",
 					chid, (mthd >> 13) & 7, mthd & 0x1ffc,
 					data);
 			}
 
-			nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
-			nv_wr32(dev, NV03_PFIFO_INTR_0,
+			nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
+			nv_wr32(priv, NV03_PFIFO_INTR_0,
 						NV_PFIFO_INTR_CACHE_ERROR);
 
-			nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
-				nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
-			nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
-			nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
-				nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
-			nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
+			nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+				nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
+			nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+			nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+				nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
+			nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
 
-			nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
-				nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
-			nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+			nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
+				nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
+			nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
 
 			status &= ~NV_PFIFO_INTR_CACHE_ERROR;
 		}
 
 		if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-			u32 dma_get = nv_rd32(dev, 0x003244);
-			u32 dma_put = nv_rd32(dev, 0x003240);
-			u32 push = nv_rd32(dev, 0x003220);
-			u32 state = nv_rd32(dev, 0x003228);
+			u32 dma_get = nv_rd32(priv, 0x003244);
+			u32 dma_put = nv_rd32(priv, 0x003240);
+			u32 push = nv_rd32(priv, 0x003220);
+			u32 state = nv_rd32(priv, 0x003228);
 
-			if (dev_priv->card_type == NV_50) {
-				u32 ho_get = nv_rd32(dev, 0x003328);
-				u32 ho_put = nv_rd32(dev, 0x003320);
-				u32 ib_get = nv_rd32(dev, 0x003334);
-				u32 ib_put = nv_rd32(dev, 0x003330);
+			if (device->card_type == NV_50) {
+				u32 ho_get = nv_rd32(priv, 0x003328);
+				u32 ho_put = nv_rd32(priv, 0x003320);
+				u32 ib_get = nv_rd32(priv, 0x003334);
+				u32 ib_put = nv_rd32(priv, 0x003330);
 
-				if (nouveau_ratelimit())
-					NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
-					     "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
-					     "State 0x%08x (err: %s) Push 0x%08x\n",
-						chid, ho_get, dma_get, ho_put,
-						dma_put, ib_get, ib_put, state,
-						nv_dma_state_err(state),
-						push);
+				nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
+				     "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
+				     "State 0x%08x (err: %s) Push 0x%08x\n",
+					chid, ho_get, dma_get, ho_put,
+					dma_put, ib_get, ib_put, state,
+					nv_dma_state_err(state),
+					push);
 
 				/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
-				nv_wr32(dev, 0x003364, 0x00000000);
+				nv_wr32(priv, 0x003364, 0x00000000);
 				if (dma_get != dma_put || ho_get != ho_put) {
-					nv_wr32(dev, 0x003244, dma_put);
-					nv_wr32(dev, 0x003328, ho_put);
+					nv_wr32(priv, 0x003244, dma_put);
+					nv_wr32(priv, 0x003328, ho_put);
 				} else
 				if (ib_get != ib_put) {
-					nv_wr32(dev, 0x003334, ib_put);
+					nv_wr32(priv, 0x003334, ib_put);
 				}
 			} else {
-				NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
+				nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
 					     "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
 					chid, dma_get, dma_put, state,
 					nv_dma_state_err(state), push);
 
 				if (dma_get != dma_put)
-					nv_wr32(dev, 0x003244, dma_put);
+					nv_wr32(priv, 0x003244, dma_put);
 			}
 
-			nv_wr32(dev, 0x003228, 0x00000000);
-			nv_wr32(dev, 0x003220, 0x00000001);
-			nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+			nv_wr32(priv, 0x003228, 0x00000000);
+			nv_wr32(priv, 0x003220, 0x00000001);
+			nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
 			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
 		}
 
@@ -427,81 +504,118 @@
 			uint32_t sem;
 
 			status &= ~NV_PFIFO_INTR_SEMAPHORE;
-			nv_wr32(dev, NV03_PFIFO_INTR_0,
+			nv_wr32(priv, NV03_PFIFO_INTR_0,
 				NV_PFIFO_INTR_SEMAPHORE);
 
-			sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
-			nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+			sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+			nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
 
-			nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
-			nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+			nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+			nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
 		}
 
-		if (dev_priv->card_type == NV_50) {
+		if (device->card_type == NV_50) {
 			if (status & 0x00000010) {
-				nv50_fb_vm_trap(dev, nouveau_ratelimit());
+				nv50_fb_trap(nouveau_fb(priv), 1);
 				status &= ~0x00000010;
-				nv_wr32(dev, 0x002100, 0x00000010);
+				nv_wr32(priv, 0x002100, 0x00000010);
 			}
 		}
 
 		if (status) {
-			if (nouveau_ratelimit())
-				NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
-					status, chid);
-			nv_wr32(dev, NV03_PFIFO_INTR_0, status);
+			nv_info(priv, "unknown intr 0x%08x, ch %d\n",
+				status, chid);
+			nv_wr32(priv, NV03_PFIFO_INTR_0, status);
 			status = 0;
 		}
 
-		nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
+		nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
 	}
 
 	if (status) {
-		NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
-		nv_wr32(dev, 0x2140, 0);
-		nv_wr32(dev, 0x140, 0);
+		nv_info(priv, "still angry after %d spins, halt\n", cnt);
+		nv_wr32(priv, 0x002140, 0);
+		nv_wr32(priv, 0x000140, 0);
 	}
 
-	nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
+	nv_wr32(priv, 0x000100, 0x00000100);
+}
+
+static int
+nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nouveau_ramht_ref(imem->ramht, &priv->ramht);
+	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
+	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv04_fifo_cclass;
+	nv_engine(priv)->sclass = nv04_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv04_ramfc;
+	return 0;
 }
 
 void
-nv04_fifo_destroy(struct drm_device *dev, int engine)
+nv04_fifo_dtor(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 8);
-
+	struct nv04_fifo_priv *priv = (void *)object;
 	nouveau_gpuobj_ref(NULL, &priv->ramfc);
 	nouveau_gpuobj_ref(NULL, &priv->ramro);
-
-	dev_priv->eng[engine] = NULL;
-	kfree(priv);
+	nouveau_ramht_ref(NULL, &priv->ramht);
+	nouveau_fifo_destroy(&priv->base);
 }
 
 int
-nv04_fifo_create(struct drm_device *dev)
+nv04_fifo_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fifo_priv *priv;
+	struct nv04_fifo_priv *priv = (void *)object;
+	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	ret = nouveau_fifo_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
-	nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
+	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
 
-	priv->base.base.destroy = nv04_fifo_destroy;
-	priv->base.base.init = nv04_fifo_init;
-	priv->base.base.fini = nv04_fifo_fini;
-	priv->base.base.context_new = nv04_fifo_context_new;
-	priv->base.base.context_del = nv04_fifo_context_del;
-	priv->base.channels = 15;
-	priv->ramfc_desc = nv04_ramfc;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->base.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
 
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
 	return 0;
 }
+
+struct nouveau_oclass
+nv04_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv04_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
new file mode 100644
index 0000000..496a4b4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
@@ -0,0 +1,178 @@
+#ifndef __NV04_FIFO_H__
+#define __NV04_FIFO_H__
+
+#include <engine/fifo.h>
+
+#define NV04_PFIFO_DELAY_0                                 0x00002040
+#define NV04_PFIFO_DMA_TIMESLICE                           0x00002044
+#define NV04_PFIFO_NEXT_CHANNEL                            0x00002050
+#define NV03_PFIFO_INTR_0                                  0x00002100
+#define NV03_PFIFO_INTR_EN_0                               0x00002140
+#    define NV_PFIFO_INTR_CACHE_ERROR                          (1<<0)
+#    define NV_PFIFO_INTR_RUNOUT                               (1<<4)
+#    define NV_PFIFO_INTR_RUNOUT_OVERFLOW                      (1<<8)
+#    define NV_PFIFO_INTR_DMA_PUSHER                          (1<<12)
+#    define NV_PFIFO_INTR_DMA_PT                              (1<<16)
+#    define NV_PFIFO_INTR_SEMAPHORE                           (1<<20)
+#    define NV_PFIFO_INTR_ACQUIRE_TIMEOUT                     (1<<24)
+#define NV03_PFIFO_RAMHT                                   0x00002210
+#define NV03_PFIFO_RAMFC                                   0x00002214
+#define NV03_PFIFO_RAMRO                                   0x00002218
+#define NV40_PFIFO_RAMFC                                   0x00002220
+#define NV03_PFIFO_CACHES                                  0x00002500
+#define NV04_PFIFO_MODE                                    0x00002504
+#define NV04_PFIFO_DMA                                     0x00002508
+#define NV04_PFIFO_SIZE                                    0x0000250c
+#define NV50_PFIFO_CTX_TABLE(c)                        (0x2600+(c)*4)
+#define NV50_PFIFO_CTX_TABLE__SIZE                                128
+#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED                  (1<<31)
+#define NV50_PFIFO_CTX_TABLE_UNK30_BAD                        (1<<30)
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80             0x0FFFFFFF
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84             0x00FFFFFF
+#define NV03_PFIFO_CACHE0_PUSH0                            0x00003000
+#define NV03_PFIFO_CACHE0_PULL0                            0x00003040
+#define NV04_PFIFO_CACHE0_PULL0                            0x00003050
+#define NV04_PFIFO_CACHE0_PULL1                            0x00003054
+#define NV03_PFIFO_CACHE1_PUSH0                            0x00003200
+#define NV03_PFIFO_CACHE1_PUSH1                            0x00003204
+#define NV03_PFIFO_CACHE1_PUSH1_DMA                            (1<<8)
+#define NV40_PFIFO_CACHE1_PUSH1_DMA                           (1<<16)
+#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000000f
+#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000001f
+#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000007f
+#define NV03_PFIFO_CACHE1_PUT                              0x00003210
+#define NV04_PFIFO_CACHE1_DMA_PUSH                         0x00003220
+#define NV04_PFIFO_CACHE1_DMA_FETCH                        0x00003224
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES         0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES        0x00000008
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES        0x00000010
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES        0x00000018
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES        0x00000020
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES        0x00000028
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES        0x00000030
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES        0x00000038
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES        0x00000040
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES        0x00000048
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES        0x00000050
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES        0x00000058
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES       0x00000060
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES       0x00000068
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES       0x00000070
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES       0x00000078
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES       0x00000080
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES       0x00000088
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES       0x00000090
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES       0x00000098
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES       0x000000A0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES       0x000000A8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES       0x000000B0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES       0x000000B8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES       0x000000C0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES       0x000000C8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES       0x000000D0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES       0x000000D8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES       0x000000E0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES       0x000000E8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES       0x000000F0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES       0x000000F8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE                 0x0000E000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES        0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES        0x00002000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES        0x00004000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES       0x00006000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES       0x00008000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES       0x0000A000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES       0x0000C000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES       0x0000E000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS             0x001F0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0           0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1           0x00010000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2           0x00020000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3           0x00030000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4           0x00040000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5           0x00050000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6           0x00060000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7           0x00070000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8           0x00080000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9           0x00090000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10          0x000A0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11          0x000B0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12          0x000C0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13          0x000D0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14          0x000E0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15          0x000F0000
+#    define NV_PFIFO_CACHE1_ENDIAN                         0x80000000
+#    define NV_PFIFO_CACHE1_LITTLE_ENDIAN                  0x7FFFFFFF
+#    define NV_PFIFO_CACHE1_BIG_ENDIAN                     0x80000000
+#define NV04_PFIFO_CACHE1_DMA_STATE                        0x00003228
+#define NV04_PFIFO_CACHE1_DMA_INSTANCE                     0x0000322c
+#define NV04_PFIFO_CACHE1_DMA_CTL                          0x00003230
+#define NV04_PFIFO_CACHE1_DMA_PUT                          0x00003240
+#define NV04_PFIFO_CACHE1_DMA_GET                          0x00003244
+#define NV10_PFIFO_CACHE1_REF_CNT                          0x00003248
+#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE                   0x0000324C
+#define NV03_PFIFO_CACHE1_PULL0                            0x00003240
+#define NV04_PFIFO_CACHE1_PULL0                            0x00003250
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED            0x00000010
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY              0x00001000
+#define NV03_PFIFO_CACHE1_PULL1                            0x00003250
+#define NV04_PFIFO_CACHE1_PULL1                            0x00003254
+#define NV04_PFIFO_CACHE1_HASH                             0x00003258
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT                  0x00003260
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP                0x00003264
+#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE                    0x00003268
+#define NV10_PFIFO_CACHE1_SEMAPHORE                        0x0000326C
+#define NV03_PFIFO_CACHE1_GET                              0x00003270
+#define NV04_PFIFO_CACHE1_ENGINE                           0x00003280
+#define NV04_PFIFO_CACHE1_DMA_DCOUNT                       0x000032A0
+#define NV40_PFIFO_GRCTX_INSTANCE                          0x000032E0
+#define NV40_PFIFO_UNK32E4                                 0x000032E4
+#define NV04_PFIFO_CACHE1_METHOD(i)                (0x00003800+(i*8))
+#define NV04_PFIFO_CACHE1_DATA(i)                  (0x00003804+(i*8))
+#define NV40_PFIFO_CACHE1_METHOD(i)                (0x00090000+(i*8))
+#define NV40_PFIFO_CACHE1_DATA(i)                  (0x00090004+(i*8))
+
+struct ramfc_desc {
+	unsigned bits:6;
+	unsigned ctxs:5;
+	unsigned ctxp:8;
+	unsigned regs:5;
+	unsigned regp;
+};
+
+struct nv04_fifo_priv {
+	struct nouveau_fifo base;
+	struct ramfc_desc *ramfc_desc;
+	struct nouveau_ramht  *ramht;
+	struct nouveau_gpuobj *ramro;
+	struct nouveau_gpuobj *ramfc;
+};
+
+struct nv04_fifo_base {
+	struct nouveau_fifo_base base;
+};
+
+struct nv04_fifo_chan {
+	struct nouveau_fifo_chan base;
+	u32 subc[8];
+	u32 ramfc;
+};
+
+int  nv04_fifo_object_attach(struct nouveau_object *,
+			     struct nouveau_object *, u32);
+void nv04_fifo_object_detach(struct nouveau_object *, int);
+
+void nv04_fifo_chan_dtor(struct nouveau_object *);
+int  nv04_fifo_chan_init(struct nouveau_object *);
+int  nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
+
+int  nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
+			    struct nouveau_oclass *, void *, u32,
+			    struct nouveau_object **);
+
+void nv04_fifo_dtor(struct nouveau_object *);
+int  nv04_fifo_init(struct nouveau_object *);
+void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
+void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
index 2d38fa8..391fefa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
@@ -1,43 +1,42 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
 
-static struct ramfc_desc {
-	unsigned bits:6;
-	unsigned ctxs:5;
-	unsigned ctxp:8;
-	unsigned regs:5;
-	unsigned regp;
-} nv10_ramfc[] = {
+#include <subdev/instmem.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+
+#include "nv04.h"
+
+static struct ramfc_desc
+nv10_ramfc[] = {
 	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
 	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
 	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
@@ -50,87 +49,122 @@
 	{}
 };
 
-struct nv10_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct ramfc_desc *ramfc_desc;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
-
-struct nv10_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 ramfc;
-};
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
 static int
-nv10_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv10_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv10_fifo_priv *priv = nv_engine(dev, engine);
-	struct nv10_fifo_chan *fctx;
-	unsigned long flags;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	struct nv_channel_dma_class *args = data;
 	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
+	if (size < sizeof(*args))
+		return -EINVAL;
 
-	fctx->ramfc = chan->id * 32;
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+					  0x10000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	/* map channel control registers */
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV03_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	chan->ramfc = chan->base.chid * 32;
 
-	/* initialise default fifo context */
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x14,
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
 			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 #ifdef __BIG_ENDIAN
 			     NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
 			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-
-	/* enable dma mode on the channel */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-error:
-	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
-}
-
-int
-nv10_fifo_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv10_fifo_priv *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
-	nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
-
-	priv->base.base.destroy = nv04_fifo_destroy;
-	priv->base.base.init = nv04_fifo_init;
-	priv->base.base.fini = nv04_fifo_fini;
-	priv->base.base.context_new = nv10_fifo_context_new;
-	priv->base.base.context_del = nv04_fifo_context_del;
-	priv->base.channels = 31;
-	priv->ramfc_desc = nv10_ramfc;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
 	return 0;
 }
+
+static struct nouveau_ofuncs
+nv10_fifo_ofuncs = {
+	.ctor = nv10_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
+
+static struct nouveau_oclass
+nv10_fifo_sclass[] = {
+	{ 0x006e, &nv10_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv10_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nouveau_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nouveau_ramht_ref(imem->ramht, &priv->ramht);
+	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
+	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv10_fifo_cclass;
+	nv_engine(priv)->sclass = nv10_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv10_ramfc;
+	return 0;
+}
+
+struct nouveau_oclass
+nv10_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv04_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
index 2f700a15e..3b9d6c9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
@@ -1,43 +1,42 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
 
-static struct ramfc_desc {
-	unsigned bits:6;
-	unsigned ctxs:5;
-	unsigned ctxp:8;
-	unsigned regs:5;
-	unsigned regp;
-} nv17_ramfc[] = {
+#include <subdev/instmem.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+
+#include "nv04.h"
+
+static struct ramfc_desc
+nv17_ramfc[] = {
 	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
 	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
 	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
@@ -55,124 +54,154 @@
 	{}
 };
 
-struct nv17_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct ramfc_desc *ramfc_desc;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
-
-struct nv17_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 ramfc;
-};
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
 static int
-nv17_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv17_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv17_fifo_priv *priv = nv_engine(dev, engine);
-	struct nv17_fifo_chan *fctx;
-	unsigned long flags;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	struct nv_channel_dma_class *args = data;
 	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
+	if (size < sizeof(*args))
+		return -EINVAL;
 
-	fctx->ramfc = chan->id * 64;
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+					  0x10000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR) |
+					  (1 << NVDEV_ENGINE_MPEG), /* NV31- */
+					  &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	/* map channel control registers */
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV03_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	chan->ramfc = chan->base.chid * 64;
 
-	/* initialise default fifo context */
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x14,
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
 			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 #ifdef __BIG_ENDIAN
 			     NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
 			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+	return 0;
+}
 
-	/* enable dma mode on the channel */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+static struct nouveau_ofuncs
+nv17_fifo_ofuncs = {
+	.ctor = nv17_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
 
-error:
+static struct nouveau_oclass
+nv17_fifo_sclass[] = {
+	{ 0x006e, &nv17_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv17_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x17),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nouveau_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+		return ret;
+
+	nouveau_ramht_ref(imem->ramht, &priv->ramht);
+	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
+	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv17_fifo_cclass;
+	nv_engine(priv)->sclass = nv17_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv17_ramfc;
+	return 0;
 }
 
 static int
-nv17_fifo_init(struct drm_device *dev, int engine)
+nv17_fifo_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv17_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
+	struct nv04_fifo_priv *priv = (void *)object;
+	int ret;
 
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
+	ret = nouveau_fifo_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
-	nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
 
-	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht->bits - 9) << 16) |
-				       (dev_priv->ramht->gpuobj->addr >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-	nv_wr32(dev, NV03_PFIFO_RAMFC, 0x00010000 |
-				       priv->ramfc->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->base.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
 
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
 
-	nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
 
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 1);
-
-	for (i = 0; i < priv->base.channels; i++) {
-		if (dev_priv->channels.ptr[i])
-			nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
-	}
-
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
 	return 0;
 }
 
-int
-nv17_fifo_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv17_fifo_priv *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
-	nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
-
-	priv->base.base.destroy = nv04_fifo_destroy;
-	priv->base.base.init = nv17_fifo_init;
-	priv->base.base.fini = nv04_fifo_fini;
-	priv->base.base.context_new = nv17_fifo_context_new;
-	priv->base.base.context_del = nv04_fifo_context_del;
-	priv->base.channels = 31;
-	priv->ramfc_desc = nv17_ramfc;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
-	return 0;
-}
+struct nouveau_oclass
+nv17_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x17),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv17_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv17_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
index 65a670f..43d5c9e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
@@ -1,43 +1,42 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
 
-static struct ramfc_desc {
-	unsigned bits:6;
-	unsigned ctxs:5;
-	unsigned ctxp:8;
-	unsigned regs:5;
-	unsigned regp;
-} nv40_ramfc[] = {
+#include <subdev/instmem.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+
+#include "nv04.h"
+
+static struct ramfc_desc
+nv40_ramfc[] = {
 	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
 	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
 	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
@@ -63,148 +62,287 @@
 	{}
 };
 
-struct nv40_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct ramfc_desc *ramfc_desc;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
-
-struct nv40_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 ramfc;
-};
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
 static int
-nv40_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv40_fifo_object_attach(struct nouveau_object *parent,
+			struct nouveau_object *object, u32 handle)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv40_fifo_priv *priv = nv_engine(dev, engine);
-	struct nv40_fifo_chan *fctx;
-	unsigned long flags;
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	u32 context, chid = chan->base.chid;
 	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->addr >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
 
-	fctx->ramfc = chan->id * 128;
-
-	/* map channel control registers */
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV03_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW:
+		context |= 0x00000000;
+		break;
+	case NVDEV_ENGINE_GR:
+		context |= 0x00100000;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		context |= 0x00200000;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	/* initialise default fifo context */
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x18, 0x30000000 |
+	context |= chid << 23;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+	return ret;
+}
+
+static int
+nv40_fifo_context_attach(struct nouveau_object *parent,
+			 struct nouveau_object *engctx)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	unsigned long flags;
+	u32 reg, ctx;
+
+	switch (nv_engidx(engctx->engine)) {
+	case NVDEV_ENGINE_SW:
+		return 0;
+	case NVDEV_ENGINE_GR:
+		reg = 0x32e0;
+		ctx = 0x38;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		reg = 0x330c;
+		ctx = 0x54;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+		nv_wr32(priv, reg, nv_gpuobj(engctx)->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_gpuobj(engctx)->addr >> 4);
+
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return 0;
+}
+
+static int
+nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
+			 struct nouveau_object *engctx)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	unsigned long flags;
+	u32 reg, ctx;
+
+	switch (nv_engidx(engctx->engine)) {
+	case NVDEV_ENGINE_SW:
+		return 0;
+	case NVDEV_ENGINE_GR:
+		reg = 0x32e0;
+		ctx = 0x38;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		reg = 0x330c;
+		ctx = 0x54;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+		nv_wr32(priv, reg, 0x00000000);
+	nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
+
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return 0;
+}
+
+static int
+nv40_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
+{
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	struct nv_channel_dma_class *args = data;
+	int ret;
+
+	if (size < sizeof(*args))
+		return -EINVAL;
+
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+					  0x1000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR) |
+					  (1 << NVDEV_ENGINE_MPEG), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv_parent(chan)->context_attach = nv40_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv40_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv40_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	chan->ramfc = chan->base.chid * 128;
+
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
 			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 #ifdef __BIG_ENDIAN
 			     NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
 			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-	nv_wo32(priv->ramfc, fctx->ramfc + 0x3c, 0x0001ffff);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
+	return 0;
+}
 
-	/* enable dma mode on the channel */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+static struct nouveau_ofuncs
+nv40_fifo_ofuncs = {
+	.ctor = nv40_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
 
-	/*XXX: remove this later, need fifo engine context commit hook */
-	nouveau_gpuobj_ref(priv->ramfc, &chan->ramfc);
+static struct nouveau_oclass
+nv40_fifo_sclass[] = {
+	{ 0x006e, &nv40_fifo_ofuncs },
+	{}
+};
 
-error:
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv40_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nouveau_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+		return ret;
+
+	nouveau_ramht_ref(imem->ramht, &priv->ramht);
+	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
+	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv40_fifo_cclass;
+	nv_engine(priv)->sclass = nv40_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv40_ramfc;
+	return 0;
 }
 
 static int
-nv40_fifo_init(struct drm_device *dev, int engine)
+nv40_fifo_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv40_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
+	struct nv04_fifo_priv *priv = (void *)object;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	int ret;
 
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
-	nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
+	ret = nouveau_fifo_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, 0x002040, 0x000000ff);
-	nv_wr32(dev, 0x002044, 0x2101ffff);
-	nv_wr32(dev, 0x002058, 0x00000001);
+	nv_wr32(priv, 0x002040, 0x000000ff);
+	nv_wr32(priv, 0x002044, 0x2101ffff);
+	nv_wr32(priv, 0x002058, 0x00000001);
 
-	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht->bits - 9) << 16) |
-				       (dev_priv->ramht->gpuobj->addr >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->base.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
 
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
-		nv_wr32(dev, 0x002230, 0x00000001);
+		nv_wr32(priv, 0x002230, 0x00000001);
 	case 0x40:
 	case 0x41:
 	case 0x42:
 	case 0x43:
 	case 0x45:
 	case 0x48:
-		nv_wr32(dev, 0x002220, 0x00030002);
+		nv_wr32(priv, 0x002220, 0x00030002);
 		break;
 	default:
-		nv_wr32(dev, 0x002230, 0x00000000);
-		nv_wr32(dev, 0x002220, ((nvfb_vram_size(dev) - 512 * 1024 +
+		nv_wr32(priv, 0x002230, 0x00000000);
+		nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 +
 					 priv->ramfc->addr) >> 16) |
-				       0x00030000);
+					0x00030000);
 		break;
 	}
 
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
 
-	nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
 
-	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 1);
-
-	for (i = 0; i < priv->base.channels; i++) {
-		if (dev_priv->channels.ptr[i])
-			nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
-	}
-
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
 	return 0;
 }
 
-int
-nv40_fifo_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv40_fifo_priv *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
-	nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
-
-	priv->base.base.destroy = nv04_fifo_destroy;
-	priv->base.base.init = nv40_fifo_init;
-	priv->base.base.fini = nv04_fifo_fini;
-	priv->base.base.context_new = nv40_fifo_context_new;
-	priv->base.base.context_del = nv04_fifo_context_del;
-	priv->base.channels = 31;
-	priv->ramfc_desc = nv40_ramfc;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
-	return 0;
-}
+struct nouveau_oclass
+nv40_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv40_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
index 7b5b159..4914c3b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
@@ -1,126 +1,123 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
+#include <core/client.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
+#include <core/class.h>
+#include <core/math.h>
 
-struct nv50_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct nouveau_gpuobj *playlist[2];
-	int cur_playlist;
-};
+#include <subdev/timer.h>
+#include <subdev/bar.h>
 
-struct nv50_fifo_chan {
-	struct nouveau_fifo_chan base;
-};
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+
+#include "nv50.h"
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
 void
-nv50_fifo_playlist_update(struct drm_device *dev)
+nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
 {
-	struct nv50_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+	struct nouveau_bar *bar = nouveau_bar(priv);
 	struct nouveau_gpuobj *cur;
 	int i, p;
 
 	cur = priv->playlist[priv->cur_playlist];
 	priv->cur_playlist = !priv->cur_playlist;
 
-	for (i = 0, p = 0; i < priv->base.channels; i++) {
-		if (nv_rd32(dev, 0x002600 + (i * 4)) & 0x80000000)
+	for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
+		if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
 			nv_wo32(cur, p++ * 4, i);
 	}
 
-	nvimem_flush(dev);
+	bar->flush(bar);
 
-	nv_wr32(dev, 0x0032f4, cur->addr >> 12);
-	nv_wr32(dev, 0x0032ec, p);
-	nv_wr32(dev, 0x002500, 0x00000101);
+	nv_wr32(priv, 0x0032f4, cur->addr >> 12);
+	nv_wr32(priv, 0x0032ec, p);
+	nv_wr32(priv, 0x002500, 0x00000101);
 }
 
 static int
-nv50_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv50_fifo_context_attach(struct nouveau_object *parent,
+			 struct nouveau_object *object)
 {
-	struct nv50_fifo_priv *priv = nv_engine(chan->dev, engine);
-	struct nv50_fifo_chan *fctx;
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
-	u64 instance = chan->ramin->addr >> 12;
-	unsigned long flags;
-	int ret = 0, i;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nouveau_gpuobj *ectx = (void *)object;
+	u64 limit = ectx->addr + ectx->size - 1;
+	u64 start = ectx->addr;
+	u32 addr;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
-	nvvm_engref(chan->vm, engine, 1);
-
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV50_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	default:
+		return -EINVAL;
 	}
 
-	for (i = 0; i < 0x100; i += 4)
-		nv_wo32(chan->ramin, i, 0x00000000);
-	nv_wo32(chan->ramin, 0x3c, 0x403f6078);
-	nv_wo32(chan->ramin, 0x40, 0x00000000);
-	nv_wo32(chan->ramin, 0x44, 0x01003fff);
-	nv_wo32(chan->ramin, 0x48, chan->pushbuf->node->offset >> 4);
-	nv_wo32(chan->ramin, 0x50, lower_32_bits(ib_offset));
-	nv_wo32(chan->ramin, 0x54, upper_32_bits(ib_offset) |
-				   drm_order(chan->dma.ib_max + 1) << 16);
-	nv_wo32(chan->ramin, 0x60, 0x7fffffff);
-	nv_wo32(chan->ramin, 0x78, 0x00000000);
-	nv_wo32(chan->ramin, 0x7c, 0x30000001);
-	nv_wo32(chan->ramin, 0x80, ((chan->ramht->bits - 9) << 27) |
-				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->gpuobj->node->offset >> 4));
-
-	nvimem_flush(dev);
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
-	nv50_fifo_playlist_update(dev);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-error:
-	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+	nv_wo32(base->eng, addr + 0x00, 0x00190000);
+	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+					upper_32_bits(start));
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+	return 0;
 }
 
-static bool
-nv50_fifo_kickoff(struct nouveau_channel *chan)
+static int
+nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
+			 struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	bool done = true;
-	u32 me;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_priv *priv = (void *)parent->engine;
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 addr, me;
+	int ret = 0;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wo32(base->eng, addr + 0x00, 0x00000000);
+	nv_wo32(base->eng, addr + 0x04, 0x00000000);
+	nv_wo32(base->eng, addr + 0x08, 0x00000000);
+	nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
 
 	/* HW bug workaround:
 	 *
@@ -134,159 +131,308 @@
 	 * there's also a "ignore these engines" bitmask reg we can use
 	 * if we hit the issue there..
 	 */
-
-	/* PME: make sure engine is enabled */
-	me = nv_mask(dev, 0x00b860, 0x00000001, 0x00000001);
+	me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
 
 	/* do the kickoff... */
-	nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
-	if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
-		NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
-		done = false;
+	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+	if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
+		nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
+		if (suspend)
+			ret = -EBUSY;
 	}
 
-	/* restore any engine states we changed, and exit */
-	nv_wr32(dev, 0x00b860, me);
-	return done;
-}
-
-static void
-nv50_fifo_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv50_fifo_chan *fctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	unsigned long flags;
-
-	/* remove channel from playlist, will context switch if active */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
-	nv50_fifo_playlist_update(dev);
-
-	/* tell any engines on this channel to unload their contexts */
-	nv50_fifo_kickoff(chan);
-
-	nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* clean up */
-	if (chan->user) {
-		iounmap(chan->user);
-		chan->user = NULL;
-	}
-
-	nvvm_engref(chan->vm, engine, -1);
-	chan->engctx[engine] = NULL;
-	kfree(fctx);
+	nv_wr32(priv, 0x00b860, me);
+	return ret;
 }
 
 static int
-nv50_fifo_init(struct drm_device *dev, int engine)
+nv50_fifo_object_attach(struct nouveau_object *parent,
+			struct nouveau_object *object, u32 handle)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 instance;
-	int i;
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 context;
 
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(dev, 0x00250c, 0x6f3cfc34);
-	nv_wr32(dev, 0x002044, 0x01003fff);
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->node->offset >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
 
-	nv_wr32(dev, 0x002100, 0xffffffff);
-	nv_wr32(dev, 0x002140, 0xffffffff);
-
-	for (i = 0; i < 128; i++) {
-		struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-		if (chan && chan->engctx[engine])
-			instance = 0x80000000 | chan->ramin->addr >> 12;
-		else
-			instance = 0x00000000;
-		nv_wr32(dev, 0x002600 + (i * 4), instance);
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
+	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
+	case NVDEV_ENGINE_MPEG  : context |= 0x00200000; break;
+	default:
+		return -EINVAL;
 	}
 
-	nv50_fifo_playlist_update(dev);
+	return nouveau_ramht_insert(chan->ramht, 0, handle, context);
+}
 
-	nv_wr32(dev, 0x003200, 1);
-	nv_wr32(dev, 0x003250, 1);
-	nv_wr32(dev, 0x002500, 1);
-	return 0;
+void
+nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
+{
+	struct nv50_fifo_chan *chan = (void *)parent;
+	nouveau_ramht_remove(chan->ramht, cookie);
 }
 
 static int
-nv50_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+nv50_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
+	struct nv_channel_ind_class *args = data;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	u64 ioffset, ilength;
+	int ret;
 
-	/* set playlist length to zero, fifo will unload context */
-	nv_wr32(dev, 0x0032ec, 0);
+	if (size < sizeof(*args))
+		return -EINVAL;
 
-	/* tell all connected engines to unload their contexts */
-	for (i = 0; i < priv->base.channels; i++) {
-		struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-		if (chan && !nv50_fifo_kickoff(chan))
-			return -EBUSY;
-	}
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+					  0x2000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR) |
+					  (1 << NVDEV_ENGINE_MPEG), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, 0x002140, 0);
+	nv_parent(chan)->context_attach = nv50_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv50_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv50_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
+	if (ret)
+		return ret;
+
+	ioffset = args->ioffset;
+	ilength = log2i(args->ilength / 8);
+
+	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+				   (4 << 24) /* SEARCH_FULL */ |
+				   (chan->ramht->base.node->offset >> 4));
+	bar->flush(bar);
 	return 0;
 }
 
 void
-nv50_fifo_tlb_flush(struct drm_device *dev, int engine)
+nv50_fifo_chan_dtor(struct nouveau_object *object)
 {
-	nv50_vm_flush_engine(dev, 5);
+	struct nv50_fifo_chan *chan = (void *)object;
+	nouveau_ramht_ref(NULL, &chan->ramht);
+	nouveau_fifo_channel_destroy(&chan->base);
 }
 
-void
-nv50_fifo_destroy(struct drm_device *dev, int engine)
+static int
+nv50_fifo_chan_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_fifo_priv *priv = nv_engine(dev, engine);
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_base *base = (void *)object->parent;
+	struct nv50_fifo_chan *chan = (void *)object;
+	struct nouveau_gpuobj *ramfc = base->ramfc;
+	u32 chid = chan->base.chid;
+	int ret;
 
-	nouveau_irq_unregister(dev, 8);
+	ret = nouveau_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
 
-	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
-	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
-
-	dev_priv->eng[engine] = NULL;
-	kfree(priv);
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
+	nv50_fifo_playlist_update(priv);
+	return 0;
 }
 
 int
-nv50_fifo_create(struct drm_device *dev)
+nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	/* remove channel from playlist, fifo will unload context */
+	nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
+	nv50_fifo_playlist_update(priv);
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
+
+	return nouveau_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nouveau_ofuncs
+nv50_fifo_ofuncs = {
+	.ctor = nv50_fifo_chan_ctor,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = nv50_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
+
+static struct nouveau_oclass
+nv50_fifo_sclass[] = {
+	{ 0x506f, &nv50_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static int
+nv50_fifo_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nv50_fifo_base *base;
+	int ret;
+
+	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+				          0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1200, 0,
+				 NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, 0,
+				&base->pgd);
+	if (ret)
+		return ret;
+
+	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void
+nv50_fifo_context_dtor(struct nouveau_object *object)
+{
+	struct nv50_fifo_base *base = (void *)object;
+	nouveau_vm_ref(NULL, &base->vm, base->pgd);
+	nouveau_gpuobj_ref(NULL, &base->pgd);
+	nouveau_gpuobj_ref(NULL, &base->eng);
+	nouveau_gpuobj_ref(NULL, &base->ramfc);
+	nouveau_gpuobj_ref(NULL, &base->cache);
+	nouveau_fifo_context_destroy(&base->base);
+}
+
+static struct nouveau_oclass
+nv50_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_fifo_context_ctor,
+		.dtor = nv50_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
 	struct nv50_fifo_priv *priv;
 	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.base.destroy = nv50_fifo_destroy;
-	priv->base.base.init = nv50_fifo_init;
-	priv->base.base.fini = nv50_fifo_fini;
-	priv->base.base.context_new = nv50_fifo_context_new;
-	priv->base.base.context_del = nv50_fifo_context_del;
-	priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
-	priv->base.channels = 127;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
+	ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
+	ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
+				&priv->playlist[0]);
 	if (ret)
-		goto error;
+		return ret;
 
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
-error:
+	ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
+				&priv->playlist[1]);
 	if (ret)
-		priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
-	return ret;
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv50_fifo_cclass;
+	nv_engine(priv)->sclass = nv50_fifo_sclass;
+	return 0;
 }
+
+void
+nv50_fifo_dtor(struct nouveau_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object;
+
+	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
+	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+
+	nouveau_fifo_destroy(&priv->base);
+}
+
+int
+nv50_fifo_init(struct nouveau_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nouveau_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+	nv_wr32(priv, 0x00250c, 0x6f3cfc34);
+	nv_wr32(priv, 0x002044, 0x01003fff);
+
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0xffffffff);
+
+	for (i = 0; i < 128; i++)
+		nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
+	nv50_fifo_playlist_update(priv);
+
+	nv_wr32(priv, 0x003200, 0x00000001);
+	nv_wr32(priv, 0x003250, 0x00000001);
+	nv_wr32(priv, 0x002500, 0x00000001);
+	return 0;
+}
+
+struct nouveau_oclass
+nv50_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_fifo_ctor,
+		.dtor = nv50_fifo_dtor,
+		.init = nv50_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
new file mode 100644
index 0000000..3a9ceb3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
@@ -0,0 +1,36 @@
+#ifndef __NV50_FIFO_H__
+#define __NV50_FIFO_H__
+
+struct nv50_fifo_priv {
+	struct nouveau_fifo base;
+	struct nouveau_gpuobj *playlist[2];
+	int cur_playlist;
+};
+
+struct nv50_fifo_base {
+	struct nouveau_fifo_base base;
+	struct nouveau_gpuobj *ramfc;
+	struct nouveau_gpuobj *cache;
+	struct nouveau_gpuobj *eng;
+	struct nouveau_gpuobj *pgd;
+	struct nouveau_vm *vm;
+};
+
+struct nv50_fifo_chan {
+	struct nouveau_fifo_chan base;
+	u32 subc[8];
+	struct nouveau_ramht *ramht;
+};
+
+void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
+
+void nv50_fifo_object_detach(struct nouveau_object *, int);
+void nv50_fifo_chan_dtor(struct nouveau_object *);
+int  nv50_fifo_chan_fini(struct nouveau_object *, bool);
+
+void nv50_fifo_context_dtor(struct nouveau_object *);
+
+void nv50_fifo_dtor(struct nouveau_object *);
+int  nv50_fifo_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index 63a4941..765affb 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -1,249 +1,343 @@
 /*
- * Copyright (C) 2012 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
+#include <core/os.h>
+#include <core/client.h>
+#include <core/engctx.h>
 #include <core/ramht.h>
+#include <core/class.h>
+#include <core/math.h>
 
-struct nv84_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct nouveau_gpuobj *playlist[2];
-	int cur_playlist;
-};
+#include <subdev/timer.h>
+#include <subdev/bar.h>
 
-struct nv84_fifo_chan {
-	struct nouveau_fifo_chan base;
-	struct nouveau_gpuobj *ramfc;
-	struct nouveau_gpuobj *cache;
-};
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+
+#include "nv50.h"
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
 
 static int
-nv84_fifo_context_new(struct nouveau_channel *chan, int engine)
+nv84_fifo_context_attach(struct nouveau_object *parent,
+			 struct nouveau_object *object)
 {
-	struct nv84_fifo_priv *priv = nv_engine(chan->dev, engine);
-	struct nv84_fifo_chan *fctx;
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-        u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
-	u64 instance;
-	unsigned long flags;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nouveau_gpuobj *ectx = (void *)object;
+	u64 limit = ectx->addr + ectx->size - 1;
+	u64 start = ectx->addr;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0020; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
+	case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wo32(base->eng, addr + 0x00, 0x00190000);
+	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+					upper_32_bits(start));
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
+			 struct nouveau_object *object)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_priv *priv = (void *)parent->engine;
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0020; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
+	case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wo32(base->eng, addr + 0x00, 0x00000000);
+	nv_wo32(base->eng, addr + 0x04, 0x00000000);
+	nv_wo32(base->eng, addr + 0x08, 0x00000000);
+	nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+	if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
+		nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
+		if (suspend)
+			return -EBUSY;
+	}
+	return 0;
+}
+
+static int
+nv84_fifo_object_attach(struct nouveau_object *parent,
+			struct nouveau_object *object, u32 handle)
+{
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 context;
+
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->node->offset >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
+	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
+	case NVDEV_ENGINE_MPEG  :
+	case NVDEV_ENGINE_PPP   : context |= 0x00200000; break;
+	case NVDEV_ENGINE_ME    :
+	case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
+	case NVDEV_ENGINE_VP    : context |= 0x00400000; break;
+	case NVDEV_ENGINE_CRYPT :
+	case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break;
+	case NVDEV_ENGINE_BSP   : context |= 0x00600000; break;
+	default:
+		return -EINVAL;
+	}
+
+	return nouveau_ramht_insert(chan->ramht, 0, handle, context);
+}
+
+static int
+nv84_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	struct nv_channel_ind_class *args = data;
+	u64 ioffset, ilength;
 	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
-	nvvm_engref(chan->vm, engine, 1);
+	if (size < sizeof(*args))
+		return -EINVAL;
 
-	chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			     NV50_USER(chan->id), PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	ret = nouveau_gpuobj_new(dev, chan, 256, 256, NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+					  0x2000, args->pushbuf,
+					  (1 << NVDEV_ENGINE_DMAOBJ) |
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR) |
+					  (1 << NVDEV_ENGINE_MPEG) |
+					  (1 << NVDEV_ENGINE_ME) |
+					  (1 << NVDEV_ENGINE_VP) |
+					  (1 << NVDEV_ENGINE_CRYPT) |
+					  (1 << NVDEV_ENGINE_BSP) |
+					  (1 << NVDEV_ENGINE_PPP) |
+					  (1 << NVDEV_ENGINE_COPY0) |
+					  (1 << NVDEV_ENGINE_UNK1C1), &chan);
+	*pobject = nv_object(chan);
 	if (ret)
-		goto error;
+		return ret;
 
-	instance = fctx->ramfc->addr >> 8;
-
-	ret = nouveau_gpuobj_new(dev, chan, 4096, 1024, 0, &fctx->cache);
+	ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
 	if (ret)
-		goto error;
+		return ret;
 
-	nv_wo32(fctx->ramfc, 0x3c, 0x403f6078);
-	nv_wo32(fctx->ramfc, 0x40, 0x00000000);
-	nv_wo32(fctx->ramfc, 0x44, 0x01003fff);
-	nv_wo32(fctx->ramfc, 0x48, chan->pushbuf->node->offset >> 4);
-	nv_wo32(fctx->ramfc, 0x50, lower_32_bits(ib_offset));
-	nv_wo32(fctx->ramfc, 0x54, upper_32_bits(ib_offset) |
-				   drm_order(chan->dma.ib_max + 1) << 16);
-	nv_wo32(fctx->ramfc, 0x60, 0x7fffffff);
-	nv_wo32(fctx->ramfc, 0x78, 0x00000000);
-	nv_wo32(fctx->ramfc, 0x7c, 0x30000001);
-	nv_wo32(fctx->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+	nv_parent(chan)->context_attach = nv84_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv84_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv84_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	ioffset = args->ioffset;
+	ilength = log2i(args->ilength / 8);
+
+	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
 				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->gpuobj->node->offset >> 4));
-	nv_wo32(fctx->ramfc, 0x88, fctx->cache->addr >> 10);
-	nv_wo32(fctx->ramfc, 0x98, chan->ramin->addr >> 12);
+				   (chan->ramht->base.node->offset >> 4));
+	nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
+	nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
+	bar->flush(bar);
+	return 0;
+}
 
-	nv_wo32(chan->ramin, 0x00, chan->id);
-	nv_wo32(chan->ramin, 0x04, fctx->ramfc->addr >> 8);
+static int
+nv84_fifo_chan_init(struct nouveau_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_base *base = (void *)object->parent;
+	struct nv50_fifo_chan *chan = (void *)object;
+	struct nouveau_gpuobj *ramfc = base->ramfc;
+	u32 chid = chan->base.chid;
+	int ret;
 
-	nvimem_flush(dev);
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
-	nv50_fifo_playlist_update(dev);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-error:
+	ret = nouveau_fifo_channel_init(&chan->base);
 	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
-}
+		return ret;
 
-static void
-nv84_fifo_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv84_fifo_chan *fctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	unsigned long flags;
-	u32 save;
-
-	/* remove channel from playlist, will context switch if active */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
-	nv50_fifo_playlist_update(dev);
-
-	save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
-
-	/* tell any engines on this channel to unload their contexts */
-	nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
-	if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff))
-		NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
-
-	nv_wr32(dev, 0x002520, save);
-
-	nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* clean up */
-	if (chan->user) {
-		iounmap(chan->user);
-		chan->user = NULL;
-	}
-
-	nouveau_gpuobj_ref(NULL, &fctx->ramfc);
-	nouveau_gpuobj_ref(NULL, &fctx->cache);
-
-	nvvm_engref(chan->vm, engine, -1);
-	chan->engctx[engine] = NULL;
-	kfree(fctx);
-}
-
-static int
-nv84_fifo_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv84_fifo_chan *fctx;
-	u32 instance;
-	int i;
-
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(dev, 0x00250c, 0x6f3cfc34);
-	nv_wr32(dev, 0x002044, 0x01003fff);
-
-	nv_wr32(dev, 0x002100, 0xffffffff);
-	nv_wr32(dev, 0x002140, 0xffffffff);
-
-	for (i = 0; i < 128; i++) {
-		struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-		if (chan && (fctx = chan->engctx[engine]))
-			instance = 0x80000000 | fctx->ramfc->addr >> 8;
-		else
-			instance = 0x00000000;
-		nv_wr32(dev, 0x002600 + (i * 4), instance);
-	}
-
-	nv50_fifo_playlist_update(dev);
-
-	nv_wr32(dev, 0x003200, 1);
-	nv_wr32(dev, 0x003250, 1);
-	nv_wr32(dev, 0x002500, 1);
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
+	nv50_fifo_playlist_update(priv);
 	return 0;
 }
 
-static int
-nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv84_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
-	u32 save;
+static struct nouveau_ofuncs
+nv84_fifo_ofuncs = {
+	.ctor = nv84_fifo_chan_ctor,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = nv84_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
 
-	/* set playlist length to zero, fifo will unload context */
-	nv_wr32(dev, 0x0032ec, 0);
+static struct nouveau_oclass
+nv84_fifo_sclass[] = {
+	{ 0x826f, &nv84_fifo_ofuncs },
+	{}
+};
 
-	save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
-
-	/* tell all connected engines to unload their contexts */
-	for (i = 0; i < priv->base.channels; i++) {
-		struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-		if (chan)
-			nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
-		if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
-			NV_INFO(dev, "PFIFO: channel %d unload timeout\n", i);
-			return -EBUSY;
-		}
-	}
-
-	nv_wr32(dev, 0x002520, save);
-	nv_wr32(dev, 0x002140, 0);
-	return 0;
-}
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
 
 int
-nv84_fifo_create(struct drm_device *dev)
+nv84_fifo_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv84_fifo_priv *priv;
+	struct nv50_fifo_base *base;
 	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.base.destroy = nv50_fifo_destroy;
-	priv->base.base.init = nv84_fifo_init;
-	priv->base.base.fini = nv84_fifo_fini;
-	priv->base.base.context_new = nv84_fifo_context_new;
-	priv->base.base.context_del = nv84_fifo_context_del;
-	priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
-	priv->base.channels = 127;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
+	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+				          0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0,
+				 NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
 	if (ret)
-		goto error;
+		return ret;
 
-	nouveau_irq_register(dev, 8, nv04_fifo_isr);
-error:
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0,
+				 0, &base->pgd);
 	if (ret)
-		priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
-	return ret;
+		return ret;
+
+	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1000, 0x400,
+				 NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0100, 0x100,
+				 NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+	if (ret)
+		return ret;
+
+	return 0;
 }
+
+static struct nouveau_oclass
+nv84_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_fifo_context_ctor,
+		.dtor = nv50_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv50_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
+				&priv->playlist[0]);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
+				&priv->playlist[1]);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv84_fifo_cclass;
+	nv_engine(priv)->sclass = nv84_fifo_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv84_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_fifo_ctor,
+		.dtor = nv50_fifo_dtor,
+		.init = nv50_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index b99d976..ef403fe 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,17 +22,24 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
+#include <core/client.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+#include <core/gpuobj.h>
+#include <core/engctx.h>
+#include <core/class.h>
+#include <core/math.h>
+#include <core/enum.h>
 
-#include "nouveau_drv.h"
-#include <core/mm.h>
+#include <subdev/timer.h>
+#include <subdev/bar.h>
+#include <subdev/vm.h>
+
+#include <engine/dmaobj.h>
 #include <engine/fifo.h>
-#include "nouveau_software.h"
-
-static void nvc0_fifo_isr(struct drm_device *);
 
 struct nvc0_fifo_priv {
-	struct nouveau_fifo_priv base;
+	struct nouveau_fifo base;
 	struct nouveau_gpuobj *playlist[2];
 	int cur_playlist;
 	struct {
@@ -42,14 +49,24 @@
 	int spoon_nr;
 };
 
+struct nvc0_fifo_base {
+	struct nouveau_fifo_base base;
+	struct nouveau_gpuobj *pgd;
+	struct nouveau_vm *vm;
+};
+
 struct nvc0_fifo_chan {
 	struct nouveau_fifo_chan base;
 };
 
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
 static void
-nvc0_fifo_playlist_update(struct drm_device *dev)
+nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
 {
-	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+	struct nouveau_bar *bar = nouveau_bar(priv);
 	struct nouveau_gpuobj *cur;
 	int i, p;
 
@@ -57,174 +74,253 @@
 	priv->cur_playlist = !priv->cur_playlist;
 
 	for (i = 0, p = 0; i < 128; i++) {
-		if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1))
+		if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1))
 			continue;
 		nv_wo32(cur, p + 0, i);
 		nv_wo32(cur, p + 4, 0x00000004);
 		p += 8;
 	}
-	nvimem_flush(dev);
+	bar->flush(bar);
 
-	nv_wr32(dev, 0x002270, cur->addr >> 12);
-	nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3));
-	if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000))
-		NV_ERROR(dev, "PFIFO - playlist update failed\n");
+	nv_wr32(priv, 0x002270, cur->addr >> 12);
+	nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
+	if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
+		nv_error(priv, "playlist update failed\n");
 }
 
 static int
-nvc0_fifo_context_new(struct nouveau_channel *chan, int engine)
+nvc0_fifo_context_attach(struct nouveau_object *parent,
+			 struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
-	struct nvc0_fifo_chan *fctx;
-	u64 usermem = priv->user.mem->addr + chan->id * 0x1000;
-	u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-	int ret, i;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nvc0_fifo_base *base = (void *)parent->parent;
+	struct nouveau_engctx *ectx = (void *)object;
+	u32 addr;
+	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
-
-	chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
-				priv->user.bar.offset + (chan->id * 0x1000),
-				PAGE_SIZE);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
+	case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
+	default:
+		return -EINVAL;
 	}
 
-	for (i = 0; i < 0x100; i += 4)
-		nv_wo32(chan->ramin, i, 0x00000000);
-	nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
-	nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
-	nv_wo32(chan->ramin, 0x10, 0x0000face);
-	nv_wo32(chan->ramin, 0x30, 0xfffff902);
-	nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
-	nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
-				   upper_32_bits(ib_virt));
-	nv_wo32(chan->ramin, 0x54, 0x00000002);
-	nv_wo32(chan->ramin, 0x84, 0x20400000);
-	nv_wo32(chan->ramin, 0x94, 0x30000001);
-	nv_wo32(chan->ramin, 0x9c, 0x00000100);
-	nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f);
-	nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f);
-	nv_wo32(chan->ramin, 0xac, 0x0000001f);
-	nv_wo32(chan->ramin, 0xb8, 0xf8000000);
-	nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
-	nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
-	nvimem_flush(dev);
+	if (!ectx->vma.node) {
+		ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+					    NV_MEM_ACCESS_RW, &ectx->vma);
+		if (ret)
+			return ret;
+	}
 
-	nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 |
-						(chan->ramin->addr >> 12));
-	nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001);
-	nvc0_fifo_playlist_update(dev);
+	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+	bar->flush(bar);
+	return 0;
+}
 
-error:
+static int
+nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
+			 struct nouveau_object *object)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nvc0_fifo_priv *priv = (void *)parent->engine;
+	struct nvc0_fifo_base *base = (void *)parent->parent;
+	struct nvc0_fifo_chan *chan = (void *)parent;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
+	case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wo32(base, addr + 0x00, 0x00000000);
+	nv_wo32(base, addr + 0x04, 0x00000000);
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x002634, chan->base.chid);
+	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+		nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
+		if (suspend)
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+nvc0_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nvc0_fifo_priv *priv = (void *)engine;
+	struct nvc0_fifo_base *base = (void *)parent;
+	struct nvc0_fifo_chan *chan;
+	struct nv_channel_ind_class *args = data;
+	u64 usermem, ioffset, ilength;
+	int ret, i;
+
+	if (size < sizeof(*args))
+		return -EINVAL;
+
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
+					  priv->user.bar.offset, 0x1000,
+					  args->pushbuf,
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR) |
+					  (1 << NVDEV_ENGINE_COPY0) |
+					  (1 << NVDEV_ENGINE_COPY1), &chan);
+	*pobject = nv_object(chan);
 	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+		return ret;
+
+	nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
+	nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
+
+	usermem = chan->base.chid * 0x1000;
+	ioffset = args->ioffset;
+	ilength = log2i(args->ilength / 8);
+
+	for (i = 0; i < 0x1000; i += 4)
+		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x10, 0x0000face);
+	nv_wo32(base, 0x30, 0xfffff902);
+	nv_wo32(base, 0x48, lower_32_bits(ioffset));
+	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base, 0x54, 0x00000002);
+	nv_wo32(base, 0x84, 0x20400000);
+	nv_wo32(base, 0x94, 0x30000001);
+	nv_wo32(base, 0x9c, 0x00000100);
+	nv_wo32(base, 0xa4, 0x1f1f1f1f);
+	nv_wo32(base, 0xa8, 0x1f1f1f1f);
+	nv_wo32(base, 0xac, 0x0000001f);
+	nv_wo32(base, 0xb8, 0xf8000000);
+	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+nvc0_fifo_chan_init(struct nouveau_object *object)
+{
+	struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
+	struct nvc0_fifo_priv *priv = (void *)object->engine;
+	struct nvc0_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nouveau_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
+	nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
+	nvc0_fifo_playlist_update(priv);
+	return 0;
+}
+
+static int
+nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nvc0_fifo_priv *priv = (void *)object->engine;
+	struct nvc0_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
+	nvc0_fifo_playlist_update(priv);
+	nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
+
+	return nouveau_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nouveau_ofuncs
+nvc0_fifo_ofuncs = {
+	.ctor = nvc0_fifo_chan_ctor,
+	.dtor = _nouveau_fifo_channel_dtor,
+	.init = nvc0_fifo_chan_init,
+	.fini = nvc0_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
+
+static struct nouveau_oclass
+nvc0_fifo_sclass[] = {
+	{ 0x906f, &nvc0_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+nvc0_fifo_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nvc0_fifo_base *base;
+	int ret;
+
+	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				          0x1000, NVOBJ_FLAG_ZERO_ALLOC |
+					  NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
+	if (ret)
+		return ret;
+
+	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0208, 0xffffffff);
+	nv_wo32(base, 0x020c, 0x000000ff);
+
+	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static void
-nvc0_fifo_context_del(struct nouveau_channel *chan, int engine)
+nvc0_fifo_context_dtor(struct nouveau_object *object)
 {
-	struct nvc0_fifo_chan *fctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-
-	nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
-	nv_wr32(dev, 0x002634, chan->id);
-	if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
-		NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
-	nvc0_fifo_playlist_update(dev);
-	nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000);
-
-	if (chan->user) {
-		iounmap(chan->user);
-		chan->user = NULL;
-	}
-
-	chan->engctx[engine] = NULL;
-	kfree(fctx);
+	struct nvc0_fifo_base *base = (void *)object;
+	nouveau_vm_ref(NULL, &base->vm, base->pgd);
+	nouveau_gpuobj_ref(NULL, &base->pgd);
+	nouveau_fifo_context_destroy(&base->base);
 }
 
-static int
-nvc0_fifo_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
-	struct nouveau_channel *chan;
-	int i;
+static struct nouveau_oclass
+nvc0_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_fifo_context_ctor,
+		.dtor = nvc0_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
 
-	/* reset PFIFO, enable all available PSUBFIFO areas */
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(dev, 0x000204, 0xffffffff);
-	nv_wr32(dev, 0x002204, 0xffffffff);
-
-	priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204));
-	NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
-
-	/* assign engines to subfifos */
-	if (priv->spoon_nr >= 3) {
-		nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */
-		nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */
-		nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */
-		nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */
-		nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */
-		nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */
-	}
-
-	/* PSUBFIFO[n] */
-	for (i = 0; i < priv->spoon_nr; i++) {
-		nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
-		nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
-		nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
-	}
-
-	nv_mask(dev, 0x002200, 0x00000001, 0x00000001);
-	nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
-	nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
-	nv_wr32(dev, 0x002100, 0xffffffff);
-	nv_wr32(dev, 0x002140, 0xbfffffff);
-
-	/* restore PFIFO context table */
-	for (i = 0; i < 128; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->engctx[engine])
-			continue;
-
-		nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
-						 (chan->ramin->addr >> 12));
-		nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
-	}
-	nvc0_fifo_playlist_update(dev);
-
-	return 0;
-}
-
-static int
-nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	int i;
-
-	for (i = 0; i < 128; i++) {
-		if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1))
-			continue;
-
-		nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000);
-		nv_wr32(dev, 0x002634, i);
-		if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
-			NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
-				i, nv_rd32(dev, 0x002634));
-			return -EBUSY;
-		}
-	}
-
-	nv_wr32(dev, 0x002140, 0x00000000);
-	return 0;
-}
-
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
 
 struct nouveau_enum nvc0_fifo_fault_unit[] = {
 	{ 0x00, "PGRAPH" },
@@ -289,16 +385,16 @@
 };
 
 static void
-nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
+nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
 {
-	u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
-	u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
-	u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
-	u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+	u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
+	u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
+	u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
+	u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
 	u32 client = (stat & 0x00001f00) >> 8;
 
-	NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
-		(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
+	nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
+		 "write" : "read", (u64)vahi << 32 | valo);
 	nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
 	printk("] from ");
 	nouveau_enum_print(nvc0_fifo_fault_unit, unit);
@@ -313,165 +409,223 @@
 }
 
 static int
-nvc0_fifo_page_flip(struct drm_device *dev, u32 chid)
+nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
 {
-	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
+	struct nvc0_fifo_chan *chan = NULL;
+	struct nouveau_handle *bind;
 	unsigned long flags;
 	int ret = -EINVAL;
 
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	if (likely(chid >= 0 && chid < priv->base.channels)) {
-		chan = dev_priv->channels.ptr[chid];
-		if (likely(chan)) {
-			struct nouveau_software_chan *swch =
-				chan->engctx[NVOBJ_ENGINE_SW];
-			ret = swch->flip(swch->flip_data);
-		}
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
+	if (likely(bind)) {
+		if (!mthd || !nv_call(bind->object, mthd, data))
+			ret = 0;
+		nouveau_namedb_put(bind);
 	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
 	return ret;
 }
 
 static void
-nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
+nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
 {
-	u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
-	u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
-	u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
-	u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
-	u32 subc = (addr & 0x00070000);
+	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
+	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
+	u32 subc = (addr & 0x00070000) >> 16;
 	u32 mthd = (addr & 0x00003ffc);
 	u32 show = stat;
 
 	if (stat & 0x00200000) {
 		if (mthd == 0x0054) {
-			if (!nvc0_fifo_page_flip(dev, chid))
+			if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
 				show &= ~0x00200000;
 		}
 	}
 
-	if (show) {
-		NV_INFO(dev, "PFIFO%d:", unit);
-		nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
-		NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
-			     unit, chid, subc, mthd, data);
+	if (stat & 0x00800000) {
+		if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
+			show &= ~0x00800000;
 	}
 
-	nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
-	nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
+	if (show) {
+		nv_error(priv, "SUBFIFO%d:", unit);
+		nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
+		printk("\n");
+		nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
+			       "data 0x%08x\n",
+			 unit, chid, subc, mthd, data);
+	}
+
+	nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
 }
 
 static void
-nvc0_fifo_isr(struct drm_device *dev)
+nvc0_fifo_intr(struct nouveau_subdev *subdev)
 {
-	u32 mask = nv_rd32(dev, 0x002140);
-	u32 stat = nv_rd32(dev, 0x002100) & mask;
+	struct nvc0_fifo_priv *priv = (void *)subdev;
+	u32 mask = nv_rd32(priv, 0x002140);
+	u32 stat = nv_rd32(priv, 0x002100) & mask;
 
 	if (stat & 0x00000100) {
-		NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
-		nv_wr32(dev, 0x002100, 0x00000100);
+		nv_info(priv, "unknown status 0x00000100\n");
+		nv_wr32(priv, 0x002100, 0x00000100);
 		stat &= ~0x00000100;
 	}
 
 	if (stat & 0x10000000) {
-		u32 units = nv_rd32(dev, 0x00259c);
+		u32 units = nv_rd32(priv, 0x00259c);
 		u32 u = units;
 
 		while (u) {
 			int i = ffs(u) - 1;
-			nvc0_fifo_isr_vm_fault(dev, i);
+			nvc0_fifo_isr_vm_fault(priv, i);
 			u &= ~(1 << i);
 		}
 
-		nv_wr32(dev, 0x00259c, units);
+		nv_wr32(priv, 0x00259c, units);
 		stat &= ~0x10000000;
 	}
 
 	if (stat & 0x20000000) {
-		u32 units = nv_rd32(dev, 0x0025a0);
+		u32 units = nv_rd32(priv, 0x0025a0);
 		u32 u = units;
 
 		while (u) {
 			int i = ffs(u) - 1;
-			nvc0_fifo_isr_subfifo_intr(dev, i);
+			nvc0_fifo_isr_subfifo_intr(priv, i);
 			u &= ~(1 << i);
 		}
 
-		nv_wr32(dev, 0x0025a0, units);
+		nv_wr32(priv, 0x0025a0, units);
 		stat &= ~0x20000000;
 	}
 
 	if (stat & 0x40000000) {
-		NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
-		nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
+		nv_warn(priv, "unknown status 0x40000000\n");
+		nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
 		stat &= ~0x40000000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
-		nv_wr32(dev, 0x002100, stat);
-		nv_wr32(dev, 0x002140, 0);
+		nv_fatal(priv, "unhandled status 0x%08x\n", stat);
+		nv_wr32(priv, 0x002100, stat);
+		nv_wr32(priv, 0x002140, 0);
 	}
 }
 
-static void
-nvc0_fifo_destroy(struct drm_device *dev, int engine)
+static int
+nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	nouveau_gpuobj_unmap(&priv->user.bar);
-	nouveau_gpuobj_ref(NULL, &priv->user.mem);
-
-	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
-	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
-
-	dev_priv->eng[engine] = NULL;
-	kfree(priv);
-}
-
-int
-nvc0_fifo_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nvc0_fifo_priv *priv;
 	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.base.destroy = nvc0_fifo_destroy;
-	priv->base.base.init = nvc0_fifo_init;
-	priv->base.base.fini = nvc0_fifo_fini;
-	priv->base.base.context_new = nvc0_fifo_context_new;
-	priv->base.base.context_del = nvc0_fifo_context_del;
-	priv->base.channels = 128;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]);
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
+				&priv->playlist[0]);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4096, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
+				&priv->playlist[1]);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW,
-				    &priv->user.bar);
+	ret = nouveau_gpuobj_new(parent, NULL, 128 * 0x1000, 0x1000, 0,
+				&priv->user.mem);
 	if (ret)
-		goto error;
+		return ret;
 
-	nouveau_irq_register(dev, 8, nvc0_fifo_isr);
-error:
+	ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+				&priv->user.bar);
 	if (ret)
-		priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
-	return ret;
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nvc0_fifo_intr;
+	nv_engine(priv)->cclass = &nvc0_fifo_cclass;
+	nv_engine(priv)->sclass = nvc0_fifo_sclass;
+	return 0;
 }
+
+static void
+nvc0_fifo_dtor(struct nouveau_object *object)
+{
+	struct nvc0_fifo_priv *priv = (void *)object;
+
+	nouveau_gpuobj_unmap(&priv->user.bar);
+	nouveau_gpuobj_ref(NULL, &priv->user.mem);
+	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
+	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+
+	nouveau_fifo_destroy(&priv->base);
+}
+
+static int
+nvc0_fifo_init(struct nouveau_object *object)
+{
+	struct nvc0_fifo_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nouveau_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x000204, 0xffffffff);
+	nv_wr32(priv, 0x002204, 0xffffffff);
+
+	priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
+	nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
+
+	/* assign engines to subfifos */
+	if (priv->spoon_nr >= 3) {
+		nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
+		nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
+		nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
+		nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
+		nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
+		nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
+	}
+
+	/* PSUBFIFO[n] */
+	for (i = 0; i < priv->spoon_nr; i++) {
+		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+	}
+
+	nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
+	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+	nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0xbfffffff);
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_fifo_ctor,
+		.dtor = nvc0_fifo_dtor,
+		.init = nvc0_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 0b356f1..aaff086 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,25 +22,30 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
+#include <core/client.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+#include <core/gpuobj.h>
+#include <core/engctx.h>
+#include <core/class.h>
+#include <core/math.h>
+#include <core/enum.h>
 
-#include "nouveau_drv.h"
-#include <core/mm.h>
+#include <subdev/timer.h>
+#include <subdev/bar.h>
+#include <subdev/vm.h>
+
+#include <engine/dmaobj.h>
 #include <engine/fifo.h>
-#include "nouveau_software.h"
 
-#define NVE0_FIFO_ENGINE_NUM 32
-
-static void nve0_fifo_isr(struct drm_device *);
-
-struct nve0_fifo_engine {
+struct nve0_fifo_engn {
 	struct nouveau_gpuobj *playlist[2];
 	int cur_playlist;
 };
 
 struct nve0_fifo_priv {
-	struct nouveau_fifo_priv base;
-	struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM];
+	struct nouveau_fifo base;
+	struct nve0_fifo_engn engine[16];
 	struct {
 		struct nouveau_gpuobj *mem;
 		struct nouveau_vma bar;
@@ -48,193 +53,285 @@
 	int spoon_nr;
 };
 
+struct nve0_fifo_base {
+	struct nouveau_fifo_base base;
+	struct nouveau_gpuobj *pgd;
+	struct nouveau_vm *vm;
+};
+
 struct nve0_fifo_chan {
 	struct nouveau_fifo_chan base;
 	u32 engine;
 };
 
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
 static void
-nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
+nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
 {
-	struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct nve0_fifo_engine *peng = &priv->engine[engine];
+	struct nouveau_bar *bar = nouveau_bar(priv);
+	struct nve0_fifo_engn *engn = &priv->engine[engine];
 	struct nouveau_gpuobj *cur;
 	u32 match = (engine << 16) | 0x00000001;
-	int ret, i, p;
+	int i, p;
 
-	cur = peng->playlist[peng->cur_playlist];
+	cur = engn->playlist[engn->cur_playlist];
 	if (unlikely(cur == NULL)) {
-		ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 0x1000, 0, &cur);
+		int ret = nouveau_gpuobj_new(nv_object(priv)->parent, NULL,
+					     0x8000, 0x1000, 0, &cur);
 		if (ret) {
-			NV_ERROR(dev, "PFIFO: playlist alloc failed\n");
+			nv_error(priv, "playlist alloc failed\n");
 			return;
 		}
 
-		peng->playlist[peng->cur_playlist] = cur;
+		engn->playlist[engn->cur_playlist] = cur;
 	}
 
-	peng->cur_playlist = !peng->cur_playlist;
+	engn->cur_playlist = !engn->cur_playlist;
 
-	for (i = 0, p = 0; i < priv->base.channels; i++) {
-		u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001;
+	for (i = 0, p = 0; i < priv->base.max; i++) {
+		u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001;
 		if (ctrl != match)
 			continue;
 		nv_wo32(cur, p + 0, i);
 		nv_wo32(cur, p + 4, 0x00000000);
 		p += 8;
 	}
-	nvimem_flush(dev);
+	bar->flush(bar);
 
-	nv_wr32(dev, 0x002270, cur->addr >> 12);
-	nv_wr32(dev, 0x002274, (engine << 20) | (p >> 3));
-	if (!nv_wait(dev, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
-		NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine);
+	nv_wr32(priv, 0x002270, cur->addr >> 12);
+	nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
+	if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
+		nv_error(priv, "playlist %d update timeout\n", engine);
 }
 
 static int
-nve0_fifo_context_new(struct nouveau_channel *chan, int engine)
+nve0_fifo_context_attach(struct nouveau_object *parent,
+			 struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	struct nve0_fifo_priv *priv = nv_engine(dev, engine);
-	struct nve0_fifo_chan *fctx;
-	u64 usermem = priv->user.mem->addr + chan->id * 512;
-	u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-	int ret = 0, i;
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nve0_fifo_base *base = (void *)parent->parent;
+	struct nouveau_engctx *ectx = (void *)object;
+	u32 addr;
+	int ret;
 
-	fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
-
-	fctx->engine = 0; /* PGRAPH */
-
-	/* allocate vram for control regs, map into polling area */
-	chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
-				priv->user.bar.offset + (chan->id * 512), 512);
-	if (!chan->user) {
-		ret = -ENOMEM;
-		goto error;
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	default:
+		return -EINVAL;
 	}
 
-	for (i = 0; i < 0x100; i += 4)
-		nv_wo32(chan->ramin, i, 0x00000000);
-	nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
-	nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
-	nv_wo32(chan->ramin, 0x10, 0x0000face);
-	nv_wo32(chan->ramin, 0x30, 0xfffff902);
-	nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
-	nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
-				     upper_32_bits(ib_virt));
-	nv_wo32(chan->ramin, 0x84, 0x20400000);
-	nv_wo32(chan->ramin, 0x94, 0x30000001);
-	nv_wo32(chan->ramin, 0x9c, 0x00000100);
-	nv_wo32(chan->ramin, 0xac, 0x0000001f);
-	nv_wo32(chan->ramin, 0xe4, 0x00000000);
-	nv_wo32(chan->ramin, 0xe8, chan->id);
-	nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
-	nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
-	nvimem_flush(dev);
+	if (!ectx->vma.node) {
+		ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+					    NV_MEM_ACCESS_RW, &ectx->vma);
+		if (ret)
+			return ret;
+	}
 
-	nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 |
-						(chan->ramin->addr >> 12));
-	nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
-	nve0_fifo_playlist_update(dev, fctx->engine);
-	nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
+	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+	bar->flush(bar);
+	return 0;
+}
 
-error:
+static int
+nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
+			 struct nouveau_object *object)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nve0_fifo_priv *priv = (void *)parent->engine;
+	struct nve0_fifo_base *base = (void *)parent->parent;
+	struct nve0_fifo_chan *chan = (void *)parent;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wo32(base, addr + 0x00, 0x00000000);
+	nv_wo32(base, addr + 0x04, 0x00000000);
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x002634, chan->base.chid);
+	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+		nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
+		if (suspend)
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+nve0_fifo_chan_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nve0_fifo_priv *priv = (void *)engine;
+	struct nve0_fifo_base *base = (void *)parent;
+	struct nve0_fifo_chan *chan;
+	struct nv_channel_ind_class *args = data;
+	u64 usermem, ioffset, ilength;
+	int ret, i;
+
+	if (size < sizeof(*args))
+		return -EINVAL;
+
+	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
+					  priv->user.bar.offset, 0x200,
+					  args->pushbuf,
+					  (1 << NVDEV_ENGINE_SW) |
+					  (1 << NVDEV_ENGINE_GR), &chan);
+	*pobject = nv_object(chan);
 	if (ret)
-		priv->base.base.context_del(chan, engine);
-	return ret;
+		return ret;
+
+	nv_parent(chan)->context_attach = nve0_fifo_context_attach;
+	nv_parent(chan)->context_detach = nve0_fifo_context_detach;
+
+	usermem = chan->base.chid * 0x200;
+	ioffset = args->ioffset;
+	ilength = log2i(args->ilength / 8);
+
+	for (i = 0; i < 0x200; i += 4)
+		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x10, 0x0000face);
+	nv_wo32(base, 0x30, 0xfffff902);
+	nv_wo32(base, 0x48, lower_32_bits(ioffset));
+	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base, 0x84, 0x20400000);
+	nv_wo32(base, 0x94, 0x30000001);
+	nv_wo32(base, 0x9c, 0x00000100);
+	nv_wo32(base, 0xac, 0x0000001f);
+	nv_wo32(base, 0xe8, chan->base.chid);
+	nv_wo32(base, 0xb8, 0xf8000000);
+	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+nve0_fifo_chan_init(struct nouveau_object *object)
+{
+	struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
+	struct nve0_fifo_priv *priv = (void *)object->engine;
+	struct nve0_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nouveau_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
+	nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+	nve0_fifo_playlist_update(priv, chan->engine);
+	nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+	return 0;
+}
+
+static int
+nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nve0_fifo_priv *priv = (void *)object->engine;
+	struct nve0_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
+	nve0_fifo_playlist_update(priv, chan->engine);
+	nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
+
+	return nouveau_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nouveau_ofuncs
+nve0_fifo_ofuncs = {
+	.ctor = nve0_fifo_chan_ctor,
+	.dtor = _nouveau_fifo_channel_dtor,
+	.init = nve0_fifo_chan_init,
+	.fini = nve0_fifo_chan_fini,
+	.rd32 = _nouveau_fifo_channel_rd32,
+	.wr32 = _nouveau_fifo_channel_wr32,
+};
+
+static struct nouveau_oclass
+nve0_fifo_sclass[] = {
+	{ 0xa06f, &nve0_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+nve0_fifo_context_ctor(struct nouveau_object *parent,
+		    struct nouveau_object *engine,
+		    struct nouveau_oclass *oclass, void *data, u32 size,
+		    struct nouveau_object **pobject)
+{
+	struct nve0_fifo_base *base;
+	int ret;
+
+	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				          0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
+	if (ret)
+		return ret;
+
+	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0208, 0xffffffff);
+	nv_wo32(base, 0x020c, 0x000000ff);
+
+	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static void
-nve0_fifo_context_del(struct nouveau_channel *chan, int engine)
+nve0_fifo_context_dtor(struct nouveau_object *object)
 {
-	struct nve0_fifo_chan *fctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-
-	nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
-	nv_wr32(dev, 0x002634, chan->id);
-	if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
-		NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
-	nve0_fifo_playlist_update(dev, fctx->engine);
-	nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000);
-
-	if (chan->user) {
-		iounmap(chan->user);
-		chan->user = NULL;
-	}
-
-	chan->engctx[NVOBJ_ENGINE_FIFO] = NULL;
-	kfree(fctx);
+	struct nve0_fifo_base *base = (void *)object;
+	nouveau_vm_ref(NULL, &base->vm, base->pgd);
+	nouveau_gpuobj_ref(NULL, &base->pgd);
+	nouveau_fifo_context_destroy(&base->base);
 }
 
-static int
-nve0_fifo_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nve0_fifo_priv *priv = nv_engine(dev, engine);
-	struct nve0_fifo_chan *fctx;
-	int i;
+static struct nouveau_oclass
+nve0_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0xe0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nve0_fifo_context_ctor,
+		.dtor = nve0_fifo_context_dtor,
+		.init = _nouveau_fifo_context_init,
+		.fini = _nouveau_fifo_context_fini,
+		.rd32 = _nouveau_fifo_context_rd32,
+		.wr32 = _nouveau_fifo_context_wr32,
+	},
+};
 
-	/* reset PFIFO, enable all available PSUBFIFO areas */
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(dev, 0x000204, 0xffffffff);
-
-	priv->spoon_nr = hweight32(nv_rd32(dev, 0x000204));
-	NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
-
-	/* PSUBFIFO[n] */
-	for (i = 0; i < priv->spoon_nr; i++) {
-		nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
-		nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
-		nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
-	}
-
-	nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
-	nv_wr32(dev, 0x002a00, 0xffffffff);
-	nv_wr32(dev, 0x002100, 0xffffffff);
-	nv_wr32(dev, 0x002140, 0xbfffffff);
-
-	/* restore PFIFO context table */
-	for (i = 0; i < priv->base.channels; i++) {
-		struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-		if (!chan || !(fctx = chan->engctx[engine]))
-			continue;
-
-		nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 |
-						 (chan->ramin->addr >> 12));
-		nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
-		nve0_fifo_playlist_update(dev, fctx->engine);
-		nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
-	}
-
-	return 0;
-}
-
-static int
-nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	struct nve0_fifo_priv *priv = nv_engine(dev, engine);
-	int i;
-
-	for (i = 0; i < priv->base.channels; i++) {
-		if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
-			continue;
-
-		nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
-		nv_wr32(dev, 0x002634, i);
-		if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
-			NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
-				i, nv_rd32(dev, 0x002634));
-			return -EBUSY;
-		}
-	}
-
-	nv_wr32(dev, 0x002140, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
 
 struct nouveau_enum nve0_fifo_fault_unit[] = {
 	{}
@@ -268,16 +365,16 @@
 };
 
 static void
-nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
+nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
 {
-	u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
-	u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
-	u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
-	u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+	u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
+	u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
+	u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
+	u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
 	u32 client = (stat & 0x00001f00) >> 8;
 
-	NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
-		(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
+	nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
+		       "write" : "read", (u64)vahi << 32 | valo);
 	nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
 	printk("] from ");
 	nouveau_enum_print(nve0_fifo_fault_unit, unit);
@@ -292,160 +389,205 @@
 }
 
 static int
-nve0_fifo_page_flip(struct drm_device *dev, u32 chid)
+nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
 {
-	struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
+	struct nve0_fifo_chan *chan = NULL;
+	struct nouveau_handle *bind;
 	unsigned long flags;
 	int ret = -EINVAL;
 
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	if (likely(chid >= 0 && chid < priv->base.channels)) {
-		chan = dev_priv->channels.ptr[chid];
-		if (likely(chan)) {
-			struct nouveau_software_chan *swch =
-				chan->engctx[NVOBJ_ENGINE_SW];
-			ret = swch->flip(swch->flip_data);
-		}
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
+	if (likely(bind)) {
+		if (!mthd || !nv_call(bind->object, mthd, data))
+			ret = 0;
+		nouveau_namedb_put(bind);
 	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
 	return ret;
 }
 
 static void
-nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
+nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
 {
-	u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
-	u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
-	u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
-	u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0xfff;
-	u32 subc = (addr & 0x00070000);
+	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
+	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+	u32 subc = (addr & 0x00070000) >> 16;
 	u32 mthd = (addr & 0x00003ffc);
 	u32 show = stat;
 
 	if (stat & 0x00200000) {
 		if (mthd == 0x0054) {
-			if (!nve0_fifo_page_flip(dev, chid))
+			if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
 				show &= ~0x00200000;
 		}
 	}
 
-	if (show) {
-		NV_INFO(dev, "PFIFO%d:", unit);
-		nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
-		NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
-			unit, chid, subc, mthd, data);
+	if (stat & 0x00800000) {
+		if (!nve0_fifo_swmthd(priv, chid, mthd, data))
+			show &= ~0x00800000;
 	}
 
-	nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
-	nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
+	if (show) {
+		nv_error(priv, "SUBFIFO%d:", unit);
+		nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
+		printk("\n");
+		nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
+			       "data 0x%08x\n",
+			 unit, chid, subc, mthd, data);
+	}
+
+	nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
 }
 
 static void
-nve0_fifo_isr(struct drm_device *dev)
+nve0_fifo_intr(struct nouveau_subdev *subdev)
 {
-	u32 mask = nv_rd32(dev, 0x002140);
-	u32 stat = nv_rd32(dev, 0x002100) & mask;
+	struct nve0_fifo_priv *priv = (void *)subdev;
+	u32 mask = nv_rd32(priv, 0x002140);
+	u32 stat = nv_rd32(priv, 0x002100) & mask;
 
 	if (stat & 0x00000100) {
-		NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
-		nv_wr32(dev, 0x002100, 0x00000100);
+		nv_warn(priv, "unknown status 0x00000100\n");
+		nv_wr32(priv, 0x002100, 0x00000100);
 		stat &= ~0x00000100;
 	}
 
 	if (stat & 0x10000000) {
-		u32 units = nv_rd32(dev, 0x00259c);
+		u32 units = nv_rd32(priv, 0x00259c);
 		u32 u = units;
 
 		while (u) {
 			int i = ffs(u) - 1;
-			nve0_fifo_isr_vm_fault(dev, i);
+			nve0_fifo_isr_vm_fault(priv, i);
 			u &= ~(1 << i);
 		}
 
-		nv_wr32(dev, 0x00259c, units);
+		nv_wr32(priv, 0x00259c, units);
 		stat &= ~0x10000000;
 	}
 
 	if (stat & 0x20000000) {
-		u32 units = nv_rd32(dev, 0x0025a0);
+		u32 units = nv_rd32(priv, 0x0025a0);
 		u32 u = units;
 
 		while (u) {
 			int i = ffs(u) - 1;
-			nve0_fifo_isr_subfifo_intr(dev, i);
+			nve0_fifo_isr_subfifo_intr(priv, i);
 			u &= ~(1 << i);
 		}
 
-		nv_wr32(dev, 0x0025a0, units);
+		nv_wr32(priv, 0x0025a0, units);
 		stat &= ~0x20000000;
 	}
 
 	if (stat & 0x40000000) {
-		NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
-		nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
+		nv_warn(priv, "unknown status 0x40000000\n");
+		nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
 		stat &= ~0x40000000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
-		nv_wr32(dev, 0x002100, stat);
-		nv_wr32(dev, 0x002140, 0);
+		nv_fatal(priv, "unhandled status 0x%08x\n", stat);
+		nv_wr32(priv, 0x002100, stat);
+		nv_wr32(priv, 0x002140, 0);
 	}
 }
 
-static void
-nve0_fifo_destroy(struct drm_device *dev, int engine)
+static int
+nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+	struct nve0_fifo_priv *priv;
+	int ret;
+
+	ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 4096 * 0x200, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+				&priv->user.bar);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nve0_fifo_intr;
+	nv_engine(priv)->cclass = &nve0_fifo_cclass;
+	nv_engine(priv)->sclass = nve0_fifo_sclass;
+	return 0;
+}
+
+static void
+nve0_fifo_dtor(struct nouveau_object *object)
+{
+	struct nve0_fifo_priv *priv = (void *)object;
 	int i;
 
 	nouveau_gpuobj_unmap(&priv->user.bar);
 	nouveau_gpuobj_ref(NULL, &priv->user.mem);
 
-	for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
-		nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
+	for (i = 0; i < ARRAY_SIZE(priv->engine); i++) {
 		nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
+		nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
 	}
 
-	dev_priv->eng[engine] = NULL;
-	kfree(priv);
+	nouveau_fifo_destroy(&priv->base);
 }
 
-int
-nve0_fifo_create(struct drm_device *dev)
+static int
+nve0_fifo_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nve0_fifo_priv *priv;
-	int ret;
+	struct nve0_fifo_priv *priv = (void *)object;
+	int ret, i;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.base.destroy = nve0_fifo_destroy;
-	priv->base.base.init = nve0_fifo_init;
-	priv->base.base.fini = nve0_fifo_fini;
-	priv->base.base.context_new = nve0_fifo_context_new;
-	priv->base.base.context_del = nve0_fifo_context_del;
-	priv->base.channels = 4096;
-	dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-
-	ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+	ret = nouveau_fifo_init(&priv->base);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW,
-				    &priv->user.bar);
-	if (ret)
-		goto error;
+	/* enable all available PSUBFIFOs */
+	nv_wr32(priv, 0x000204, 0xffffffff);
+	priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
+	nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
 
-	nouveau_irq_register(dev, 8, nve0_fifo_isr);
-error:
-	if (ret)
-		priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
-	return ret;
+	/* PSUBFIFO[n] */
+	for (i = 0; i < priv->spoon_nr; i++) {
+		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+	}
+
+	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+	nv_wr32(priv, 0x002a00, 0xffffffff);
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0xbfffffff);
+	return 0;
 }
+
+struct nouveau_oclass
+nve0_fifo_oclass = {
+	.handle = NV_ENGINE(FIFO, 0xe0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nve0_fifo_ctor,
+		.dtor = nve0_fifo_dtor,
+		.init = nve0_fifo_init,
+		.fini = _nouveau_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
index b0795ec..e194701 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
@@ -2,7 +2,7 @@
 #define __NOUVEAU_GRCTX_H__
 
 struct nouveau_grctx {
-	struct drm_device *dev;
+	struct nouveau_device *device;
 
 	enum {
 		NOUVEAU_GRCTX_PROG,
@@ -10,18 +10,18 @@
 	} mode;
 	void *data;
 
-	uint32_t ctxprog_max;
-	uint32_t ctxprog_len;
-	uint32_t ctxprog_reg;
-	int      ctxprog_label[32];
-	uint32_t ctxvals_pos;
-	uint32_t ctxvals_base;
+	u32 ctxprog_max;
+	u32 ctxprog_len;
+	u32 ctxprog_reg;
+	int ctxprog_label[32];
+	u32 ctxvals_pos;
+	u32 ctxvals_base;
 };
 
 static inline void
-cp_out(struct nouveau_grctx *ctx, uint32_t inst)
+cp_out(struct nouveau_grctx *ctx, u32 inst)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
 		return;
@@ -31,13 +31,13 @@
 }
 
 static inline void
-cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
+cp_lsr(struct nouveau_grctx *ctx, u32 val)
 {
 	cp_out(ctx, CP_LOAD_SR | val);
 }
 
 static inline void
-cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
+cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
 {
 	ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
 
@@ -55,7 +55,7 @@
 static inline void
 cp_name(struct nouveau_grctx *ctx, int name)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 	int i;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
@@ -115,7 +115,7 @@
 }
 
 static inline void
-gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
+gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
 {
 	if (ctx->mode != NOUVEAU_GRCTX_VALS)
 		return;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
index b17506d..e45035e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
@@ -22,6 +22,8 @@
  * Authors: Ben Skeggs
  */
 
+#include <core/gpuobj.h>
+
 /* NVIDIA context programs handle a number of other conditions which are
  * not implemented in our versions.  It's not clear why NVIDIA context
  * programs have this code, nor whether it's strictly necessary for
@@ -109,8 +111,7 @@
 #define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
 #define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nv40.h"
 #include "ctx.h"
 
 /* TODO:
@@ -118,11 +119,10 @@
  */
 
 static int
-nv40_graph_vs_count(struct drm_device *dev)
+nv40_graph_vs_count(struct nouveau_device *device)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -160,7 +160,7 @@
 static void
 nv40_graph_construct_general(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x4000a4, 1);
@@ -187,7 +187,7 @@
 	cp_ctx(ctx, 0x400724, 1);
 	gr_def(ctx, 0x400724, 0x02008821);
 	cp_ctx(ctx, 0x400770, 3);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x400814, 4);
 		cp_ctx(ctx, 0x400828, 5);
 		cp_ctx(ctx, 0x400840, 5);
@@ -208,7 +208,7 @@
 		gr_def(ctx, 0x4009dc, 0x80000000);
 	} else {
 		cp_ctx(ctx, 0x400840, 20);
-		if (nv44_graph_class(ctx->dev)) {
+		if (nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
 		}
@@ -217,21 +217,21 @@
 		gr_def(ctx, 0x400888, 0x00000040);
 		cp_ctx(ctx, 0x400894, 11);
 		gr_def(ctx, 0x400894, 0x00000040);
-		if (!nv44_graph_class(ctx->dev)) {
+		if (!nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
 		}
 		cp_ctx(ctx, 0x4008e0, 2);
 		cp_ctx(ctx, 0x4008f8, 2);
-		if (dev_priv->chipset == 0x4c ||
-		    (dev_priv->chipset & 0xf0) == 0x60)
+		if (device->chipset == 0x4c ||
+		    (device->chipset & 0xf0) == 0x60)
 			cp_ctx(ctx, 0x4009f8, 1);
 	}
 	cp_ctx(ctx, 0x400a00, 73);
 	gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
 	cp_ctx(ctx, 0x401000, 4);
 	cp_ctx(ctx, 0x405004, 1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -240,7 +240,7 @@
 		break;
 	default:
 		cp_ctx(ctx, 0x403440, 1);
-		switch (dev_priv->chipset) {
+		switch (device->chipset) {
 		case 0x40:
 			gr_def(ctx, 0x403440, 0x00000010);
 			break;
@@ -266,19 +266,19 @@
 static void
 nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401880, 51);
 		gr_def(ctx, 0x401940, 0x00000100);
 	} else
-	if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
-	    dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+	if (device->chipset == 0x46 || device->chipset == 0x47 ||
+	    device->chipset == 0x49 || device->chipset == 0x4b) {
 		cp_ctx(ctx, 0x401880, 32);
 		for (i = 0; i < 16; i++)
 			gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
-		if (dev_priv->chipset == 0x46)
+		if (device->chipset == 0x46)
 			cp_ctx(ctx, 0x401900, 16);
 		cp_ctx(ctx, 0x401940, 3);
 	}
@@ -289,7 +289,7 @@
 	gr_def(ctx, 0x401978, 0xffff0000);
 	gr_def(ctx, 0x40197c, 0x00000001);
 	gr_def(ctx, 0x401990, 0x46400000);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x4019a0, 2);
 		cp_ctx(ctx, 0x4019ac, 5);
 	} else {
@@ -297,7 +297,7 @@
 		cp_ctx(ctx, 0x4019b4, 3);
 	}
 	gr_def(ctx, 0x4019bc, 0xffff0000);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -316,7 +316,7 @@
 	for (i = 0; i < 16; i++)
 		gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
 	gr_def(ctx, 0x401a8c, 0x4b7fffff);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401ab8, 3);
 	} else {
 		cp_ctx(ctx, 0x401ab8, 1);
@@ -327,10 +327,10 @@
 	gr_def(ctx, 0x401ad4, 0x70605040);
 	gr_def(ctx, 0x401ad8, 0xb8a89888);
 	gr_def(ctx, 0x401adc, 0xf8e8d8c8);
-	cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
+	cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
 	gr_def(ctx, 0x401b10, 0x40100000);
-	cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
-	gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
+	cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
+	gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
 			      0x00000004 : 0x00000000);
 	cp_ctx(ctx, 0x401b30, 25);
 	gr_def(ctx, 0x401b34, 0x0000ffff);
@@ -341,8 +341,8 @@
 	gr_def(ctx, 0x401b84, 0xffffffff);
 	gr_def(ctx, 0x401b88, 0x00ff7000);
 	gr_def(ctx, 0x401b8c, 0x0000ffff);
-	if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
-	    dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x44 && device->chipset != 0x4a &&
+	    device->chipset != 0x4e)
 		cp_ctx(ctx, 0x401b94, 1);
 	cp_ctx(ctx, 0x401b98, 8);
 	gr_def(ctx, 0x401b9c, 0x00ff0000);
@@ -371,12 +371,12 @@
 static void
 nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x402000, 1);
-	cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
-	switch (dev_priv->chipset) {
+	cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402404, 0x00000001);
 		break;
@@ -393,9 +393,9 @@
 	default:
 		gr_def(ctx, 0x402404, 0x00000021);
 	}
-	if (dev_priv->chipset != 0x40)
+	if (device->chipset != 0x40)
 		gr_def(ctx, 0x402408, 0x030c30c3);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x44:
 	case 0x46:
 	case 0x4a:
@@ -408,10 +408,10 @@
 	default:
 		break;
 	}
-	cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
+	cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
 	gr_def(ctx, 0x402488, 0x3e020200);
 	gr_def(ctx, 0x40248c, 0x00ffffff);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402490, 0x60103f00);
 		break;
@@ -428,16 +428,16 @@
 		gr_def(ctx, 0x402490, 0x0c103f00);
 		break;
 	}
-	gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
+	gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
 			      0x00020000 : 0x00040000);
 	cp_ctx(ctx, 0x402500, 31);
 	gr_def(ctx, 0x402530, 0x00008100);
-	if (dev_priv->chipset == 0x40)
+	if (device->chipset == 0x40)
 		cp_ctx(ctx, 0x40257c, 6);
 	cp_ctx(ctx, 0x402594, 16);
 	cp_ctx(ctx, 0x402800, 17);
 	gr_def(ctx, 0x402800, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -445,7 +445,7 @@
 		gr_def(ctx, 0x402864, 0x00001001);
 		cp_ctx(ctx, 0x402870, 3);
 		gr_def(ctx, 0x402878, 0x00000003);
-		if (dev_priv->chipset != 0x47) { /* belong at end!! */
+		if (device->chipset != 0x47) { /* belong at end!! */
 			cp_ctx(ctx, 0x402900, 1);
 			cp_ctx(ctx, 0x402940, 1);
 			cp_ctx(ctx, 0x402980, 1);
@@ -470,9 +470,9 @@
 	}
 
 	cp_ctx(ctx, 0x402c00, 4);
-	gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
+	gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
 			      0x80800001 : 0x00888001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -485,30 +485,30 @@
 		break;
 	default:
 		cp_ctx(ctx, 0x402c10, 4);
-		if (dev_priv->chipset == 0x40)
+		if (device->chipset == 0x40)
 			cp_ctx(ctx, 0x402c20, 36);
 		else
-		if (dev_priv->chipset <= 0x42)
+		if (device->chipset <= 0x42)
 			cp_ctx(ctx, 0x402c20, 24);
 		else
-		if (dev_priv->chipset <= 0x4a)
+		if (device->chipset <= 0x4a)
 			cp_ctx(ctx, 0x402c20, 16);
 		else
 			cp_ctx(ctx, 0x402c20, 8);
-		cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
+		cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
 		gr_def(ctx, 0x402cd4, 0x00000005);
-		if (dev_priv->chipset != 0x40)
+		if (device->chipset != 0x40)
 			gr_def(ctx, 0x402ce0, 0x0000ffff);
 		break;
 	}
 
-	cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
-	for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
+	cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
+	for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
 		gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
 
-	if (dev_priv->chipset != 0x40) {
+	if (device->chipset != 0x40) {
 		cp_ctx(ctx, 0x403600, 1);
 		gr_def(ctx, 0x403600, 0x00000001);
 	}
@@ -516,7 +516,7 @@
 
 	cp_ctx(ctx, 0x403c18, 1);
 	gr_def(ctx, 0x403c18, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -527,7 +527,7 @@
 		gr_def(ctx, 0x405c24, 0x000e3000);
 		break;
 	}
-	if (dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x4e)
 		cp_ctx(ctx, 0x405800, 11);
 	cp_ctx(ctx, 0x407000, 1);
 }
@@ -535,7 +535,7 @@
 static void
 nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
 {
-	int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
+	int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
 
 	cp_out (ctx, 0x300000);
 	cp_lsr (ctx, len - 4);
@@ -550,32 +550,31 @@
 static void
 nv40_graph_construct_shader(struct nouveau_grctx *ctx)
 {
-	struct drm_device *dev = ctx->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	struct nouveau_gpuobj *obj = ctx->data;
 	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
 	int offset, i;
 
-	vs_nr    = nv40_graph_vs_count(ctx->dev);
+	vs_nr    = nv40_graph_vs_count(ctx->device);
 	vs_nr_b0 = 363;
-	vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
-	if (dev_priv->chipset == 0x40) {
+	vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
+	if (device->chipset == 0x40) {
 		b0_offset = 0x2200/4; /* 33a0 */
 		b1_offset = 0x55a0/4; /* 1500 */
 		vs_len = 0x6aa0/4;
 	} else
-	if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
+	if (device->chipset == 0x41 || device->chipset == 0x42) {
 		b0_offset = 0x2200/4; /* 2200 */
 		b1_offset = 0x4400/4; /* 0b00 */
 		vs_len = 0x4f00/4;
 	} else {
 		b0_offset = 0x1d40/4; /* 2200 */
 		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
-		vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
+		vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
 	}
 
 	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
-	cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
+	cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
 
 	offset = ctx->ctxvals_pos;
 	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
@@ -661,21 +660,21 @@
 }
 
 void
-nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
 {
 	nv40_grctx_generate(&(struct nouveau_grctx) {
-			     .dev = dev,
+			     .device = device,
 			     .mode = NOUVEAU_GRCTX_VALS,
 			     .data = mem,
 			   });
 }
 
 void
-nv40_grctx_init(struct drm_device *dev, u32 *size)
+nv40_grctx_init(struct nouveau_device *device, u32 *size)
 {
 	u32 ctxprog[256], i;
 	struct nouveau_grctx ctx = {
-		.dev = dev,
+		.device = device,
 		.mode = NOUVEAU_GRCTX_PROG,
 		.data = ctxprog,
 		.ctxprog_max = ARRAY_SIZE(ctxprog)
@@ -683,8 +682,8 @@
 
 	nv40_grctx_generate(&ctx);
 
-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+	nv_wr32(device, 0x400324, 0);
 	for (i = 0; i < ctx.ctxprog_len; i++)
-		nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
+		nv_wr32(device, 0x400328, ctxprog[i]);
 	*size = ctx.ctxvals_pos * 4;
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
index e17c17b..552fdbd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
@@ -20,6 +20,8 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <core/gpuobj.h>
+
 #define CP_FLAG_CLEAR                 0
 #define CP_FLAG_SET                   1
 #define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
@@ -105,8 +107,7 @@
 #define CP_SEEK_1      0x00c000ff
 #define CP_SEEK_2      0x00c800ff
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nv50.h"
 #include "ctx.h"
 
 #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
@@ -175,32 +176,6 @@
 static int
 nv50_grctx_generate(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-
-	switch (dev_priv->chipset) {
-	case 0x50:
-	case 0x84:
-	case 0x86:
-	case 0x92:
-	case 0x94:
-	case 0x96:
-	case 0x98:
-	case 0xa0:
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-	case 0xaa:
-	case 0xac:
-	case 0xaf:
-		break;
-	default:
-		NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
-				   "your NV%x card.\n", dev_priv->chipset);
-		NV_ERROR(ctx->dev, "Disabling acceleration. Please contact "
-				   "the devs.\n");
-		return -ENOSYS;
-	}
-
 	cp_set (ctx, STATE, RUNNING);
 	cp_set (ctx, XFER_SWITCH, ENABLE);
 	/* decide whether we're loading/unloading the context */
@@ -278,30 +253,36 @@
 }
 
 void
-nv50_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
 {
 	nv50_grctx_generate(&(struct nouveau_grctx) {
-			     .dev = dev,
+			     .device = device,
 			     .mode = NOUVEAU_GRCTX_VALS,
 			     .data = mem,
 			   });
 }
 
 int
-nv50_grctx_init(struct drm_device *dev, u32 *data, u32 max, u32 *len, u32 *cnt)
+nv50_grctx_init(struct nouveau_device *device, u32 *size)
 {
+	u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
 	struct nouveau_grctx ctx = {
-		.dev = dev,
+		.device = device,
 		.mode = NOUVEAU_GRCTX_PROG,
-		.data = data,
-		.ctxprog_max = max
+		.data = ctxprog,
+		.ctxprog_max = 512,
 	};
-	int ret;
 
-	ret = nv50_grctx_generate(&ctx);
-	*cnt = ctx.ctxvals_pos * 4;
-	*len = ctx.ctxprog_len;
-	return ret;
+	if (!ctxprog)
+		return -ENOMEM;
+	nv50_grctx_generate(&ctx);
+
+	nv_wr32(device, 0x400324, 0);
+	for (i = 0; i < ctx.ctxprog_len; i++)
+		nv_wr32(device, 0x400328, ctxprog[i]);
+	*size = ctx.ctxvals_pos * 4;
+	kfree(ctxprog);
+	return 0;
 }
 
 /*
@@ -315,36 +296,36 @@
 static void
 nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i, j;
 	int offset, base;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 
 	/* 0800: DISPATCH */
 	cp_ctx(ctx, 0x400808, 7);
 	gr_def(ctx, 0x400814, 0x00000030);
 	cp_ctx(ctx, 0x400834, 0x32);
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		gr_def(ctx, 0x400834, 0xff400040);
 		gr_def(ctx, 0x400838, 0xfff00080);
 		gr_def(ctx, 0x40083c, 0xfff70090);
 		gr_def(ctx, 0x400840, 0xffe806a8);
 	}
 	gr_def(ctx, 0x400844, 0x00000002);
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		gr_def(ctx, 0x400894, 0x00001000);
 	gr_def(ctx, 0x4008e8, 0x00000003);
 	gr_def(ctx, 0x4008ec, 0x00001000);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x400908, 0xb);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		cp_ctx(ctx, 0x400908, 0xc);
 	else
 		cp_ctx(ctx, 0x400908, 0xe);
 
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		cp_ctx(ctx, 0x400b00, 0x1);
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		cp_ctx(ctx, 0x400b10, 0x1);
 		gr_def(ctx, 0x400b10, 0x0001629d);
 		cp_ctx(ctx, 0x400b20, 0x1);
@@ -358,10 +339,10 @@
 	gr_def(ctx, 0x400c08, 0x0000fe0c);
 
 	/* 1000 */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x401008, 0x4);
 		gr_def(ctx, 0x401014, 0x00001000);
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		cp_ctx(ctx, 0x401008, 0x5);
 		gr_def(ctx, 0x401018, 0x00001000);
 	} else {
@@ -372,7 +353,7 @@
 	/* 1400 */
 	cp_ctx(ctx, 0x401400, 0x8);
 	cp_ctx(ctx, 0x401424, 0x3);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		gr_def(ctx, 0x40142c, 0x0001fd87);
 	else
 		gr_def(ctx, 0x40142c, 0x00000187);
@@ -382,10 +363,10 @@
 	/* 1800: STREAMOUT */
 	cp_ctx(ctx, 0x401814, 0x1);
 	gr_def(ctx, 0x401814, 0x000000ff);
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		cp_ctx(ctx, 0x40181c, 0xe);
 		gr_def(ctx, 0x401850, 0x00000004);
-	} else if (dev_priv->chipset < 0xa0) {
+	} else if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x40181c, 0xf);
 		gr_def(ctx, 0x401854, 0x00000004);
 	} else {
@@ -395,7 +376,7 @@
 
 	/* 1C00 */
 	cp_ctx(ctx, 0x401c00, 0x1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		gr_def(ctx, 0x401c00, 0x0001005f);
 		break;
@@ -424,7 +405,7 @@
 
 	/* 2400 */
 	cp_ctx(ctx, 0x402400, 0x1);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x402408, 0x1);
 	else
 		cp_ctx(ctx, 0x402408, 0x2);
@@ -432,21 +413,21 @@
 
 	/* 2800: CSCHED */
 	cp_ctx(ctx, 0x402800, 0x1);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		gr_def(ctx, 0x402800, 0x00000006);
 
 	/* 2C00: ZCULL */
 	cp_ctx(ctx, 0x402c08, 0x6);
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		gr_def(ctx, 0x402c14, 0x01000000);
 	gr_def(ctx, 0x402c18, 0x000000ff);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x402ca0, 0x1);
 	else
 		cp_ctx(ctx, 0x402ca0, 0x2);
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		gr_def(ctx, 0x402ca0, 0x00000400);
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		gr_def(ctx, 0x402ca0, 0x00000800);
 	else
 		gr_def(ctx, 0x402ca0, 0x00000400);
@@ -457,14 +438,14 @@
 	gr_def(ctx, 0x403004, 0x00000001);
 
 	/* 3400 */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		cp_ctx(ctx, 0x403404, 0x1);
 		gr_def(ctx, 0x403404, 0x00000001);
 	}
 
 	/* 5000: CCACHE */
 	cp_ctx(ctx, 0x405000, 0x1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		gr_def(ctx, 0x405000, 0x00300080);
 		break;
@@ -493,22 +474,22 @@
 	cp_ctx(ctx, 0x40502c, 0x1);
 
 	/* 6000? */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x4063e0, 0x1);
 
 	/* 6800: M2MF */
-	if (dev_priv->chipset < 0x90) {
+	if (device->chipset < 0x90) {
 		cp_ctx(ctx, 0x406814, 0x2b);
 		gr_def(ctx, 0x406818, 0x00000f80);
 		gr_def(ctx, 0x406860, 0x007f0080);
 		gr_def(ctx, 0x40689c, 0x007f0080);
 	} else {
 		cp_ctx(ctx, 0x406814, 0x4);
-		if (dev_priv->chipset == 0x98)
+		if (device->chipset == 0x98)
 			gr_def(ctx, 0x406818, 0x00000f80);
 		else
 			gr_def(ctx, 0x406818, 0x00001f80);
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			gr_def(ctx, 0x40681c, 0x00000030);
 		cp_ctx(ctx, 0x406830, 0x3);
 	}
@@ -517,43 +498,43 @@
 	for (i = 0; i < 8; i++) {
 		if (units & (1<<(i+16))) {
 			cp_ctx(ctx, 0x407000 + (i<<8), 3);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
-			else if (dev_priv->chipset != 0xa5)
+			else if (device->chipset != 0xa5)
 				gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
 			else
 				gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
 			gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
 
-			if (dev_priv->chipset == 0x50) {
+			if (device->chipset == 0x50) {
 				cp_ctx(ctx, 0x407010 + (i<<8), 1);
-			} else if (dev_priv->chipset < 0xa0) {
+			} else if (device->chipset < 0xa0) {
 				cp_ctx(ctx, 0x407010 + (i<<8), 2);
 				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
 				gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
 			} else {
 				cp_ctx(ctx, 0x407010 + (i<<8), 3);
 				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
-				if (dev_priv->chipset != 0xa5)
+				if (device->chipset != 0xa5)
 					gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
 				else
 					gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
 			}
 
 			cp_ctx(ctx, 0x407080 + (i<<8), 4);
-			if (dev_priv->chipset != 0xa5)
+			if (device->chipset != 0xa5)
 				gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
 			else
 				gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
 			else
 				gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
 			gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, 0x407094 + (i<<8), 1);
-			else if (!IS_NVA3F(dev_priv->chipset))
+			else if (!IS_NVA3F(device->chipset))
 				cp_ctx(ctx, 0x407094 + (i<<8), 3);
 			else {
 				cp_ctx(ctx, 0x407094 + (i<<8), 4);
@@ -563,30 +544,30 @@
 	}
 
 	cp_ctx(ctx, 0x407c00, 0x3);
-	if (dev_priv->chipset < 0x90)
+	if (device->chipset < 0x90)
 		gr_def(ctx, 0x407c00, 0x00010040);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		gr_def(ctx, 0x407c00, 0x00390040);
 	else
 		gr_def(ctx, 0x407c00, 0x003d0040);
 	gr_def(ctx, 0x407c08, 0x00000022);
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		cp_ctx(ctx, 0x407c10, 0x3);
 		cp_ctx(ctx, 0x407c20, 0x1);
 		cp_ctx(ctx, 0x407c2c, 0x1);
 	}
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x407d00, 0x9);
 	} else {
 		cp_ctx(ctx, 0x407d00, 0x15);
 	}
-	if (dev_priv->chipset == 0x98)
+	if (device->chipset == 0x98)
 		gr_def(ctx, 0x407d08, 0x00380040);
 	else {
-		if (dev_priv->chipset < 0x90)
+		if (device->chipset < 0x90)
 			gr_def(ctx, 0x407d08, 0x00010040);
-		else if (dev_priv->chipset < 0xa0)
+		else if (device->chipset < 0xa0)
 			gr_def(ctx, 0x407d08, 0x00390040);
 		else
 			gr_def(ctx, 0x407d08, 0x003d0040);
@@ -596,11 +577,11 @@
 	/* 8000+: per-TP state */
 	for (i = 0; i < 10; i++) {
 		if (units & (1<<i)) {
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				base = 0x408000 + (i<<12);
 			else
 				base = 0x408000 + (i<<11);
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xc00;
 			else
 				offset = base + 0x80;
@@ -609,9 +590,9 @@
 			cp_ctx(ctx, offset + 0x08, 1);
 
 			/* per-MP state */
-			for (j = 0; j < (dev_priv->chipset < 0xa0 ? 2 : 4); j++) {
+			for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
 				if (!(units & (1 << (j+24)))) continue;
-				if (dev_priv->chipset < 0xa0)
+				if (device->chipset < 0xa0)
 					offset = base + 0x200 + (j<<7);
 				else
 					offset = base + 0x100 + (j<<7);
@@ -620,7 +601,7 @@
 				gr_def(ctx, offset + 0x04, 0x00160000);
 				gr_def(ctx, offset + 0x08, 0x01800000);
 				gr_def(ctx, offset + 0x18, 0x0003ffff);
-				switch (dev_priv->chipset) {
+				switch (device->chipset) {
 				case 0x50:
 					gr_def(ctx, offset + 0x1c, 0x00080000);
 					break;
@@ -651,53 +632,53 @@
 					break;
 				}
 				gr_def(ctx, offset + 0x40, 0x00010401);
-				if (dev_priv->chipset == 0x50)
+				if (device->chipset == 0x50)
 					gr_def(ctx, offset + 0x48, 0x00000040);
 				else
 					gr_def(ctx, offset + 0x48, 0x00000078);
 				gr_def(ctx, offset + 0x50, 0x000000bf);
 				gr_def(ctx, offset + 0x58, 0x00001210);
-				if (dev_priv->chipset == 0x50)
+				if (device->chipset == 0x50)
 					gr_def(ctx, offset + 0x5c, 0x00000080);
 				else
 					gr_def(ctx, offset + 0x5c, 0x08000080);
-				if (dev_priv->chipset >= 0xa0)
+				if (device->chipset >= 0xa0)
 					gr_def(ctx, offset + 0x68, 0x0000003e);
 			}
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x300, 0x4);
 			else
 				cp_ctx(ctx, base + 0x300, 0x5);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, base + 0x304, 0x00007070);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, base + 0x304, 0x00027070);
-			else if (!IS_NVA3F(dev_priv->chipset))
+			else if (!IS_NVA3F(device->chipset))
 				gr_def(ctx, base + 0x304, 0x01127070);
 			else
 				gr_def(ctx, base + 0x304, 0x05127070);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x318, 1);
 			else
 				cp_ctx(ctx, base + 0x320, 1);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, base + 0x318, 0x0003ffff);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, base + 0x318, 0x03ffffff);
 			else
 				gr_def(ctx, base + 0x320, 0x07ffffff);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x324, 5);
 			else
 				cp_ctx(ctx, base + 0x328, 4);
 
-			if (dev_priv->chipset < 0xa0) {
+			if (device->chipset < 0xa0) {
 				cp_ctx(ctx, base + 0x340, 9);
 				offset = base + 0x340;
-			} else if (!IS_NVA3F(dev_priv->chipset)) {
+			} else if (!IS_NVA3F(device->chipset)) {
 				cp_ctx(ctx, base + 0x33c, 0xb);
 				offset = base + 0x344;
 			} else {
@@ -706,12 +687,12 @@
 			}
 			gr_def(ctx, offset + 0x0, 0x00120407);
 			gr_def(ctx, offset + 0x4, 0x05091507);
-			if (dev_priv->chipset == 0x84)
+			if (device->chipset == 0x84)
 				gr_def(ctx, offset + 0x8, 0x05100202);
 			else
 				gr_def(ctx, offset + 0x8, 0x05010202);
 			gr_def(ctx, offset + 0xc, 0x00030201);
-			if (dev_priv->chipset == 0xa3)
+			if (device->chipset == 0xa3)
 				cp_ctx(ctx, base + 0x36c, 1);
 
 			cp_ctx(ctx, base + 0x400, 2);
@@ -720,7 +701,7 @@
 			gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
 			gr_def(ctx, base + 0x410, 0x00141210);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0x800;
 			else
 				offset = base + 0x500;
@@ -728,55 +709,55 @@
 			gr_def(ctx, offset + 0x0, 0x000001f0);
 			gr_def(ctx, offset + 0x4, 0x00000001);
 			gr_def(ctx, offset + 0x8, 0x00000003);
-			if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset))
+			if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
 				gr_def(ctx, offset + 0xc, 0x00008000);
 			gr_def(ctx, offset + 0x14, 0x00039e00);
 			cp_ctx(ctx, offset + 0x1c, 2);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, offset + 0x1c, 0x00000040);
 			else
 				gr_def(ctx, offset + 0x1c, 0x00000100);
 			gr_def(ctx, offset + 0x20, 0x00003800);
 
-			if (dev_priv->chipset >= 0xa0) {
+			if (device->chipset >= 0xa0) {
 				cp_ctx(ctx, base + 0x54c, 2);
-				if (!IS_NVA3F(dev_priv->chipset))
+				if (!IS_NVA3F(device->chipset))
 					gr_def(ctx, base + 0x54c, 0x003fe006);
 				else
 					gr_def(ctx, base + 0x54c, 0x003fe007);
 				gr_def(ctx, base + 0x550, 0x003fe000);
 			}
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xa00;
 			else
 				offset = base + 0x680;
 			cp_ctx(ctx, offset, 1);
 			gr_def(ctx, offset, 0x00404040);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xe00;
 			else
 				offset = base + 0x700;
 			cp_ctx(ctx, offset, 2);
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				gr_def(ctx, offset, 0x0077f005);
-			else if (dev_priv->chipset == 0xa5)
+			else if (device->chipset == 0xa5)
 				gr_def(ctx, offset, 0x6cf7f007);
-			else if (dev_priv->chipset == 0xa8)
+			else if (device->chipset == 0xa8)
 				gr_def(ctx, offset, 0x6cfff007);
-			else if (dev_priv->chipset == 0xac)
+			else if (device->chipset == 0xac)
 				gr_def(ctx, offset, 0x0cfff007);
 			else
 				gr_def(ctx, offset, 0x0cf7f007);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, offset + 0x4, 0x00007fff);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, offset + 0x4, 0x003f7fff);
 			else
 				gr_def(ctx, offset + 0x4, 0x02bf7fff);
 			cp_ctx(ctx, offset + 0x2c, 1);
-			if (dev_priv->chipset == 0x50) {
+			if (device->chipset == 0x50) {
 				cp_ctx(ctx, offset + 0x50, 9);
 				gr_def(ctx, offset + 0x54, 0x000003ff);
 				gr_def(ctx, offset + 0x58, 0x00000003);
@@ -785,7 +766,7 @@
 				gr_def(ctx, offset + 0x64, 0x0000001f);
 				gr_def(ctx, offset + 0x68, 0x0000000f);
 				gr_def(ctx, offset + 0x6c, 0x0000000f);
-			} else if (dev_priv->chipset < 0xa0) {
+			} else if (device->chipset < 0xa0) {
 				cp_ctx(ctx, offset + 0x50, 1);
 				cp_ctx(ctx, offset + 0x70, 1);
 			} else {
@@ -797,7 +778,7 @@
 }
 
 static void
-dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+dd_emit(struct nouveau_grctx *ctx, int num, u32 val) {
 	int i;
 	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
 		for (i = 0; i < num; i++)
@@ -808,7 +789,7 @@
 static void
 nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int base, num;
 	base = ctx->ctxvals_pos;
 
@@ -822,7 +803,7 @@
 	dd_emit(ctx, 1, 1);	/* 00000001 SRC_LINEAR #1 */
 	dd_emit(ctx, 1, 0);	/* 000000ff SRC_ADDRESS_HIGH */
 	dd_emit(ctx, 1, 0);	/* 00000001 SRC_SRGB */
-	if (dev_priv->chipset >= 0x94)
+	if (device->chipset >= 0x94)
 		dd_emit(ctx, 1, 0);	/* 00000003 eng2d UNK0258 */
 	dd_emit(ctx, 1, 1);	/* 00000fff SRC_DEPTH */
 	dd_emit(ctx, 1, 0x100);	/* 0000ffff SRC_HEIGHT */
@@ -851,7 +832,7 @@
 	dd_emit(ctx, 1, 1);		/* 0000007f BLOCKDIM_Z */
 	dd_emit(ctx, 1, 4);		/* 000000ff CP_REG_ALLOC_TEMP */
 	dd_emit(ctx, 1, 1);		/* 00000001 BLOCKDIM_DIRTY */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0);	/* 00000003 UNK03E8 */
 	dd_emit(ctx, 1, 1);		/* 0000007f BLOCK_ALLOC_HALFWARPS */
 	dd_emit(ctx, 1, 1);		/* 00000007 LOCAL_WARPS_NO_CLAMP */
@@ -863,7 +844,7 @@
 	dd_emit(ctx, 1, 1);		/* 000007ff BLOCK_ALLOC_THREADS */
 
 	/* compat 2d state */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 4, 0);		/* 0000ffff clip X, Y, W, H */
 
 		dd_emit(ctx, 1, 1);		/* ffffffff chroma COLOR_FORMAT */
@@ -923,7 +904,7 @@
 	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_IN */
 
 	/* more compat 2d state */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 1, 1);		/* ffffffff line COLOR_FORMAT */
 		dd_emit(ctx, 1, 0);		/* ffffffff line OPERATION */
 
@@ -957,18 +938,18 @@
 	dd_emit(ctx, 1, 0);		/* 000000ff UNK12B0_2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f FP_TEXTURES_LOG2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f FP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		dd_emit(ctx, 1, 0);	/* ffffffff */
 		dd_emit(ctx, 1, 0);	/* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
 	} else {
 		dd_emit(ctx, 1, 0);	/* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
 	}
 	dd_emit(ctx, 1, 0xc);		/* 000000ff SEMANTIC_COLOR.BFC0_ID */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_COLOR.CLMP_EN */
 	dd_emit(ctx, 1, 8);		/* 000000ff SEMANTIC_COLOR.COLR_NR */
 	dd_emit(ctx, 1, 0x14);		/* 000000ff SEMANTIC_COLOR.FFC0_ID */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 1, 0);	/* 000000ff SEMANTIC_LAYER */
 		dd_emit(ctx, 1, 0);	/* 00000001 */
 	} else {
@@ -994,7 +975,7 @@
 	dd_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
 	dd_emit(ctx, 1, 0xcf);		/* 000000ff RT_FORMAT */
 	dd_emit(ctx, 7, 0);		/* 000000ff RT_FORMAT */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 3, 0);	/* 1, 1, 1 */
 	else
 		dd_emit(ctx, 2, 0);	/* 1, 1 */
@@ -1002,15 +983,15 @@
 	dd_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
 	dd_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
 	dd_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		dd_emit(ctx, 1, 3);	/* 00000003 */
 		dd_emit(ctx, 1, 0);	/* 00000001 UNK1418. Alone. */
 	}
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 3);	/* 00000003 UNK15AC */
 	dd_emit(ctx, 1, 1);		/* ffffffff RASTERIZE_ENABLE */
 	dd_emit(ctx, 1, 0);		/* 00000001 FP_CONTROL.EXPORTS_Z */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 0);	/* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
 	dd_emit(ctx, 1, 0x12);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT */
 	dd_emit(ctx, 1, 0x10);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
@@ -1022,16 +1003,16 @@
 	dd_emit(ctx, 1, 4);		/* 000000ff FP_RESULT_COUNT */
 	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
 	dd_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* ffffffff */
 	dd_emit(ctx, 1, 0);		/* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
 	dd_emit(ctx, 1, 0);		/* ffffffff STRMOUT_ENABLE */
 	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
 	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
 	dd_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE*/
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 8, 0);	/* 00000001 */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.COMP */
 		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.SIZE */
 		dd_emit(ctx, 1, 2);	/* 00000007 VTX_ATTR_DEFINE.TYPE */
@@ -1042,20 +1023,20 @@
 	dd_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	dd_emit(ctx, 1, 0);		/* 0000000f VP_TEXTURES_LOG2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f VP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0);	/* 00000001 */
 	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_BACK */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
 	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* 00000003 */
 	dd_emit(ctx, 1, 0);		/* 00000001 CULL_FACE_ENABLE */
 	dd_emit(ctx, 1, 1);		/* 00000003 CULL_FACE */
 	dd_emit(ctx, 1, 0);		/* 00000001 FRONT_FACE */
 	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_FRONT */
 	dd_emit(ctx, 1, 0x1000);	/* 00007fff UNK141C */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		dd_emit(ctx, 1, 0xe00);		/* 7fff */
 		dd_emit(ctx, 1, 0x1000);	/* 7fff */
 		dd_emit(ctx, 1, 0x1e00);	/* 7fff */
@@ -1070,10 +1051,10 @@
 	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
 	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
 	dd_emit(ctx, 1, 0x200);		/* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0x200);
 	dd_emit(ctx, 1, 0);		/* 00000001 */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		dd_emit(ctx, 1, 1);	/* 00000001 */
 		dd_emit(ctx, 1, 0x70);	/* 000000ff */
 		dd_emit(ctx, 1, 0x80);	/* 000000ff */
@@ -1120,7 +1101,7 @@
 
 	num = ctx->ctxvals_pos - base;
 	ctx->ctxvals_pos = base;
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		cp_ctx(ctx, 0x404800, num);
 	else
 		cp_ctx(ctx, 0x405400, num);
@@ -1169,7 +1150,7 @@
  */
 
 static void
-xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+xf_emit(struct nouveau_grctx *ctx, int num, u32 val) {
 	int i;
 	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
 		for (i = 0; i < num; i++)
@@ -1201,16 +1182,16 @@
 static void
 nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	int offset;
 	int size = 0;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 
 	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
 	ctx->ctxvals_base = offset;
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		/* Strand 0 */
 		ctx->ctxvals_pos = offset;
 		nv50_graph_construct_gene_dispatch(ctx);
@@ -1280,7 +1261,7 @@
 
 		/* Strand 2 */
 		ctx->ctxvals_pos = offset + 2;
-		if (dev_priv->chipset == 0xa0)
+		if (device->chipset == 0xa0)
 			nv50_graph_construct_gene_unk14xx(ctx);
 		nv50_graph_construct_gene_unk24xx(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
@@ -1327,7 +1308,7 @@
 
 		/* Strand 7 */
 		ctx->ctxvals_pos = offset + 7;
-		if (dev_priv->chipset == 0xa0) {
+		if (device->chipset == 0xa0) {
 			if (units & (1 << 4))
 				nv50_graph_construct_xfer_tp(ctx);
 			if (units & (1 << 5))
@@ -1365,24 +1346,24 @@
 nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
 {
 	/* start of strand 0 */
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* SEEK */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 5, 0);
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 6, 0);
 	else
 		xf_emit(ctx, 4, 0);
 	/* SEEK */
 	/* the PGRAPH's internal FIFO */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 8*3, 0);
 	else
 		xf_emit(ctx, 0x100*3, 0);
 	/* and another bonus slot?!? */
 	xf_emit(ctx, 3, 0);
 	/* and YET ANOTHER bonus slot? */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 3, 0);
 	/* SEEK */
 	/* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
@@ -1394,7 +1375,7 @@
 	/* SEEK */
 	xf_emit(ctx, 9, 0);
 	/* SEEK */
-	if (dev_priv->chipset < 0x90)
+	if (device->chipset < 0x90)
 		xf_emit(ctx, 4, 0);
 	/* SEEK */
 	xf_emit(ctx, 2, 0);
@@ -1407,9 +1388,9 @@
 	xf_emit(ctx, 6*2, 0);
 	xf_emit(ctx, 2, 0);
 	/* SEEK */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 0x1c, 0);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x1e, 0);
 	else
 		xf_emit(ctx, 0x22, 0);
@@ -1421,9 +1402,9 @@
 nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
 {
 	/* Strand 0, right after dispatch */
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int smallm2mf = 0;
-	if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98)
+	if (device->chipset < 0x92 || device->chipset == 0x98)
 		smallm2mf = 1;
 	/* SEEK */
 	xf_emit (ctx, 1, 0);		/* DMA_NOTIFY instance >> 4 */
@@ -1472,10 +1453,10 @@
 static void
 nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* RO */
 	xf_emit(ctx, 0x800, 0);		/* ffffffff */
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 	case 0x92:
 	case 0xa0:
@@ -1540,7 +1521,7 @@
 static void
 nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	/* end of area 2 on pre-NVA0, area 1 on NVAx */
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
@@ -1550,14 +1531,14 @@
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 000007ff */
 	xf_emit(ctx, 1, 0);		/* 111/113 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	for (i = 0; i < 8; i++) {
-		switch (dev_priv->chipset) {
+		switch (device->chipset) {
 		case 0x50:
 		case 0x86:
 		case 0x98:
@@ -1600,7 +1581,7 @@
 static void
 nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* end of area 2 on pre-NVA0, area 1 on NVAx */
 	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
 	xf_emit(ctx, 1, 0);		/* 00000003 VIEWPORT_CLIP_MODE */
@@ -1614,9 +1595,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0x1fe21);	/* 0001ffff tesla UNK0FAC */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x0fac6881);
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 1);
 		xf_emit(ctx, 3, 0);
 	}
@@ -1625,9 +1606,9 @@
 static void
 nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 5, 0);		/* ffffffff */
 		xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 		xf_emit(ctx, 1, 0);		/* 00000001 */
@@ -1643,14 +1624,14 @@
 	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
 	xf_emit(ctx, 1, 0);			/* 000000ff VP_CLIP_DISTANCE_ENABLE */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);		/* 3ff */
 	xf_emit(ctx, 1, 0);			/* 000000ff tesla UNK1940 */
 	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
 	xf_emit(ctx, 1, 0x804);			/* 00000fff SEMANTIC_CLIP */
 	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
 	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0x7f);		/* 000000ff tesla UNK0FFC */
 	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 1);			/* 00000001 SHADE_MODEL */
@@ -1669,7 +1650,7 @@
 	xf_emit(ctx, 4, 0);			/* ffffffff NOPERSPECTIVE_BITMAP */
 	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
 	xf_emit(ctx, 1, 0);			/* 0000000f */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);		/* 000003ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);		/* 000007ff tesla UNK0D68 */
@@ -1704,11 +1685,11 @@
 	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);		/* 00000001 */
 	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
 	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);		/* ffffffff */
 		xf_emit(ctx, 1, 0);		/* 00000001 */
 		xf_emit(ctx, 1, 0);		/* 000003ff */
@@ -1736,7 +1717,7 @@
 static void
 nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
@@ -1774,7 +1755,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1108 */
 	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
@@ -1789,7 +1770,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
 	xf_emit(ctx, 1, 3);		/* 00000003 FP_CTRL_UNK196C */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1968 */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 0fffffff tesla UNK1104 */
 	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK151C */
 }
@@ -1817,7 +1798,7 @@
 static void
 nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	/* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
 	/* SEEK */
@@ -1829,7 +1810,7 @@
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 4, 0);	/* RO */
 		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
 		xf_emit(ctx, 1, 0);	/* 1ff */
@@ -1860,7 +1841,7 @@
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
@@ -1869,7 +1850,7 @@
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 1);		/* 00000001 */
 	/* SEEK */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 2, 4);	/* 000000ff */
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
@@ -1893,20 +1874,20 @@
 	xf_emit(ctx, 0x10, 0);		/* 00ffffff POINT_COORD_REPLACE_MAP */
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
 	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 000003ff */
 }
 
 static void
 nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int acnt = 0x10, rep, i;
 	/* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		acnt = 0x20;
 	/* SEEK */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK13A4 */
 		xf_emit(ctx, 1, 1);	/* 00000fff tesla UNK1318 */
 	}
@@ -1923,9 +1904,9 @@
 	xf_emit(ctx, 1, 0);		/* 0000ffff turing USER_PARAM_COUNT */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0xb, 0);	/* RO */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 0x9, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x8, 0);	/* RO */
@@ -1944,11 +1925,11 @@
 	xf_emit(ctx, 1, 4);		/* 000001ff UNK1A28 */
 	xf_emit(ctx, 1, 8);		/* 000001ff UNK0DF0 */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);	/* 3ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 7ff tesla UNK0D68 */
-	if (dev_priv->chipset == 0xa8)
+	if (device->chipset == 0xa8)
 		xf_emit(ctx, 1, 0x1e00);	/* 7fff */
 	/* SEEK */
 	xf_emit(ctx, 0xc, 0);		/* RO or close */
@@ -1956,13 +1937,13 @@
 	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0)
+	if (device->chipset > 0x50 && device->chipset < 0xa0)
 		xf_emit(ctx, 2, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 1, 0);	/* ffffffff */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0FD8 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 0x10, 0);	/* 0? */
 		xf_emit(ctx, 2, 0);	/* weird... */
 		xf_emit(ctx, 2, 0);	/* RO */
@@ -1975,7 +1956,7 @@
 	xf_emit(ctx, 1, 0);		/* ffffffff VB_ELEMENT_BASE */
 	xf_emit(ctx, 1, 0);		/* ffffffff UNK1438 */
 	xf_emit(ctx, acnt, 0);		/* 1 tesla UNK1000 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1118? */
 	/* SEEK */
 	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
@@ -2013,23 +1994,23 @@
 	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_LIMIT_HIGH */
 	xf_emit(ctx, 3, 0);		/* f/1f */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, acnt, 0);		/* f */
 		xf_emit(ctx, 3, 0);		/* f/1f */
 	}
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 2, 0);	/* RO */
 	else
 		xf_emit(ctx, 5, 0);	/* RO */
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* ffff DMA_VTXBUF */
 	/* SEEK */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		xf_emit(ctx, 0x41, 0);	/* RO */
 		/* SEEK */
 		xf_emit(ctx, 0x11, 0);	/* RO */
-	} else if (!IS_NVA3F(dev_priv->chipset))
+	} else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x50, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x58, 0);	/* RO */
@@ -2041,7 +2022,7 @@
 	xf_emit(ctx, acnt*4, 0);	/* ffffffff VTX_ATTR */
 	xf_emit(ctx, 4, 0);		/* f/1f, 0, 0, 0 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x1d, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x16, 0);	/* RO */
@@ -2049,21 +2030,21 @@
 	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
 	/* SEEK */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 8, 0);	/* RO */
-	else if (IS_NVA3F(dev_priv->chipset))
+	else if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0xc, 0);	/* RO */
 	else
 		xf_emit(ctx, 7, 0);	/* RO */
 	/* SEEK */
 	xf_emit(ctx, 0xa, 0);		/* RO */
-	if (dev_priv->chipset == 0xa0)
+	if (device->chipset == 0xa0)
 		rep = 0xc;
 	else
 		rep = 4;
 	for (i = 0; i < rep; i++) {
 		/* SEEK */
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			xf_emit(ctx, 0x20, 0);	/* ffffffff */
 		xf_emit(ctx, 0x200, 0);	/* ffffffff */
 		xf_emit(ctx, 4, 0);	/* 7f/ff, 0, 0, 0 */
@@ -2077,7 +2058,7 @@
 	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 7, 0);	/* weird... */
 	else
 		xf_emit(ctx, 5, 0);	/* weird... */
@@ -2086,13 +2067,13 @@
 static void
 nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 2, 0);		/* 0001ffff CLIP_X, CLIP_Y */
 	xf_emit(ctx, 2, 0);		/* 0000ffff CLIP_W, CLIP_H */
 	xf_emit(ctx, 1, 0);		/* 00000001 CLIP_ENABLE */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		/* this is useless on everything but the original NV50,
 		 * guess they forgot to nuke it. Or just didn't bother. */
 		xf_emit(ctx, 2, 0);	/* 0000ffff IFC_CLIP_X, Y */
@@ -2148,7 +2129,7 @@
 static void
 nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
@@ -2173,7 +2154,7 @@
 	xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
 	/* SEEK */
 	xf_emit(ctx, 0x40, 0);		/* ffffffff USER_PARAM */
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 	case 0x92:
 		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
@@ -2247,7 +2228,7 @@
 static void
 nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
 	xf_emit(ctx, 1, 0x3f800000);	/* ffffffff LINE_WIDTH */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
@@ -2277,9 +2258,9 @@
 	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 3);	/* 00000003 UNK16B4 */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 1);	/* 00000001 UNK16B4 */
 	xf_emit(ctx, 1, 0);		/* 00000003 MULTISAMPLE_CTRL */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0F90 */
@@ -2293,11 +2274,11 @@
 	xf_emit(ctx, 1, 0);		/* ffffffff POINT_SIZE */
 	xf_emit(ctx, 1, 0);		/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* 00000007 tesla UNK0FB4 */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);	/* 3ff */
 		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK1110 */
 	}
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1928 */
 	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
 	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
@@ -2316,11 +2297,11 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
 	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x1c, 0);	/* RO */
-	else if (IS_NVA3F(dev_priv->chipset))
+	else if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x9, 0);
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
@@ -2328,13 +2309,13 @@
 	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
 	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
 		xf_emit(ctx, 1, 0);	/* 3ff */
 	}
 	/* XXX: the following block could belong either to unk1cxx, or
 	 * to STRMOUT. Rather hard to tell. */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x25, 0);
 	else
 		xf_emit(ctx, 0x3b, 0);
@@ -2343,18 +2324,18 @@
 static void
 nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
 	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
 	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
 	}
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);	/* 000003ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 000007ff tesla UNK0D68 */
@@ -2365,7 +2346,7 @@
 	xf_emit(ctx, 4, 0);		/* 000000ff STRMOUT_ADDRESS_HIGH */
 	xf_emit(ctx, 4, 0);		/* ffffffff STRMOUT_ADDRESS_LOW */
 	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
 	}
@@ -2385,12 +2366,12 @@
 static void
 nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
 	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0);		/* 000003ff */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 }
@@ -2398,7 +2379,7 @@
 static void
 nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
 	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
@@ -2416,7 +2397,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 eng2d UNK260 */
 	xf_emit(ctx, 1, 0);		/* ff/3ff */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 }
@@ -2424,11 +2405,11 @@
 static void
 nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic2;
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		magic2 = 0x001ffe67;
 	} else {
 		magic2 = 0x00087e67;
@@ -2446,14 +2427,14 @@
 	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
 	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
 	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
 	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset))
+	if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
 		xf_emit(ctx, 1, 0x15);	/* 000000ff */
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
@@ -2462,14 +2443,14 @@
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
+	if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
 		xf_emit(ctx, 3, 0);	/* ff, ffffffff, ffffffff */
 		xf_emit(ctx, 1, 4);	/* 7 */
 		xf_emit(ctx, 1, 0x400);	/* fffffff */
 		xf_emit(ctx, 1, 0x300);	/* ffff */
 		xf_emit(ctx, 1, 0x1001);	/* 1fff */
-		if (dev_priv->chipset != 0xa0) {
-			if (IS_NVA3F(dev_priv->chipset))
+		if (device->chipset != 0xa0) {
+			if (IS_NVA3F(device->chipset))
 				xf_emit(ctx, 1, 0);	/* 0000000f UNK15C8 */
 			else
 				xf_emit(ctx, 1, 0x15);	/* ff */
@@ -2547,7 +2528,7 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 2, 0);
 		xf_emit(ctx, 1, 0x1001);
 		xf_emit(ctx, 0xb, 0);
@@ -2564,7 +2545,7 @@
 	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);	/* 0000000f LOGIC_OP */
 		xf_emit(ctx, 1, 0);	/* 000000ff */
 	}
@@ -2581,7 +2562,7 @@
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK12E4 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
@@ -2600,7 +2581,7 @@
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		xf_emit(ctx, 1, 0);	/* 00000001 */
 		xf_emit(ctx, 1, 0);	/* 000003ff */
-	} else if (dev_priv->chipset >= 0xa0) {
+	} else if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 2, 0);	/* 00000001 */
 		xf_emit(ctx, 1, 0);	/* 00000007 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
@@ -2614,7 +2595,7 @@
 	xf_emit(ctx, 4, 0);		/* ffffffff CLEAR_COLOR */
 	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR A R G B */
 	xf_emit(ctx, 1, 0);		/* 00000fff eng2d UNK2B0 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 2, 0);	/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* 000003ff */
 	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
@@ -2628,9 +2609,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f LOGIC_OP */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4? NVA3+ only? */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
@@ -2659,9 +2640,9 @@
 static void
 nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic3;
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		magic3 = 0x1000;
 		break;
@@ -2681,16 +2662,16 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 0);		/* 111/113[NVA0+] */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x1f, 0);	/* ffffffff */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 0x0f, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 0x10, 0);	/* fffffff VP_RESULT_MAP_1 up */
 	xf_emit(ctx, 2, 0);		/* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
 	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
 	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x03020100);	/* ffffffff */
 	else
 		xf_emit(ctx, 1, 0x00608080);	/* fffffff VP_RESULT_MAP_0 */
@@ -2733,11 +2714,11 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 0);		/* 111/113 */
-	if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
+	if (device->chipset == 0x94 || device->chipset == 0x96)
 		xf_emit(ctx, 0x1020, 0);	/* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		xf_emit(ctx, 0xa20, 0);	/* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x210, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 0x410, 0);	/* ffffffff */
@@ -2751,12 +2732,12 @@
 static void
 nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic1, magic2;
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		magic1 = 0x3ff;
 		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		magic1 = 0x7ff;
 		magic2 = 0x001ffe67;
 	} else {
@@ -2766,7 +2747,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* ffffffff ALPHA_TEST_REF */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000000f UNK16A0 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
@@ -2800,11 +2781,11 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK16B4 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1298 */
-	} else if (dev_priv->chipset >= 0xa0) {
+	} else if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK16B4 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 	} else {
@@ -2818,7 +2799,7 @@
 	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
 	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
 	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
@@ -2846,7 +2827,7 @@
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff DRAW_COLOR_FORMAT */
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff SRC_FORMAT */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0);		/* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
@@ -2870,9 +2851,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0);	/* ff */
 	else
 		xf_emit(ctx, 3, 0);	/* 1, 7, 3ff */
@@ -2907,7 +2888,7 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 8, 0);		/* 0000ffff DMA_COLOR */
 	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_GLOBAL */
@@ -2945,7 +2926,7 @@
 	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
 	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
@@ -2974,7 +2955,7 @@
 	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);	/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
@@ -2988,14 +2969,14 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
 	xf_emit(ctx, 1, 0);		/* 7 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	}
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x0fac6881);	/* fffffff */
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
@@ -3012,12 +2993,12 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		xf_emit(ctx, 1, 0);	/* 0000000f tesla UNK15C8 */
 	}
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 3, 0);		/* 7/f, 1, ffff0ff3 */
 		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
 		xf_emit(ctx, 4, 0);		/* 1, 1, 1, 3ff */
@@ -3027,7 +3008,7 @@
 		xf_emit(ctx, 2, 0);		/* 7, f */
 		xf_emit(ctx, 1, 1);		/* 1 */
 		xf_emit(ctx, 1, 0);		/* 7/f */
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			xf_emit(ctx, 0x9, 0);	/* 1 */
 		else
 			xf_emit(ctx, 0x8, 0);	/* 1 */
@@ -3041,7 +3022,7 @@
 		xf_emit(ctx, 1, 0x11);		/* 7f */
 		xf_emit(ctx, 1, 1);		/* 1 */
 		xf_emit(ctx, 5, 0);		/* 1, 7, 3ff, 3, 7 */
-		if (IS_NVA3F(dev_priv->chipset)) {
+		if (IS_NVA3F(device->chipset)) {
 			xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
 			xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		}
@@ -3051,15 +3032,15 @@
 static void
 nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* 1 LINKED_TSC. yes, 2. */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 3 */
 	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DU_DX_INT */
 	xf_emit(ctx, 1, 0);		/* fffff BLIT_DU_DX_FRACT */
 	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DV_DY_INT */
 	xf_emit(ctx, 1, 0);		/* fffff BLIT_DV_DY_FRACT */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0);	/* 3 BLIT_CONTROL */
 	else
 		xf_emit(ctx, 2, 0);	/* 3ff, 1 */
@@ -3071,13 +3052,13 @@
 	xf_emit(ctx, 1, 0x10100);	/* ffffffff SRC_TIC_5 */
 	xf_emit(ctx, 1, 0x02800000);	/* ffffffff SRC_TIC_6 */
 	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_7 */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK358 */
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
 		xf_emit(ctx, 1, 0);	/* 00000003 turing UNK37C tesla UNK1690 */
 		xf_emit(ctx, 1, 0);	/* 00000003 BLIT_CONTROL */
 		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK32C tesla UNK0F94 */
-	} else if (!IS_NVAAF(dev_priv->chipset)) {
+	} else if (!IS_NVAAF(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 		xf_emit(ctx, 1, 0);	/* 000003ff */
@@ -3097,7 +3078,7 @@
 static void
 nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 2, 0);		/* 7, ffff0ff3 */
@@ -3109,7 +3090,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
 	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK0F98 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
@@ -3136,8 +3117,8 @@
 static void
 nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	if (dev_priv->chipset < 0xa0) {
+	struct nouveau_device *device = ctx->device;
+	if (device->chipset < 0xa0) {
 		nv50_graph_construct_xfer_unk84xx(ctx);
 		nv50_graph_construct_xfer_tprop(ctx);
 		nv50_graph_construct_xfer_tex(ctx);
@@ -3153,9 +3134,9 @@
 static void
 nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i, mpcnt = 2;
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 		case 0x98:
 		case 0xaa:
 			mpcnt = 1;
@@ -3182,34 +3163,34 @@
 		xf_emit(ctx, 1, 0x80);		/* ffffffff tesla UNK1404 */
 		xf_emit(ctx, 1, 0x80007004);	/* ffffffff tesla UNK12B0 */
 		xf_emit(ctx, 1, 0x04000400);	/* ffffffff */
-		if (dev_priv->chipset >= 0xa0)
+		if (device->chipset >= 0xa0)
 			xf_emit(ctx, 1, 0xc0);	/* 00007fff tesla UNK152C */
 		xf_emit(ctx, 1, 0x1000);	/* 0000ffff tesla UNK0D60 */
 		xf_emit(ctx, 1, 0);		/* ff/3ff */
 		xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-		if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) {
+		if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
 			xf_emit(ctx, 1, 0xe00);		/* 7fff */
 			xf_emit(ctx, 1, 0x1e00);	/* 7fff */
 		}
 		xf_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
 		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-		if (dev_priv->chipset == 0x50)
+		if (device->chipset == 0x50)
 			xf_emit(ctx, 2, 0x1000);	/* 7fff tesla UNK141C */
 		xf_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 		xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
-		if (IS_NVAAF(dev_priv->chipset))
+		if (IS_NVAAF(device->chipset))
 			xf_emit(ctx, 0xb, 0);	/* RO */
-		else if (dev_priv->chipset >= 0xa0)
+		else if (device->chipset >= 0xa0)
 			xf_emit(ctx, 0xc, 0);	/* RO */
 		else
 			xf_emit(ctx, 0xa, 0);	/* RO */
 	}
 	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
 	xf_emit(ctx, 1, 0);			/* ff/3ff */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 0x1fe21);	/* 0003ffff tesla UNK0FAC */
 	}
 	xf_emit(ctx, 3, 0);			/* 7fff, 0, 0 */
@@ -3223,7 +3204,7 @@
 	xf_emit(ctx, 1, 0);			/* ffffffff SHARED_SIZE */
 	xf_emit(ctx, 1, 0x1fe21);		/* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
 	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A34 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);			/* ff/3ff */
 	xf_emit(ctx, 1, 0);			/* 1 LINKED_TSC */
@@ -3238,7 +3219,7 @@
 	xf_emit(ctx, 1, 0);			/* 00000007 */
 	xf_emit(ctx, 1, 0xfac6881);		/* 0fffffff RT_CONTROL */
 	xf_emit(ctx, 1, 0);			/* 00000003 MULTISAMPLE_CTRL */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK16B4 */
 	xf_emit(ctx, 1, 0);			/* 00000001 ALPHA_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000007 ALPHA_TEST_FUNC */
@@ -3253,7 +3234,7 @@
 	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_ALPHA */
 	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_ALPHA */
 	xf_emit(ctx, 1, 1);			/* 00000001 UNK133C */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);		/* 00000001 UNK12E4 */
 		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_RGB */
 		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_RGB */
@@ -3268,11 +3249,11 @@
 	xf_emit(ctx, 1, 0);			/* 00000003 tesla UNK0F90 */
 	xf_emit(ctx, 1, 4);			/* 000000ff FP_RESULT_COUNT */
 	/* XXX: demagic this part some day */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 0x3a0, 0);
-	else if (dev_priv->chipset < 0x94)
+	else if (device->chipset < 0x94)
 		xf_emit(ctx, 0x3a2, 0);
-	else if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
+	else if (device->chipset == 0x98 || device->chipset == 0xaa)
 		xf_emit(ctx, 0x39f, 0);
 	else
 		xf_emit(ctx, 0x3a3, 0);
@@ -3285,15 +3266,15 @@
 static void
 nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
-	uint32_t offset;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 offset;
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 	int size = 0;
 
 	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		for (i = 0; i < 8; i++) {
 			ctx->ctxvals_pos = offset + i;
 			/* that little bugger belongs to csched. No idea
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
index b19a406..c12e766 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
@@ -22,13 +22,10 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <core/mm.h>
 #include "nvc0.h"
 
 void
-nv_icmd(struct drm_device *priv, u32 icmd, u32 data)
+nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data)
 {
 	nv_wr32(priv, 0x400204, data);
 	nv_wr32(priv, 0x400200, icmd);
@@ -36,21 +33,22 @@
 }
 
 int
-nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv,
-		struct nvc0_grctx *info)
+nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
+	struct nouveau_bar *bar = nouveau_bar(priv);
+	struct nouveau_object *parent = nv_object(priv);
 	struct nouveau_gpuobj *chan;
-	u32 size = (0x80000 + oprv->size + 4095) & ~4095;
+	u32 size = (0x80000 + priv->size + 4095) & ~4095;
 	int ret, i;
 
 	/* allocate memory to for a "channel", which we'll use to generate
 	 * the default context values
 	 */
-	ret = nouveau_gpuobj_new(priv, NULL, size, 0x1000,
+	ret = nouveau_gpuobj_new(parent, NULL, size, 0x1000,
 				 NVOBJ_FLAG_ZERO_ALLOC, &info->chan);
 	chan = info->chan;
 	if (ret) {
-		NV_ERROR(priv, "failed to allocate channel memory, %d\n", ret);
+		nv_error(priv, "failed to allocate channel memory, %d\n", ret);
 		return ret;
 	}
 
@@ -75,32 +73,31 @@
 	nv_wo32(chan, 0x0210, 0x00080004);
 	nv_wo32(chan, 0x0214, 0x00000000);
 
-	nvimem_flush(priv);
+	bar->flush(bar);
 
 	nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
 	nv_wr32(priv, 0x100cbc, 0x80000001);
 	nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
 
 	/* setup default state for mmio list construction */
-	info->dev  = priv;
-	info->data = oprv->mmio_data;
-	info->mmio = oprv->mmio_list;
+	info->data = priv->mmio_data;
+	info->mmio = priv->mmio_list;
 	info->addr = 0x2000 + (i * 8);
-	info->priv = oprv;
+	info->priv = priv;
 	info->buffer_nr = 0;
 
-	if (oprv->firmware) {
+	if (priv->firmware) {
 		nv_wr32(priv, 0x409840, 0x00000030);
 		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
 		nv_wr32(priv, 0x409504, 0x00000003);
 		if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
-			NV_ERROR(priv, "load_ctx timeout\n");
+			nv_error(priv, "load_ctx timeout\n");
 
 		nv_wo32(chan, 0x8001c, 1);
 		nv_wo32(chan, 0x80020, 0);
 		nv_wo32(chan, 0x80028, 0);
 		nv_wo32(chan, 0x8002c, 0);
-		nvimem_flush(priv);
+		bar->flush(bar);
 		return 0;
 	}
 
@@ -109,7 +106,7 @@
 	nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
 	nv_wr32(priv, 0x409504, 0x00000001);
 	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
-		NV_ERROR(priv, "HUB_SET_CHAN timeout\n");
+		nv_error(priv, "HUB_SET_CHAN timeout\n");
 		nvc0_graph_ctxctl_debug(priv);
 		nouveau_gpuobj_ref(NULL, &info->chan);
 		return -EBUSY;
@@ -135,6 +132,8 @@
 void
 nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf)
 {
+	struct nvc0_graph_priv *priv = info->priv;
+
 	info->mmio->addr = addr;
 	info->mmio->data = data;
 	info->mmio->shift = shift;
@@ -143,7 +142,7 @@
 
 	if (shift)
 		data |= info->buffer[buf] >> shift;
-	nv_wr32(info->dev, addr, data);
+	nv_wr32(priv, addr, data);
 }
 
 int
@@ -153,11 +152,11 @@
 	int i;
 
 	if (priv->firmware) {
-		nv_wr32(info->dev, 0x409840, 0x00000003);
-		nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
-		nv_wr32(info->dev, 0x409504, 0x00000009);
-		if (!nv_wait(info->dev, 0x409800, 0x00000001, 0x00000000)) {
-			NV_ERROR(info->dev, "unload_ctx timeout\n");
+		nv_wr32(priv, 0x409840, 0x00000003);
+		nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
+		nv_wr32(priv, 0x409504, 0x00000009);
+		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000000)) {
+			nv_error(priv, "unload_ctx timeout\n");
 			return -EBUSY;
 		}
 
@@ -165,12 +164,12 @@
 	}
 
 	/* HUB_FUC(CTX_SAVE) */
-	nv_wr32(info->dev, 0x409840, 0x80000000);
-	nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
-	nv_wr32(info->dev, 0x409504, 0x00000002);
-	if (!nv_wait(info->dev, 0x409800, 0x80000000, 0x80000000)) {
-		NV_ERROR(info->dev, "HUB_CTX_SAVE timeout\n");
-		nvc0_graph_ctxctl_debug(info->dev);
+	nv_wr32(priv, 0x409840, 0x80000000);
+	nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
+	nv_wr32(priv, 0x409504, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+		nv_error(priv, "HUB_CTX_SAVE timeout\n");
+		nvc0_graph_ctxctl_debug(priv);
 		return -EBUSY;
 	}
 
@@ -186,7 +185,7 @@
 }
 
 static void
-nvc0_grctx_generate_9097(struct drm_device *priv)
+nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1343,7 +1342,7 @@
 }
 
 static void
-nvc0_grctx_generate_9197(struct drm_device *priv)
+nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1356,7 +1355,7 @@
 }
 
 static void
-nvc0_grctx_generate_9297(struct drm_device *priv)
+nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1374,7 +1373,7 @@
 }
 
 static void
-nvc0_grctx_generate_902d(struct drm_device *priv)
+nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
 	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -1396,7 +1395,7 @@
 }
 
 static void
-nvc0_grctx_generate_9039(struct drm_device *priv)
+nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x9039, 0x030c, 0x00000000);
 	nv_mthd(priv, 0x9039, 0x0310, 0x00000000);
@@ -1409,12 +1408,11 @@
 }
 
 static void
-nvc0_grctx_generate_90c0(struct drm_device *priv)
+nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 	int i;
 
-	for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
+	for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) {
 		nv_mthd(priv, 0x90c0, 0x2700 + (i * 0x40), 0x00000000);
 		nv_mthd(priv, 0x90c0, 0x2720 + (i * 0x40), 0x00000000);
 		nv_mthd(priv, 0x90c0, 0x2704 + (i * 0x40), 0x00000000);
@@ -1430,7 +1428,7 @@
 	nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000);
 	nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000);
 	nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000);
-	for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
+	for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) {
 		nv_mthd(priv, 0x90c0, 0x2710 + (i * 0x40), 0x00014000);
 		nv_mthd(priv, 0x90c0, 0x2730 + (i * 0x40), 0x00014000);
 		nv_mthd(priv, 0x90c0, 0x2714 + (i * 0x40), 0x00000040);
@@ -1458,7 +1456,7 @@
 }
 
 static void
-nvc0_grctx_generate_dispatch(struct drm_device *priv)
+nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv)
 {
 	int i;
 
@@ -1511,7 +1509,7 @@
 }
 
 static void
-nvc0_grctx_generate_macro(struct drm_device *priv)
+nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404404, 0x00000000);
 	nv_wr32(priv, 0x404408, 0x00000000);
@@ -1536,7 +1534,7 @@
 }
 
 static void
-nvc0_grctx_generate_m2mf(struct drm_device *priv)
+nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404604, 0x00000015);
 	nv_wr32(priv, 0x404608, 0x00000000);
@@ -1600,7 +1598,7 @@
 }
 
 static void
-nvc0_grctx_generate_unk47xx(struct drm_device *priv)
+nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404700, 0x00000000);
 	nv_wr32(priv, 0x404704, 0x00000000);
@@ -1627,16 +1625,15 @@
 }
 
 static void
-nvc0_grctx_generate_shaders(struct drm_device *priv)
+nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x405800, 0x0f8000bf);
 		nv_wr32(priv, 0x405830, 0x02180218);
 		nv_wr32(priv, 0x405834, 0x08000000);
 	} else
-	if (dev_priv->chipset == 0xc1) {
+	if (nv_device(priv)->chipset == 0xc1) {
 		nv_wr32(priv, 0x405800, 0x0f8000bf);
 		nv_wr32(priv, 0x405830, 0x02180218);
 		nv_wr32(priv, 0x405834, 0x00000000);
@@ -1657,7 +1654,7 @@
 }
 
 static void
-nvc0_grctx_generate_unk60xx(struct drm_device *priv)
+nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x406020, 0x000103c1);
 	nv_wr32(priv, 0x406028, 0x00000001);
@@ -1667,25 +1664,24 @@
 }
 
 static void
-nvc0_grctx_generate_unk64xx(struct drm_device *priv)
+nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 
 	nv_wr32(priv, 0x4064a8, 0x00000000);
 	nv_wr32(priv, 0x4064ac, 0x00003fff);
 	nv_wr32(priv, 0x4064b4, 0x00000000);
 	nv_wr32(priv, 0x4064b8, 0x00000000);
-	if (dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xd9)
 		nv_wr32(priv, 0x4064bc, 0x00000000);
-	if (dev_priv->chipset == 0xc1 ||
-	    dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xc1 ||
+	    nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x4064c0, 0x80140078);
 		nv_wr32(priv, 0x4064c4, 0x0086ffff);
 	}
 }
 
 static void
-nvc0_grctx_generate_tpbus(struct drm_device *priv)
+nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407804, 0x00000023);
 	nv_wr32(priv, 0x40780c, 0x0a418820);
@@ -1698,7 +1694,7 @@
 }
 
 static void
-nvc0_grctx_generate_ccache(struct drm_device *priv)
+nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408000, 0x00000000);
 	nv_wr32(priv, 0x408004, 0x00000000);
@@ -1711,10 +1707,9 @@
 }
 
 static void
-nvc0_grctx_generate_rop(struct drm_device *priv)
+nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 
 	/* ROPC_BROADCAST */
 	nv_wr32(priv, 0x408800, 0x02802a3c);
@@ -1741,10 +1736,9 @@
 }
 
 static void
-nvc0_grctx_generate_gpc(struct drm_device *priv)
+nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 	int i;
 
 	/* GPC_BROADCAST */
@@ -1834,10 +1828,9 @@
 }
 
 static void
-nvc0_grctx_generate_tp(struct drm_device *priv)
+nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 
 	/* GPC_BROADCAST.TP_BROADCAST */
 	nv_wr32(priv, 0x419818, 0x00000000);
@@ -1876,7 +1869,7 @@
 	nv_wr32(priv, 0x419c04, 0x00000006);
 	nv_wr32(priv, 0x419c08, 0x00000002);
 	nv_wr32(priv, 0x419c20, 0x00000000);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x419c24, 0x00084210);
 		nv_wr32(priv, 0x419c28, 0x3cf3cf3c);
 		nv_wr32(priv, 0x419cb0, 0x00020048);
@@ -1929,16 +1922,14 @@
 }
 
 int
-nvc0_grctx_generate(struct drm_device *priv)
+nvc0_grctx_generate(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
 	struct nvc0_grctx info;
 	int ret, i, gpc, tpc, id;
 	u32 fermi = nvc0_graph_class(priv);
 	u32 r000260, tmp;
 
-	ret = nvc0_grctx_init(priv, oprv, &info);
+	ret = nvc0_grctx_init(priv, &info);
 	if (ret)
 		return ret;
 
@@ -1975,11 +1966,11 @@
 	mmio_list(0x419008, 0x00000000,  0, 0);
 	mmio_list(0x418808, 0x00000000,  8, 0);
 	mmio_list(0x41880c, 0x80000018,  0, 0);
-	if (dev_priv->chipset != 0xc1) {
+	if (nv_device(priv)->chipset != 0xc1) {
 		tmp = 0x02180000;
 		mmio_list(0x405830, tmp, 0, 0);
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
 				u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
 				mmio_list(reg, tmp, 0, 0);
 				tmp += 0x0324;
@@ -1989,13 +1980,13 @@
 		tmp = 0x02180000;
 		mmio_list(0x405830, 0x00000218 | tmp, 0, 0);
 		mmio_list(0x4064c4, 0x0086ffff, 0, 0);
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
 				u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
 				mmio_list(reg, 0x10000000 | tmp, 0, 0);
 				tmp += 0x0324;
 			}
-			for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
+			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
 				u32 reg = TPC_UNIT(gpc, tpc, 0x0544);
 				mmio_list(reg, tmp, 0, 0);
 				tmp += 0x0324;
@@ -2004,8 +1995,8 @@
 	}
 
 	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			if (tpc < oprv->tpc_nr[gpc]) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			if (tpc < priv->tpc_nr[gpc]) {
 				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
 				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
 				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
@@ -2013,14 +2004,14 @@
 				id++;
 			}
 
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
 		}
 	}
 
 	tmp = 0;
-	for (i = 0; i < oprv->gpc_nr; i++)
-		tmp |= oprv->tpc_nr[i] << (i * 4);
+	for (i = 0; i < priv->gpc_nr; i++)
+		tmp |= priv->tpc_nr[i] << (i * 4);
 	nv_wr32(priv, 0x406028, tmp);
 	nv_wr32(priv, 0x405870, tmp);
 
@@ -2034,13 +2025,13 @@
 	if (1) {
 		u8 tpcnr[GPC_MAX], data[TPC_MAX];
 
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 		memset(data, 0x1f, sizeof(data));
 
 		gpc = -1;
-		for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
 			tpcnr[gpc]--;
 			data[tpc] = gpc;
@@ -2056,12 +2047,12 @@
 		u8 shift, ntpcv;
 
 		/* calculate first set of magics */
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 
 		gpc = -1;
-		for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
 			tpcnr[gpc]--;
 
@@ -2073,7 +2064,7 @@
 
 		/* and the second... */
 		shift = 0;
-		ntpcv = oprv->tpc_total;
+		ntpcv = priv->tpc_total;
 		while (!(ntpcv & (1 << 4))) {
 			ntpcv <<= 1;
 			shift++;
@@ -2086,22 +2077,22 @@
 			data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
 		/* GPC_BROADCAST */
-		nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) |
-					oprv->magic_not_rop_nr);
+		nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+					priv->magic_not_rop_nr);
 		for (i = 0; i < 6; i++)
 			nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
 
 		/* GPC_BROADCAST.TP_BROADCAST */
-		nv_wr32(priv, 0x419bd0, (oprv->tpc_total << 8) |
-				       oprv->magic_not_rop_nr |
+		nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
+				       priv->magic_not_rop_nr |
 				       data2[0]);
 		nv_wr32(priv, 0x419be4, data2[1]);
 		for (i = 0; i < 6; i++)
 			nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
 
 		/* UNK78xx */
-		nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) |
-					oprv->magic_not_rop_nr);
+		nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+					priv->magic_not_rop_nr);
 		for (i = 0; i < 6; i++)
 			nv_wr32(priv, 0x40780c + (i * 4), data[i]);
 	}
@@ -2110,18 +2101,18 @@
 		u32 tpc_mask = 0, tpc_set = 0;
 		u8  tpcnr[GPC_MAX], a, b;
 
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
-			tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
+		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+			tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
 
 		for (i = 0, gpc = -1, b = -1; i < 32; i++) {
-			a = (i * (oprv->tpc_total - 1)) / 32;
+			a = (i * (priv->tpc_total - 1)) / 32;
 			if (a != b) {
 				b = a;
 				do {
-					gpc = (gpc + 1) % oprv->gpc_nr;
+					gpc = (gpc + 1) % priv->gpc_nr;
 				} while (!tpcnr[gpc]);
-				tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
+				tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
 
 				tpc_set |= 1 << ((gpc * 8) + tpc);
 			}
@@ -2232,7 +2223,7 @@
 	nv_icmd(priv, 0x00000215, 0x00000040);
 	nv_icmd(priv, 0x00000216, 0x00000040);
 	nv_icmd(priv, 0x00000217, 0x00000040);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		for (i = 0x0400; i <= 0x0417; i++)
 			nv_icmd(priv, i, 0x00000040);
 	}
@@ -2244,7 +2235,7 @@
 	nv_icmd(priv, 0x0000021d, 0x0000c080);
 	nv_icmd(priv, 0x0000021e, 0x0000c080);
 	nv_icmd(priv, 0x0000021f, 0x0000c080);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		for (i = 0x0440; i <= 0x0457; i++)
 			nv_icmd(priv, i, 0x0000c080);
 	}
@@ -2810,8 +2801,8 @@
 	nv_icmd(priv, 0x0000053f, 0xffff0000);
 	nv_icmd(priv, 0x00000585, 0x0000003f);
 	nv_icmd(priv, 0x00000576, 0x00000003);
-	if (dev_priv->chipset == 0xc1 ||
-	    dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xc1 ||
+	    nv_device(priv)->chipset == 0xd9)
 		nv_icmd(priv, 0x0000057b, 0x00000059);
 	nv_icmd(priv, 0x00000586, 0x00000040);
 	nv_icmd(priv, 0x00000582, 0x00000080);
@@ -2913,7 +2904,7 @@
 	nv_icmd(priv, 0x00000957, 0x00000003);
 	nv_icmd(priv, 0x0000095e, 0x20164010);
 	nv_icmd(priv, 0x0000095f, 0x00000020);
-	if (dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xd9)
 		nv_icmd(priv, 0x0000097d, 0x00000020);
 	nv_icmd(priv, 0x00000683, 0x00000006);
 	nv_icmd(priv, 0x00000685, 0x003fffff);
@@ -3056,5 +3047,6 @@
 	nvc0_grctx_generate_90c0(priv);
 
 	nv_wr32(priv, 0x000260, r000260);
+
 	return nvc0_grctx_fini(&info);
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
index e550317..6d8c639 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
@@ -22,13 +22,10 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <core/mm.h>
 #include "nvc0.h"
 
 static void
-nve0_grctx_generate_icmd(struct drm_device *priv)
+nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x400208, 0x80000000);
 	nv_icmd(priv, 0x001000, 0x00000004);
@@ -916,7 +913,7 @@
 }
 
 static void
-nve0_grctx_generate_a097(struct drm_device *priv)
+nve0_grctx_generate_a097(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0xa097, 0x0800, 0x00000000);
 	nv_mthd(priv, 0xa097, 0x0840, 0x00000000);
@@ -2146,7 +2143,7 @@
 }
 
 static void
-nve0_grctx_generate_902d(struct drm_device *priv)
+nve0_grctx_generate_902d(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
 	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -2169,7 +2166,7 @@
 }
 
 static void
-nve0_graph_generate_unk40xx(struct drm_device *priv)
+nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404010, 0x0);
 	nv_wr32(priv, 0x404014, 0x0);
@@ -2213,7 +2210,7 @@
 }
 
 static void
-nve0_graph_generate_unk44xx(struct drm_device *priv)
+nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404404, 0x0);
 	nv_wr32(priv, 0x404408, 0x0);
@@ -2238,7 +2235,7 @@
 }
 
 static void
-nve0_graph_generate_unk46xx(struct drm_device *priv)
+nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404604, 0x14);
 	nv_wr32(priv, 0x404608, 0x0);
@@ -2278,7 +2275,7 @@
 }
 
 static void
-nve0_graph_generate_unk47xx(struct drm_device *priv)
+nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404700, 0x0);
 	nv_wr32(priv, 0x404704, 0x0);
@@ -2299,7 +2296,7 @@
 }
 
 static void
-nve0_graph_generate_unk58xx(struct drm_device *priv)
+nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x405800, 0xf8000bf);
 	nv_wr32(priv, 0x405830, 0x2180648);
@@ -2318,7 +2315,7 @@
 }
 
 static void
-nve0_graph_generate_unk60xx(struct drm_device *priv)
+nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x406020, 0x4103c1);
 	nv_wr32(priv, 0x406028, 0x1);
@@ -2328,7 +2325,7 @@
 }
 
 static void
-nve0_graph_generate_unk64xx(struct drm_device *priv)
+nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x4064a8, 0x0);
 	nv_wr32(priv, 0x4064ac, 0x3fff);
@@ -2350,13 +2347,13 @@
 }
 
 static void
-nve0_graph_generate_unk70xx(struct drm_device *priv)
+nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407040, 0x0);
 }
 
 static void
-nve0_graph_generate_unk78xx(struct drm_device *priv)
+nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407804, 0x23);
 	nv_wr32(priv, 0x40780c, 0xa418820);
@@ -2369,7 +2366,7 @@
 }
 
 static void
-nve0_graph_generate_unk80xx(struct drm_device *priv)
+nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408000, 0x0);
 	nv_wr32(priv, 0x408004, 0x0);
@@ -2382,7 +2379,7 @@
 }
 
 static void
-nve0_graph_generate_unk88xx(struct drm_device *priv)
+nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408800, 0x2802a3c);
 	nv_wr32(priv, 0x408804, 0x40);
@@ -2395,7 +2392,7 @@
 }
 
 static void
-nve0_graph_generate_gpc(struct drm_device *priv)
+nve0_graph_generate_gpc(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x418380, 0x16);
 	nv_wr32(priv, 0x418400, 0x38004e00);
@@ -2521,7 +2518,7 @@
 }
 
 static void
-nve0_graph_generate_tpc(struct drm_device *priv)
+nve0_graph_generate_tpc(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x419848, 0x0);
 	nv_wr32(priv, 0x419864, 0x129);
@@ -2586,7 +2583,7 @@
 }
 
 static void
-nve0_graph_generate_tpcunk(struct drm_device *priv)
+nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x41be24, 0x6);
 	nv_wr32(priv, 0x41bec0, 0x12180000);
@@ -2604,9 +2601,8 @@
 }
 
 int
-nve0_grctx_generate(struct drm_device *priv)
+nve0_grctx_generate(struct nvc0_graph_priv *priv)
 {
-	struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
 	struct nvc0_grctx info;
 	int ret, i, gpc, tpc, id;
 	u32 data[6] = {}, data2[2] = {}, tmp;
@@ -2615,7 +2611,7 @@
 	u8 tpcnr[GPC_MAX], a, b;
 	u8 shift, ntpcv;
 
-	ret = nvc0_grctx_init(priv, oprv, &info);
+	ret = nvc0_grctx_init(priv, &info);
 	if (ret)
 		return ret;
 
@@ -2657,17 +2653,17 @@
 	mmio_list(0x419848, 0x10000000, 12, 2);
 	mmio_list(0x405830, 0x02180648,  0, 0);
 	mmio_list(0x4064c4, 0x0192ffff,  0, 0);
-	for (gpc = 0, offset = 0; gpc < oprv->gpc_nr; gpc++) {
-		u16 magic0 = 0x0218 * oprv->tpc_nr[gpc];
-		u16 magic1 = 0x0648 * oprv->tpc_nr[gpc];
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+		u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
 		magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
 		magic[gpc][1]  = 0x00000000 | (magic1 << 16);
-		offset += 0x0324 * oprv->tpc_nr[gpc];
+		offset += 0x0324 * priv->tpc_nr[gpc];
 	}
-	for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
 		mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
 		mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
-		offset += 0x07ff * oprv->tpc_nr[gpc];
+		offset += 0x07ff * priv->tpc_nr[gpc];
 	}
 	mmio_list(0x17e91c, 0x06060609, 0, 0);
 	mmio_list(0x17e920, 0x00090a05, 0, 0);
@@ -2680,22 +2676,22 @@
 	nv_wr32(priv, 0x419c00, 0xa);
 
 	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			if (tpc < oprv->tpc_nr[gpc]) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			if (tpc < priv->tpc_nr[gpc]) {
 				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0698), id);
 				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x04e8), id);
 				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
 				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0088), id++);
 			}
 
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
 		}
 	}
 
 	tmp = 0;
-	for (i = 0; i < oprv->gpc_nr; i++)
-		tmp |= oprv->tpc_nr[i] << (i * 4);
+	for (i = 0; i < priv->gpc_nr; i++)
+		tmp |= priv->tpc_nr[i] << (i * 4);
 	nv_wr32(priv, 0x406028, tmp);
 	nv_wr32(priv, 0x405870, tmp);
 
@@ -2707,12 +2703,12 @@
 	nv_wr32(priv, 0x40587c, 0x0);
 
 	/* calculate first set of magics */
-	memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 
 	gpc = -1;
-	for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 		do {
-			gpc = (gpc + 1) % oprv->gpc_nr;
+			gpc = (gpc + 1) % priv->gpc_nr;
 		} while (!tpcnr[gpc]);
 		tpcnr[gpc]--;
 
@@ -2724,7 +2720,7 @@
 
 	/* and the second... */
 	shift = 0;
-	ntpcv = oprv->tpc_total;
+	ntpcv = priv->tpc_total;
 	while (!(ntpcv & (1 << 4))) {
 		ntpcv <<= 1;
 		shift++;
@@ -2733,13 +2729,13 @@
 	data2[0]  = ntpcv << 16;
 	data2[0] |= shift << 21;
 	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-	data2[0] |= oprv->tpc_total << 8;
-	data2[0] |= oprv->magic_not_rop_nr;
+	data2[0] |= priv->tpc_total << 8;
+	data2[0] |= priv->magic_not_rop_nr;
 	for (i = 1; i < 7; i++)
 		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
 	/* and write it all the various parts of PGRAPH */
-	nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
+	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
 	for (i = 0; i < 6; i++)
 		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
 
@@ -2748,23 +2744,23 @@
 	for (i = 0; i < 6; i++)
 		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
 
-	nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
+	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
 	for (i = 0; i < 6; i++)
 		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
 
 
-	memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
-	for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
-		tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+		tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
 
 	for (i = 0, gpc = -1, b = -1; i < 32; i++) {
-		a = (i * (oprv->tpc_total - 1)) / 32;
+		a = (i * (priv->tpc_total - 1)) / 32;
 		if (a != b) {
 			b = a;
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
-			tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
+			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
 
 			tpc_set |= 1 << ((gpc * 8) + tpc);
 		}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
index 7f3a275..e5b0189 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
@@ -22,19 +22,22 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
-#include "nouveau_hw.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/namedb.h>
 
-struct nv04_graph_engine {
-	struct nouveau_exec_engine base;
-};
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/timer.h>
 
-static uint32_t nv04_graph_ctx_regs[] = {
+#include <engine/fifo.h>
+#include <engine/graph.h>
+
+#include "regs.h"
+
+static u32
+nv04_graph_ctx_regs[] = {
 	0x0040053c,
 	0x00400544,
 	0x00400540,
@@ -348,205 +351,28 @@
 	NV04_PGRAPH_DEBUG_3
 };
 
-struct graph_state {
-	uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+struct nv04_graph_priv {
+	struct nouveau_graph base;
+	struct nv04_graph_chan *chan[16];
+	spinlock_t lock;
 };
 
-static struct nouveau_channel *
-nv04_graph_channel(struct drm_device *dev)
+struct nv04_graph_chan {
+	struct nouveau_object base;
+	int chid;
+	u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+};
+
+
+static inline struct nv04_graph_priv *
+nv04_graph_priv(struct nv04_graph_chan *chan)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int chid = 15;
-
-	if (nv_rd32(dev, NV04_PGRAPH_CTX_CONTROL) & 0x00010000)
-		chid = nv_rd32(dev, NV04_PGRAPH_CTX_USER) >> 24;
-
-	if (chid > 15)
-		return NULL;
-
-	return dev_priv->channels.ptr[chid];
+	return (void *)nv_object(chan)->engine;
 }
 
-static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
-		if (nv04_graph_ctx_regs[i] == reg)
-			return &ctx->nv04[i];
-	}
-
-	return NULL;
-}
-
-static int
-nv04_graph_load_context(struct nouveau_channel *chan)
-{
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct drm_device *dev = chan->dev;
-	uint32_t tmp;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		nv_wr32(dev, nv04_graph_ctx_regs[i], pgraph_ctx->nv04[i]);
-
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
-
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp | chan->id << 24);
-
-	tmp = nv_rd32(dev, NV04_PGRAPH_FFINTFC_ST2);
-	nv_wr32(dev, NV04_PGRAPH_FFINTFC_ST2, tmp & 0x000fffff);
-
-	return 0;
-}
-
-static int
-nv04_graph_unload_context(struct drm_device *dev)
-{
-	struct nouveau_channel *chan = NULL;
-	struct graph_state *ctx;
-	uint32_t tmp;
-	int i;
-
-	chan = nv04_graph_channel(dev);
-	if (!chan)
-		return 0;
-	ctx = chan->engctx[NVOBJ_ENGINE_GR];
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
-
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 15 << 24;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
-	return 0;
-}
-
-static int
-nv04_graph_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct graph_state *pgraph_ctx;
-	NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
-	pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
-	if (pgraph_ctx == NULL)
-		return -ENOMEM;
-
-	*ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-	chan->engctx[engine] = pgraph_ctx;
-	return 0;
-}
-
-static void
-nv04_graph_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[engine];
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-	/* Unload the context if it's the currently active one */
-	if (nv04_graph_channel(dev) == chan)
-		nv04_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	kfree(pgraph_ctx);
-	chan->engctx[engine] = NULL;
-}
-
-int
-nv04_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 1;
-	obj->class  = class;
-
-#ifdef __BIG_ENDIAN
-	nv_wo32(obj, 0x00, 0x00080000 | class);
-#else
-	nv_wo32(obj, 0x00, class);
-#endif
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
-}
-
-static int
-nv04_graph_init(struct drm_device *dev, int engine)
-{
-	uint32_t tmp;
-
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
-
-	/* Enable PGRAPH interrupts */
-	nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_VALID1, 0);
-	nv_wr32(dev, NV04_PGRAPH_VALID2, 0);
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x000001FF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
-	/*1231C000 blob, 001 haiku*/
-	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
-	/*0x72111100 blob , 01 haiku*/
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
-	/*haiku same*/
-
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
-	/*haiku and blob 10d4*/
-
-	nv_wr32(dev, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 15 << 24;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
-
-	/* These don't belong here, they're part of a per-channel context */
-	nv_wr32(dev, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
-
-	return 0;
-}
-
-static int
-nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv04_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
 /*
  * Software methods, why they are needed, and how they all work:
@@ -623,37 +449,35 @@
  */
 
 static void
-nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value)
+nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value)
 {
-	struct drm_device *dev = chan->dev;
-	u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
-	int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
 	u32 tmp;
 
-	tmp  = nv_ri32(dev, instance);
+	tmp  = nv_ro32(object, 0x00);
 	tmp &= ~mask;
 	tmp |= value;
+	nv_wo32(object, 0x00, tmp);
 
-	nv_wi32(dev, instance, tmp);
-	nv_wr32(dev, NV04_PGRAPH_CTX_SWITCH1, tmp);
-	nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
+	nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
 }
 
 static void
-nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value)
+nv04_graph_set_ctx_val(struct nouveau_object *object, u32 mask, u32 value)
 {
-	struct drm_device *dev = chan->dev;
-	u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
-	u32 tmp, ctx1;
 	int class, op, valid = 1;
+	u32 tmp, ctx1;
 
-	ctx1 = nv_ri32(dev, instance);
+	ctx1 = nv_ro32(object, 0x00);
 	class = ctx1 & 0xff;
 	op = (ctx1 >> 15) & 7;
-	tmp  = nv_ri32(dev, instance + 0xc);
+
+	tmp = nv_ro32(object, 0x0c);
 	tmp &= ~mask;
 	tmp |= value;
-	nv_wi32(dev, instance + 0xc, tmp);
+	nv_wo32(object, 0x0c, tmp);
 
 	/* check for valid surf2d/surf_dst/surf_color */
 	if (!(tmp & 0x02000000))
@@ -685,30 +509,34 @@
 		break;
 	}
 
-	nv04_graph_set_ctx1(chan, 0x01000000, valid << 24);
+	nv04_graph_set_ctx1(object, 0x01000000, valid << 24);
 }
 
 static int
-nv04_graph_mthd_set_operation(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_set_operation(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
+	u32 class = nv_ro32(object, 0) & 0xff;
+	u32 data = *(u32 *)args;
 	if (data > 5)
 		return 1;
 	/* Old versions of the objects only accept first three operations. */
 	if (data > 2 && class < 0x40)
 		return 1;
-	nv04_graph_set_ctx1(chan, 0x00038000, data << 15);
+	nv04_graph_set_ctx1(object, 0x00038000, data << 15);
 	/* changing operation changes set of objects needed for validation */
-	nv04_graph_set_ctx_val(chan, 0, 0);
+	nv04_graph_set_ctx_val(object, 0, 0);
 	return 0;
 }
 
 static int
-nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	uint32_t min = data & 0xffff, max;
-	uint32_t w = data >> 16;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
 	if (min & 0x8000)
 		/* too large */
 		return 1;
@@ -717,17 +545,19 @@
 		w |= 0xffff0000;
 	max = min + w;
 	max &= 0x3ffff;
-	nv_wr32(chan->dev, 0x40053c, min);
-	nv_wr32(chan->dev, 0x400544, max);
+	nv_wr32(priv, 0x40053c, min);
+	nv_wr32(priv, 0x400544, max);
 	return 0;
 }
 
 static int
-nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	uint32_t min = data & 0xffff, max;
-	uint32_t w = data >> 16;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
 	if (min & 0x8000)
 		/* too large */
 		return 1;
@@ -736,223 +566,661 @@
 		w |= 0xffff0000;
 	max = min + w;
 	max &= 0x3ffff;
-	nv_wr32(chan->dev, 0x400540, min);
-	nv_wr32(chan->dev, 0x400548, max);
+	nv_wr32(priv, 0x400540, min);
+	nv_wr32(priv, 0x400548, max);
 	return 0;
 }
 
-static int
-nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan,
-			    u32 class, u32 mthd, u32 data)
+static u16
+nv04_graph_mthd_bind_class(struct nouveau_object *object, u32 *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	struct nouveau_instmem *imem = nouveau_instmem(object);
+	u32 inst = *(u32 *)args << 4;
+	return nv_ro32(imem, inst);
+}
+
+static int
+nv04_graph_mthd_bind_surf2d(struct nouveau_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x42:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan,
-				    u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_object *object, u32 mthd,
+				    void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x42:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	case 0x52:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0x00004000);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0x00004000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0);
 		return 0;
 	case 0x18:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0);
 		return 0;
 	case 0x44:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_rop(struct nouveau_channel *chan,
-			 u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd,
+			 void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x10000000, 0);
+		nv04_graph_set_ctx_val(object, 0x10000000, 0);
 		return 0;
 	case 0x43:
-		nv04_graph_set_ctx_val(chan, 0x10000000, 0x10000000);
+		nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x20000000, 0);
+		nv04_graph_set_ctx_val(object, 0x20000000, 0);
 		return 0;
 	case 0x12:
-		nv04_graph_set_ctx_val(chan, 0x20000000, 0x20000000);
+		nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x40000000, 0);
+		nv04_graph_set_ctx_val(object, 0x40000000, 0);
 		return 0;
 	case 0x72:
-		nv04_graph_set_ctx_val(chan, 0x40000000, 0x40000000);
+		nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x58:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0);
 		return 0;
 	case 0x59:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan,
-				u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd,
+				void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x5a:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd,
+			       void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0);
 		return 0;
 	case 0x5b:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_clip(struct nouveau_channel *chan,
-			  u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x2000, 0);
+		nv04_graph_set_ctx1(object, 0x2000, 0);
 		return 0;
 	case 0x19:
-		nv04_graph_set_ctx1(chan, 0x2000, 0x2000);
+		nv04_graph_set_ctx1(object, 0x2000, 0x2000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
-			    u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd,
+			    void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x1000, 0);
+		nv04_graph_set_ctx1(object, 0x1000, 0);
 		return 0;
 	/* Yes, for some reason even the old versions of objects
 	 * accept 0x57 and not 0x17. Consistency be damned.
 	 */
 	case 0x57:
-		nv04_graph_set_ctx1(chan, 0x1000, 0x1000);
+		nv04_graph_set_ctx1(object, 0x1000, 0x1000);
 		return 0;
 	}
 	return 1;
 }
 
-static struct nouveau_bitfield nv04_graph_intr[] = {
+static struct nouveau_omthds
+nv03_graph_gdi_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_patt },
+	{ 0x0188, nv04_graph_mthd_bind_rop },
+	{ 0x018c, nv04_graph_mthd_bind_beta1 },
+	{ 0x0190, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_gdi_omthds[] = {
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_blit_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv01_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_surf_dst },
+	{ 0x019c, nv04_graph_mthd_bind_surf_src },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_blit_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_beta4 },
+	{ 0x019c, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_iifc_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_chroma },
+	{ 0x018c, nv01_graph_mthd_bind_clip },
+	{ 0x0190, nv04_graph_mthd_bind_patt },
+	{ 0x0194, nv04_graph_mthd_bind_rop },
+	{ 0x0198, nv04_graph_mthd_bind_beta1 },
+	{ 0x019c, nv04_graph_mthd_bind_beta4 },
+	{ 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
+	{ 0x03e4, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_ifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv01_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_ifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_beta4 },
+	{ 0x019c, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_sifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_sifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_sifm_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x0304, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_sifm_omthds[] = {
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x0304, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_surf3d_omthds[] = {
+	{ 0x02f8, nv04_graph_mthd_surf3d_clip_h },
+	{ 0x02fc, nv04_graph_mthd_surf3d_clip_v },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_ttri_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_surf_color },
+	{ 0x0190, nv04_graph_mthd_bind_surf_zeta },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_prim_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_clip },
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_prim_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_clip },
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static int
+nv04_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nouveau_gpuobj *obj;
+	int ret;
+
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
+#endif
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+struct nouveau_ofuncs
+nv04_graph_ofuncs = {
+	.ctor = nv04_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv04_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0017, &nv04_graph_ofuncs }, /* chroma */
+	{ 0x0018, &nv04_graph_ofuncs }, /* pattern (nv01) */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x001c, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* line */
+	{ 0x001d, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* tri */
+	{ 0x001e, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* rect */
+	{ 0x001f, &nv04_graph_ofuncs, nv01_graph_blit_omthds },
+	{ 0x0021, &nv04_graph_ofuncs, nv01_graph_ifc_omthds },
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0036, &nv04_graph_ofuncs, nv03_graph_sifc_omthds },
+	{ 0x0037, &nv04_graph_ofuncs, nv03_graph_sifm_omthds },
+	{ 0x0038, &nv04_graph_ofuncs }, /* dvd subpicture */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0042, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x0048, &nv04_graph_ofuncs, nv03_graph_ttri_omthds },
+	{ 0x004a, &nv04_graph_ofuncs, nv04_graph_gdi_omthds },
+	{ 0x004b, &nv04_graph_ofuncs, nv03_graph_gdi_omthds },
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x0053, &nv04_graph_ofuncs, nv04_graph_surf3d_omthds },
+	{ 0x0054, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0055, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0057, &nv04_graph_ofuncs }, /* chroma */
+	{ 0x0058, &nv04_graph_ofuncs }, /* surf_dst */
+	{ 0x0059, &nv04_graph_ofuncs }, /* surf_src */
+	{ 0x005a, &nv04_graph_ofuncs }, /* surf_color */
+	{ 0x005b, &nv04_graph_ofuncs }, /* surf_zeta */
+	{ 0x005c, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* line */
+	{ 0x005d, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* tri */
+	{ 0x005e, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* rect */
+	{ 0x005f, &nv04_graph_ofuncs, nv04_graph_blit_omthds },
+	{ 0x0060, &nv04_graph_ofuncs, nv04_graph_iifc_omthds },
+	{ 0x0061, &nv04_graph_ofuncs, nv04_graph_ifc_omthds },
+	{ 0x0064, &nv04_graph_ofuncs }, /* iifc (nv05) */
+	{ 0x0065, &nv04_graph_ofuncs }, /* ifc (nv05) */
+	{ 0x0066, &nv04_graph_ofuncs }, /* sifc (nv05) */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0076, &nv04_graph_ofuncs, nv04_graph_sifc_omthds },
+	{ 0x0077, &nv04_graph_ofuncs, nv04_graph_sifm_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv04_graph_chan *
+nv04_graph_channel(struct nv04_graph_priv *priv)
+{
+	struct nv04_graph_chan *chan = NULL;
+	if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
+		int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static int
+nv04_graph_load_context(struct nv04_graph_chan *chan, int chid)
+{
+	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
+		nv_wr32(priv, nv04_graph_ctx_regs[i], chan->nv04[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
+	return 0;
+}
+
+static int
+nv04_graph_unload_context(struct nv04_graph_chan *chan)
+{
+	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
+		chan->nv04[i] = nv_rd32(priv, nv04_graph_ctx_regs[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+	return 0;
+}
+
+static void
+nv04_graph_context_switch(struct nv04_graph_priv *priv)
+{
+	struct nv04_graph_chan *prev = NULL;
+	struct nv04_graph_chan *next = NULL;
+	unsigned long flags;
+	int chid;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_graph_idle(priv);
+
+	/* If previous context is valid, we need to save it */
+	prev = nv04_graph_channel(priv);
+	if (prev)
+		nv04_graph_unload_context(prev);
+
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
+	next = priv->chan[chid];
+	if (next)
+		nv04_graph_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u32 *ctx_reg(struct nv04_graph_chan *chan, u32 reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
+		if (nv04_graph_ctx_regs[i] == reg)
+			return &chan->nv04[i];
+	}
+
+	return NULL;
+}
+
+static int
+nv04_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nouveau_fifo_chan *fifo = (void *)parent;
+	struct nv04_graph_priv *priv = (void *)engine;
+	struct nv04_graph_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nouveau_object_destroy(&chan->base);
+		return 1;
+	}
+
+	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+static void
+nv04_graph_context_dtor(struct nouveau_object *object)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nouveau_object_destroy(&chan->base);
+}
+
+static int
+nv04_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv04_graph_channel(priv) == chan)
+		nv04_graph_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nouveau_object_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv04_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_graph_context_ctor,
+		.dtor = nv04_graph_context_dtor,
+		.init = nouveau_object_init,
+		.fini = nv04_graph_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+bool
+nv04_graph_idle(void *obj)
+{
+	struct nouveau_graph *graph = nouveau_graph(obj);
+	u32 mask = 0xffffffff;
+
+	if (nv_device(obj)->card_type == NV_40)
+		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
+
+	if (!nv_wait(graph, NV04_PGRAPH_STATUS, mask, 0)) {
+		nv_error(graph, "idle timed out with status 0x%08x\n",
+			 nv_rd32(graph, NV04_PGRAPH_STATUS));
+		return false;
+	}
+
+	return true;
+}
+
+static struct nouveau_bitfield
+nv04_graph_intr_name[] = {
 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
 	{}
 };
 
-static struct nouveau_bitfield nv04_graph_nstatus[] = {
+static struct nouveau_bitfield
+nv04_graph_nstatus[] = {
 	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
 	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
 	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
@@ -960,7 +1228,8 @@
 	{}
 };
 
-struct nouveau_bitfield nv04_graph_nsource[] = {
+struct nouveau_bitfield
+nv04_graph_nsource[] = {
 	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
 	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
 	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
@@ -984,343 +1253,135 @@
 };
 
 static void
-nv04_graph_context_switch(struct drm_device *dev)
+nv04_graph_intr(struct nouveau_subdev *subdev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
-	int chid;
+	struct nv04_graph_priv *priv = (void *)subdev;
+	struct nv04_graph_chan *chan = NULL;
+	struct nouveau_namedb *namedb = NULL;
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x0f000000) >> 24;
+	u32 subc = (addr & 0x0000e000) >> 13;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
+	u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
+	u32 show = stat;
+	unsigned long flags;
 
-	nouveau_wait_for_idle(dev);
-
-	/* If previous context is valid, we need to save it */
-	nv04_graph_unload_context(dev);
-
-	/* Load context for next channel */
-	chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
-			    NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
-	chan = dev_priv->channels.ptr[chid];
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
 	if (chan)
-		nv04_graph_load_context(chan);
-}
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x0f000000) >> 24;
-		u32 subc = (addr & 0x0000e000) >> 13;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_NOTIFY) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_NOTIFY;
-			}
-		}
-
-		if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-			nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-			stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			nv04_graph_context_switch(dev);
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv04_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
+	if (stat & NV_PGRAPH_INTR_NOTIFY) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nouveau_namedb_get_vinst(namedb, inst);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_NOTIFY;
 		}
 	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv04_graph_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "");
+		nouveau_bitfield_print(nv04_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch %d/%d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 chid, subc, class, mthd, data);
+	}
+
+	nouveau_namedb_put(handle);
 }
 
-static void
-nv04_graph_destroy(struct drm_device *dev, int engine)
+static int
+nv04_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
 {
-	struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+	struct nv04_graph_priv *priv;
+	int ret;
 
-	nouveau_irq_unregister(dev, 12);
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv04_graph_create(struct drm_device *dev)
-{
-	struct nv04_graph_engine *pgraph;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv04_graph_destroy;
-	pgraph->base.init = nv04_graph_init;
-	pgraph->base.fini = nv04_graph_fini;
-	pgraph->base.context_new = nv04_graph_context_new;
-	pgraph->base.context_del = nv04_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv04_graph_isr);
-
-	/* dvd subpicture */
-	NVOBJ_CLASS(dev, 0x0038, GR);
-
-	/* m2mf */
-	NVOBJ_CLASS(dev, 0x0039, GR);
-
-	/* nv03 gdirect */
-	NVOBJ_CLASS(dev, 0x004b, GR);
-	NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 gdirect */
-	NVOBJ_CLASS(dev, 0x004a, GR);
-	NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 imageblit */
-	NVOBJ_CLASS(dev, 0x001f, GR);
-	NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src);
-	NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 imageblit */
-	NVOBJ_CLASS(dev, 0x005f, GR);
-	NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 iifc */
-	NVOBJ_CLASS(dev, 0x0060, GR);
-	NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf);
-	NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation);
-
-	/* nv05 iifc */
-	NVOBJ_CLASS(dev, 0x0064, GR);
-
-	/* nv01 ifc */
-	NVOBJ_CLASS(dev, 0x0021, GR);
-	NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 ifc */
-	NVOBJ_CLASS(dev, 0x0061, GR);
-	NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv05 ifc */
-	NVOBJ_CLASS(dev, 0x0065, GR);
-
-	/* nv03 sifc */
-	NVOBJ_CLASS(dev, 0x0036, GR);
-	NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 sifc */
-	NVOBJ_CLASS(dev, 0x0076, GR);
-	NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv05 sifc */
-	NVOBJ_CLASS(dev, 0x0066, GR);
-
-	/* nv03 sifm */
-	NVOBJ_CLASS(dev, 0x0037, GR);
-	NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation);
-
-	/* nv04 sifm */
-	NVOBJ_CLASS(dev, 0x0077, GR);
-	NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf);
-	NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation);
-
-	/* null */
-	NVOBJ_CLASS(dev, 0x0030, GR);
-
-	/* surf2d */
-	NVOBJ_CLASS(dev, 0x0042, GR);
-
-	/* rop */
-	NVOBJ_CLASS(dev, 0x0043, GR);
-
-	/* beta1 */
-	NVOBJ_CLASS(dev, 0x0012, GR);
-
-	/* beta4 */
-	NVOBJ_CLASS(dev, 0x0072, GR);
-
-	/* cliprect */
-	NVOBJ_CLASS(dev, 0x0019, GR);
-
-	/* nv01 pattern */
-	NVOBJ_CLASS(dev, 0x0018, GR);
-
-	/* nv04 pattern */
-	NVOBJ_CLASS(dev, 0x0044, GR);
-
-	/* swzsurf */
-	NVOBJ_CLASS(dev, 0x0052, GR);
-
-	/* surf3d */
-	NVOBJ_CLASS(dev, 0x0053, GR);
-	NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h);
-	NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v);
-
-	/* nv03 tex_tri */
-	NVOBJ_CLASS(dev, 0x0048, GR);
-	NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color);
-	NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta);
-
-	/* tex_tri */
-	NVOBJ_CLASS(dev, 0x0054, GR);
-
-	/* multitex_tri */
-	NVOBJ_CLASS(dev, 0x0055, GR);
-
-	/* nv01 chroma */
-	NVOBJ_CLASS(dev, 0x0017, GR);
-
-	/* nv04 chroma */
-	NVOBJ_CLASS(dev, 0x0057, GR);
-
-	/* surf_dst */
-	NVOBJ_CLASS(dev, 0x0058, GR);
-
-	/* surf_src */
-	NVOBJ_CLASS(dev, 0x0059, GR);
-
-	/* surf_color */
-	NVOBJ_CLASS(dev, 0x005a, GR);
-
-	/* surf_zeta */
-	NVOBJ_CLASS(dev, 0x005b, GR);
-
-	/* nv01 line */
-	NVOBJ_CLASS(dev, 0x001c, GR);
-	NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 line */
-	NVOBJ_CLASS(dev, 0x005c, GR);
-	NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 tri */
-	NVOBJ_CLASS(dev, 0x001d, GR);
-	NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 tri */
-	NVOBJ_CLASS(dev, 0x005d, GR);
-	NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 rect */
-	NVOBJ_CLASS(dev, 0x001e, GR);
-	NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 rect */
-	NVOBJ_CLASS(dev, 0x005e, GR);
-	NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation);
-
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv04_graph_intr;
+	nv_engine(priv)->cclass = &nv04_graph_cclass;
+	nv_engine(priv)->sclass = nv04_graph_sclass;
+	spin_lock_init(&priv->lock);
 	return 0;
 }
+
+static int
+nv04_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv04_graph_priv *priv = (void *)engine;
+	int ret;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* Enable PGRAPH interrupts */
+	nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
+	nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
+	/*1231C000 blob, 001 haiku*/
+	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
+	/*0x72111100 blob , 01 haiku*/
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
+	/*haiku same*/
+
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
+	/*haiku and blob 10d4*/
+
+	nv_wr32(priv, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+
+	/* These don't belong here, they're part of a per-channel context */
+	nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv04_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
index d006658..ce38196 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
@@ -22,27 +22,28 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
 
-struct nv10_graph_engine {
-	struct nouveau_exec_engine base;
-};
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+#include <engine/graph.h>
+
+#include "regs.h"
 
 struct pipe_state {
-	uint32_t pipe_0x0000[0x040/4];
-	uint32_t pipe_0x0040[0x010/4];
-	uint32_t pipe_0x0200[0x0c0/4];
-	uint32_t pipe_0x4400[0x080/4];
-	uint32_t pipe_0x6400[0x3b0/4];
-	uint32_t pipe_0x6800[0x2f0/4];
-	uint32_t pipe_0x6c00[0x030/4];
-	uint32_t pipe_0x7000[0x130/4];
-	uint32_t pipe_0x7400[0x0c0/4];
-	uint32_t pipe_0x7800[0x0c0/4];
+	u32 pipe_0x0000[0x040/4];
+	u32 pipe_0x0040[0x010/4];
+	u32 pipe_0x0200[0x0c0/4];
+	u32 pipe_0x4400[0x080/4];
+	u32 pipe_0x6400[0x3b0/4];
+	u32 pipe_0x6800[0x2f0/4];
+	u32 pipe_0x6c00[0x030/4];
+	u32 pipe_0x7000[0x130/4];
+	u32 pipe_0x7400[0x0c0/4];
+	u32 pipe_0x7800[0x0c0/4];
 };
 
 static int nv10_graph_ctx_regs[] = {
@@ -388,117 +389,322 @@
 	0x00400a04,
 };
 
-struct graph_state {
+struct nv10_graph_priv {
+	struct nouveau_graph base;
+	struct nv10_graph_chan *chan[32];
+	spinlock_t lock;
+};
+
+struct nv10_graph_chan {
+	struct nouveau_object base;
+	int chid;
 	int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
 	int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
 	struct pipe_state pipe_state;
-	uint32_t lma_window[4];
+	u32 lma_window[4];
 };
 
-#define PIPE_SAVE(dev, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
-	} while (0)
 
-#define PIPE_RESTORE(dev, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \
-	} while (0)
-
-static void nv10_graph_save_pipe(struct nouveau_channel *chan)
+static inline struct nv10_graph_priv *
+nv10_graph_priv(struct nv10_graph_chan *chan)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-
-	PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-	PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400);
-	PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800);
-	PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000);
-	PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400);
-	PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800);
-	PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040);
-	PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000);
+	return (void *)nv_object(chan)->engine;
 }
 
-static void nv10_graph_load_pipe(struct nouveau_channel *chan)
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+#define PIPE_SAVE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
+	} while (0)
+
+#define PIPE_RESTORE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+	} while (0)
+
+static struct nouveau_oclass
+nv10_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0056, &nv04_graph_ofuncs }, /* celcius */
+	{},
+};
+
+static struct nouveau_oclass
+nv15_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0096, &nv04_graph_ofuncs }, /* celcius */
+	{},
+};
+
+static int
+nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-	uint32_t xfmode0, xfmode1;
+	struct nv10_graph_chan *chan = (void *)object->parent;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+	u32 xfmode0, xfmode1;
+	u32 data = *(u32 *)args;
 	int i;
 
-	nouveau_wait_for_idle(dev);
-	/* XXX check haiku comments */
-	xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	chan->lma_window[(mthd - 0x1638) / 4] = data;
+
+	if (mthd != 0x1644)
+		return 0;
+
+	nv04_graph_idle(priv);
+
+	PIPE_SAVE(priv, pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+
+	PIPE_RESTORE(priv, chan->lma_window, 0x6790);
+
+	nv04_graph_idle(priv);
+
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
+
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
 	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
 	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
 	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
 	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
 
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
 
-	PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-	nouveau_wait_for_idle(dev);
+	nv04_graph_idle(priv);
 
-	/* restore XFMODE */
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-	PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400);
-	PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800);
-	PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000);
-	PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400);
-	PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800);
-	PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000);
-	PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040);
-	nouveau_wait_for_idle(dev);
+	PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+
+	PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv04_graph_idle(priv);
+
+	return 0;
 }
 
-static void nv10_graph_create_pipe(struct nouveau_channel *chan)
+static int
+nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-	uint32_t *fifo_pipe_state_addr;
+	struct nv10_graph_chan *chan = (void *)object->parent;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+
+	nv04_graph_idle(priv);
+
+	nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
+	nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
+	return 0;
+}
+
+static struct nouveau_omthds
+nv17_celcius_omthds[] = {
+	{ 0x1638, nv17_graph_mthd_lma_window },
+	{ 0x163c, nv17_graph_mthd_lma_window },
+	{ 0x1640, nv17_graph_mthd_lma_window },
+	{ 0x1644, nv17_graph_mthd_lma_window },
+	{ 0x1658, nv17_graph_mthd_lma_enable },
+	{}
+};
+
+static struct nouveau_oclass
+nv17_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv10_graph_chan *
+nv10_graph_channel(struct nv10_graph_priv *priv)
+{
+	struct nv10_graph_chan *chan = NULL;
+	if (nv_rd32(priv, 0x400144) & 0x00010000) {
+		int chid = nv_rd32(priv, 0x400148) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static void
+nv10_graph_save_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+	PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
+}
+
+static void
+nv10_graph_load_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 xfmode0, xfmode1;
+	int i;
+
+	nv04_graph_idle(priv);
+	/* XXX check haiku comments */
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+	nv04_graph_idle(priv);
+
+	/* restore XFMODE */
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+	PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
+	PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
+	nv04_graph_idle(priv);
+}
+
+static void
+nv10_graph_create_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe_state = &chan->pipe_state;
+	u32 *pipe_state_addr;
 	int i;
 #define PIPE_INIT(addr) \
 	do { \
-		fifo_pipe_state_addr = fifo_pipe_state->pipe_##addr; \
+		pipe_state_addr = pipe_state->pipe_##addr; \
 	} while (0)
 #define PIPE_INIT_END(addr) \
 	do { \
-		uint32_t *__end_addr = fifo_pipe_state->pipe_##addr + \
-				ARRAY_SIZE(fifo_pipe_state->pipe_##addr); \
-		if (fifo_pipe_state_addr != __end_addr) \
-			NV_ERROR(dev, "incomplete pipe init for 0x%x :  %p/%p\n", \
-				addr, fifo_pipe_state_addr, __end_addr); \
+		u32 *__end_addr = pipe_state->pipe_##addr + \
+				ARRAY_SIZE(pipe_state->pipe_##addr); \
+		if (pipe_state_addr != __end_addr) \
+			nv_error(priv, "incomplete pipe init for 0x%x :  %p/%p\n", \
+				addr, pipe_state_addr, __end_addr); \
 	} while (0)
-#define NV_WRITE_PIPE_INIT(value) *(fifo_pipe_state_addr++) = value
+#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
 
 	PIPE_INIT(0x0200);
 	for (i = 0; i < 48; i++)
@@ -634,34 +840,36 @@
 #undef NV_WRITE_PIPE_INIT
 }
 
-static int nv10_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) {
 		if (nv10_graph_ctx_regs[i] == reg)
 			return i;
 	}
-	NV_ERROR(dev, "unknow offset nv10_ctx_regs %d\n", reg);
+	nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
 	return -1;
 }
 
-static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) {
 		if (nv17_graph_ctx_regs[i] == reg)
 			return i;
 	}
-	NV_ERROR(dev, "unknow offset nv17_ctx_regs %d\n", reg);
+	nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
 	return -1;
 }
 
-static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
-				       uint32_t inst)
+static void
+nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst)
 {
-	struct drm_device *dev = chan->dev;
-	uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
-	uint32_t ctx_user, ctx_switch[5];
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+	u32 ctx_user, ctx_switch[5];
 	int i, subchan = -1;
 
 	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
@@ -671,7 +879,7 @@
 
 	/* Look for a celsius object */
 	for (i = 0; i < 8; i++) {
-		int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+		int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
 
 		if (class == 0x56 || class == 0x96 || class == 0x99) {
 			subchan = i;
@@ -683,168 +891,158 @@
 		return;
 
 	/* Save the current ctx object */
-	ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+	ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
 	for (i = 0; i < 5; i++)
-		ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+		ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
 
 	/* Save the FIFO state */
-	st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-	st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
-	st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
-	fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+	st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
+	st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
+	st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
+	fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
 
 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+		fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
 
 	/* Switch to the celsius subchannel */
 	for (i = 0; i < 5; i++)
-		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
-			nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
-	nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
+			nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
 
 	/* Inject NV10TCL_DMA_VTXBUF */
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
-		0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
-	nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
+		0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+	nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
 
 	/* Restore the FIFO state */
 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+		nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
 
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
 
 	/* Restore the current ctx object */
 	for (i = 0; i < 5; i++)
-		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+	nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
 static int
-nv10_graph_load_context(struct nouveau_channel *chan)
+nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	uint32_t tmp;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	u32 inst;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		nv_wr32(dev, nv10_graph_ctx_regs[i], pgraph_ctx->nv10[i]);
-	if (dev_priv->chipset >= 0x17) {
+		nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
+
+	if (nv_device(priv)->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			nv_wr32(dev, nv17_graph_ctx_regs[i],
-						pgraph_ctx->nv17[i]);
+			nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
 	}
 
 	nv10_graph_load_pipe(chan);
-	nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
-					  & 0xffff));
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, (tmp & 0xffffff) | chan->id << 24);
-	tmp = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, tmp & 0xcfffffff);
+	inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
+	nv10_graph_load_dma_vtxbuf(chan, chid, inst);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
 	return 0;
 }
 
 static int
-nv10_graph_unload_context(struct drm_device *dev)
+nv10_graph_unload_context(struct nv10_graph_chan *chan)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	struct graph_state *ctx;
-	uint32_t tmp;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
 	int i;
 
-	chan = nv10_graph_channel(dev);
-	if (!chan)
-		return 0;
-	ctx = chan->engctx[NVOBJ_ENGINE_GR];
-
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
+		chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
 
-	if (dev_priv->chipset >= 0x17) {
+	if (nv_device(priv)->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			ctx->nv17[i] = nv_rd32(dev, nv17_graph_ctx_regs[i]);
+			chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
 	}
 
 	nv10_graph_save_pipe(chan);
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
 	return 0;
 }
 
 static void
-nv10_graph_context_switch(struct drm_device *dev)
+nv10_graph_context_switch(struct nv10_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
+	struct nv10_graph_chan *prev = NULL;
+	struct nv10_graph_chan *next = NULL;
+	unsigned long flags;
 	int chid;
 
-	nouveau_wait_for_idle(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_graph_idle(priv);
 
 	/* If previous context is valid, we need to save it */
-	nv10_graph_unload_context(dev);
+	prev = nv10_graph_channel(priv);
+	if (prev)
+		nv10_graph_unload_context(prev);
 
-	/* Load context for next channel */
-	chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
-	chan = dev_priv->channels.ptr[chid];
-	if (chan && chan->engctx[NVOBJ_ENGINE_GR])
-		nv10_graph_load_context(chan);
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
+	next = priv->chan[chid];
+	if (next)
+		nv10_graph_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 #define NV_WRITE_CTX(reg, val) do { \
-	int offset = nv10_graph_ctx_regs_find_offset(dev, reg); \
+	int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \
 	if (offset > 0) \
-		pgraph_ctx->nv10[offset] = val; \
+		chan->nv10[offset] = val; \
 	} while (0)
 
 #define NV17_WRITE_CTX(reg, val) do { \
-	int offset = nv17_graph_ctx_regs_find_offset(dev, reg); \
+	int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \
 	if (offset > 0) \
-		pgraph_ctx->nv17[offset] = val; \
+		chan->nv17[offset] = val; \
 	} while (0)
 
-struct nouveau_channel *
-nv10_graph_channel(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int chid = 31;
-
-	if (nv_rd32(dev, NV10_PGRAPH_CTX_CONTROL) & 0x00010000)
-		chid = nv_rd32(dev, NV10_PGRAPH_CTX_USER) >> 24;
-
-	if (chid >= 31)
-		return NULL;
-
-	return dev_priv->channels.ptr[chid];
-}
-
 static int
-nv10_graph_context_new(struct nouveau_channel *chan, int engine)
+nv10_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx;
+	struct nouveau_fifo_chan *fifo = (void *)parent;
+	struct nv10_graph_priv *priv = (void *)engine;
+	struct nv10_graph_chan *chan;
+	unsigned long flags;
+	int ret;
 
-	NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
+	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
-	if (pgraph_ctx == NULL)
-		return -ENOMEM;
-	chan->engctx[engine] = pgraph_ctx;
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nouveau_object_destroy(&chan->base);
+		return 1;
+	}
 
 	NV_WRITE_CTX(0x00400e88, 0x08000000);
 	NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -853,212 +1051,91 @@
 	NV_WRITE_CTX(0x00400e14, 0x00001000);
 	NV_WRITE_CTX(0x00400e30, 0x00080008);
 	NV_WRITE_CTX(0x00400e34, 0x00080008);
-	if (dev_priv->chipset >= 0x17) {
+	if (nv_device(priv)->chipset >= 0x17) {
 		/* is it really needed ??? */
 		NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
-					nv_rd32(dev, NV10_PGRAPH_DEBUG_4));
-		NV17_WRITE_CTX(0x004006b0, nv_rd32(dev, 0x004006b0));
+					nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
+		NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
 		NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
 		NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
 		NV17_WRITE_CTX(0x00400ec0, 0x00000080);
 		NV17_WRITE_CTX(0x00400ed0, 0x00000080);
 	}
-	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->id << 24);
+	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
 
 	nv10_graph_create_pipe(chan);
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
 	return 0;
 }
 
 static void
-nv10_graph_context_del(struct nouveau_channel *chan, int engine)
+nv10_graph_context_dtor(struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[engine];
+	struct nv10_graph_priv *priv = (void *)object->engine;
+	struct nv10_graph_chan *chan = (void *)object;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Unload the context if it's the currently active one */
-	if (nv10_graph_channel(dev) == chan)
-		nv10_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	chan->engctx[engine] = NULL;
-	kfree(pgraph_ctx);
+	nouveau_object_destroy(&chan->base);
 }
 
+static int
+nv10_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv10_graph_priv *priv = (void *)object->engine;
+	struct nv10_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv10_graph_channel(priv) == chan)
+		nv10_graph_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nouveau_object_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv10_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_graph_context_ctor,
+		.dtor = nv10_graph_context_dtor,
+		.init = nouveau_object_init,
+		.fini = nv10_graph_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 static void
-nv10_graph_set_tile_region(struct drm_device *dev, int i)
+nv10_graph_tile_prog(struct nouveau_engine *engine, int i)
 {
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-	nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv10_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
+
+	pfifo->start(pfifo, &flags);
 }
 
-static int
-nv10_graph_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 tmp;
-	int i;
-
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
-
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	/* nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0x55DE0830 |
-				      (1<<29) |
-				      (1<<31));
-	if (dev_priv->chipset >= 0x17) {
-		nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000);
-		nv_wr32(dev, 0x400a10, 0x3ff3fb6);
-		nv_wr32(dev, 0x400838, 0x2f8684);
-		nv_wr32(dev, 0x40083c, 0x115f3f);
-		nv_wr32(dev, 0x004006b0, 0x40000020);
-	} else
-		nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv10_graph_set_tile_region(dev, i);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
-
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
-
-	return 0;
-}
-
-static int
-nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv10_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
-
-static int
-nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
-{
-	struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct drm_device *dev = chan->dev;
-	struct pipe_state *pipe = &ctx->pipe_state;
-	uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
-	uint32_t xfmode0, xfmode1;
-	int i;
-
-	ctx->lma_window[(mthd - 0x1638) / 4] = data;
-
-	if (mthd != 0x1644)
-		return 0;
-
-	nouveau_wait_for_idle(dev);
-
-	PIPE_SAVE(dev, pipe_0x0040, 0x0040);
-	PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-
-	PIPE_RESTORE(dev, ctx->lma_window, 0x6790);
-
-	nouveau_wait_for_idle(dev);
-
-	xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-
-	PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(dev, pipe_0x64c0, 0x64c0);
-	PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0);
-	PIPE_SAVE(dev, pipe_0x6a80, 0x6a80);
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
-	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
-	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-	PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-
-	nouveau_wait_for_idle(dev);
-
-	PIPE_RESTORE(dev, pipe_0x0040, 0x0040);
-
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-
-	PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0);
-	PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0);
-	PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80);
-	PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nouveau_wait_for_idle(dev);
-
-	return 0;
-}
-
-static int
-nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
-{
-	struct drm_device *dev = chan->dev;
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4,
-		nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8);
-	nv_wr32(dev, 0x004006b0,
-		nv_rd32(dev, 0x004006b0) | 0x8 << 24);
-
-	return 0;
-}
-
-struct nouveau_bitfield nv10_graph_intr[] = {
+struct nouveau_bitfield nv10_graph_intr_name[] = {
 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
 	{ NV_PGRAPH_INTR_ERROR,  "ERROR"  },
 	{}
@@ -1073,115 +1150,165 @@
 };
 
 static void
-nv10_graph_isr(struct drm_device *dev)
+nv10_graph_intr(struct nouveau_subdev *subdev)
 {
-	u32 stat;
+	struct nv10_graph_priv *priv = (void *)subdev;
+	struct nv10_graph_chan *chan = NULL;
+	struct nouveau_namedb *namedb = NULL;
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 show = stat;
+	unsigned long flags;
 
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x01f00000) >> 20;
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
-		u32 show = stat;
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
+	if (chan)
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			}
-		}
-
-		if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-			nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-			stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			nv10_graph_context_switch(dev);
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nouveau_namedb_get_class(namedb, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
 		}
 	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv10_graph_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch %d/%d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 chid, subc, class, mthd, data);
+	}
+
+	nouveau_namedb_put(handle);
+}
+
+static int
+nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nv10_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv10_graph_intr;
+	nv_engine(priv)->cclass = &nv10_graph_cclass;
+
+	if (nv_device(priv)->chipset <= 0x10)
+		nv_engine(priv)->sclass = nv10_graph_sclass;
+	else
+	if (nv_device(priv)->chipset <  0x17 ||
+	    nv_device(priv)->chipset == 0x1a)
+		nv_engine(priv)->sclass = nv15_graph_sclass;
+	else
+		nv_engine(priv)->sclass = nv17_graph_sclass;
+
+	nv_engine(priv)->tile_prog = nv10_graph_tile_prog;
+	spin_lock_init(&priv->lock);
+	return 0;
 }
 
 static void
-nv10_graph_destroy(struct drm_device *dev, int engine)
+nv10_graph_dtor(struct nouveau_object *object)
 {
-	struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-	kfree(pgraph);
+	struct nv10_graph_priv *priv = (void *)object;
+	nouveau_graph_destroy(&priv->base);
 }
 
-int
-nv10_graph_create(struct drm_device *dev)
+static int
+nv10_graph_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv10_graph_engine *pgraph;
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	struct nv10_graph_priv *priv = (void *)engine;
+	int ret, i;
 
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pgraph->base.destroy = nv10_graph_destroy;
-	pgraph->base.init = nv10_graph_init;
-	pgraph->base.fini = nv10_graph_fini;
-	pgraph->base.context_new = nv10_graph_context_new;
-	pgraph->base.context_del = nv10_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-	pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv10_graph_isr);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	/* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
 
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-	NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-	NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-	NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-	/* celcius */
-	if (dev_priv->chipset <= 0x10) {
-		NVOBJ_CLASS(dev, 0x0056, GR);
-	} else
-	if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-		NVOBJ_CLASS(dev, 0x0096, GR);
+	if (nv_device(priv)->chipset >= 0x17) {
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+		nv_wr32(priv, 0x400a10, 0x03ff3fb6);
+		nv_wr32(priv, 0x400838, 0x002f8684);
+		nv_wr32(priv, 0x40083c, 0x00115f3f);
+		nv_wr32(priv, 0x4006b0, 0x40000020);
 	} else {
-		NVOBJ_CLASS(dev, 0x0099, GR);
-		NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
 	}
 
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
+
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
 	return 0;
 }
+
+static int
+nv10_graph_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv10_graph_priv *priv = (void *)object;
+	return nouveau_graph_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv10_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_graph_ctor,
+		.dtor = nv10_graph_dtor,
+		.init = nv10_graph_init,
+		.fini = nv10_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
index 0d874b8b..61faef9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
@@ -1,836 +1,378 @@
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <nouveau_drm.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+#include <core/enum.h>
 
-/*
- * NV20
- * -----
- * There are 3 families :
- * NV20 is 0x10de:0x020*
- * NV25/28 is 0x10de:0x025* / 0x10de:0x028*
- * NV2A is 0x10de:0x02A0
- *
- * NV30
- * -----
- * There are 3 families :
- * NV30/31 is 0x10de:0x030* / 0x10de:0x031*
- * NV34 is 0x10de:0x032*
- * NV35/36 is 0x10de:0x033* / 0x10de:0x034*
- *
- * Not seen in the wild, no dumps (probably NV35) :
- * NV37 is 0x10de:0x00fc, 0x10de:0x00fd
- * NV38 is 0x10de:0x0333, 0x10de:0x00fe
- *
- */
+#include <subdev/timer.h>
+#include <subdev/fb.h>
 
-struct nv20_graph_engine {
-	struct nouveau_exec_engine base;
-	struct nouveau_gpuobj *ctxtab;
-	void (*grctx_init)(struct nouveau_gpuobj *);
-	u32 grctx_size;
-	u32 grctx_user;
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv20_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
+	{ 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */
+	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{},
 };
 
-#define NV20_GRCTX_SIZE (3580*4)
-#define NV25_GRCTX_SIZE (3529*4)
-#define NV2A_GRCTX_SIZE (3500*4)
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
 
-#define NV30_31_GRCTX_SIZE (24392)
-#define NV34_GRCTX_SIZE    (18140)
-#define NV35_36_GRCTX_SIZE (22396)
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
+static int
+nv20_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct nouveau_channel *chan;
-	struct nouveau_gpuobj *grctx;
-	u32 tmp;
+	struct nv20_graph_chan *chan;
+	int ret, i;
 
-	chan = nv10_graph_channel(dev);
-	if (!chan)
-		return 0;
-	grctx = chan->engctx[NVOBJ_ENGINE_GR];
-
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->addr >> 4);
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-		     NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-	return 0;
-}
-
-static void
-nv20_graph_rdi(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i, writecount = 32;
-	uint32_t rdi_index = 0x2c80000;
-
-	if (dev_priv->chipset == 0x20) {
-		rdi_index = 0x3d0000;
-		writecount = 15;
-	}
-
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
-	for (i = 0; i < writecount; i++)
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
-	nouveau_wait_for_idle(dev);
-}
-
-static void
-nv20_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x033c, 0xffff0000);
-	nv_wo32(ctx, 0x03a0, 0x0fff0000);
-	nv_wo32(ctx, 0x03a4, 0x0fff0000);
-	nv_wo32(ctx, 0x047c, 0x00000101);
-	nv_wo32(ctx, 0x0490, 0x00000111);
-	nv_wo32(ctx, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
-	nv_wo32(ctx, 0x05fc, 0x00000001);
-	nv_wo32(ctx, 0x0604, 0x00004000);
-	nv_wo32(ctx, 0x0610, 0x00000001);
-	nv_wo32(ctx, 0x0618, 0x00040000);
-	nv_wo32(ctx, 0x061c, 0x00010000);
-	for (i = 0x1c1c; i <= 0x248c; i += 16) {
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x281c, 0x3f800000);
-	nv_wo32(ctx, 0x2830, 0x3f800000);
-	nv_wo32(ctx, 0x285c, 0x40000000);
-	nv_wo32(ctx, 0x2860, 0x3f800000);
-	nv_wo32(ctx, 0x2864, 0x3f000000);
-	nv_wo32(ctx, 0x286c, 0x40000000);
-	nv_wo32(ctx, 0x2870, 0x3f800000);
-	nv_wo32(ctx, 0x2878, 0xbf800000);
-	nv_wo32(ctx, 0x2880, 0xbf800000);
-	nv_wo32(ctx, 0x34a4, 0x000fe000);
-	nv_wo32(ctx, 0x3530, 0x000003f8);
-	nv_wo32(ctx, 0x3540, 0x002fe000);
-	for (i = 0x355c; i <= 0x3578; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv25_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x035c, 0xffff0000);
-	nv_wo32(ctx, 0x03c0, 0x0fff0000);
-	nv_wo32(ctx, 0x03c4, 0x0fff0000);
-	nv_wo32(ctx, 0x049c, 0x00000101);
-	nv_wo32(ctx, 0x04b0, 0x00000111);
-	nv_wo32(ctx, 0x04c8, 0x00000080);
-	nv_wo32(ctx, 0x04cc, 0xffff0000);
-	nv_wo32(ctx, 0x04d0, 0x00000001);
-	nv_wo32(ctx, 0x04e4, 0x44400000);
-	nv_wo32(ctx, 0x04fc, 0x4b800000);
-	for (i = 0x0510; i <= 0x051c; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x0530; i <= 0x053c; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x0548; i <= 0x0554; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0558; i <= 0x0564; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x0568; i <= 0x0574; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x0598; i <= 0x05d4; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05e0, 0x4b7fffff);
-	nv_wo32(ctx, 0x0620, 0x00000080);
-	nv_wo32(ctx, 0x0624, 0x30201000);
-	nv_wo32(ctx, 0x0628, 0x70605040);
-	nv_wo32(ctx, 0x062c, 0xb0a09080);
-	nv_wo32(ctx, 0x0630, 0xf0e0d0c0);
-	nv_wo32(ctx, 0x0664, 0x00000001);
-	nv_wo32(ctx, 0x066c, 0x00004000);
-	nv_wo32(ctx, 0x0678, 0x00000001);
-	nv_wo32(ctx, 0x0680, 0x00040000);
-	nv_wo32(ctx, 0x0684, 0x00010000);
-	for (i = 0x1b04; i <= 0x2374; i += 16) {
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x2704, 0x3f800000);
-	nv_wo32(ctx, 0x2718, 0x3f800000);
-	nv_wo32(ctx, 0x2744, 0x40000000);
-	nv_wo32(ctx, 0x2748, 0x3f800000);
-	nv_wo32(ctx, 0x274c, 0x3f000000);
-	nv_wo32(ctx, 0x2754, 0x40000000);
-	nv_wo32(ctx, 0x2758, 0x3f800000);
-	nv_wo32(ctx, 0x2760, 0xbf800000);
-	nv_wo32(ctx, 0x2768, 0xbf800000);
-	nv_wo32(ctx, 0x308c, 0x000fe000);
-	nv_wo32(ctx, 0x3108, 0x000003f8);
-	nv_wo32(ctx, 0x3468, 0x002fe000);
-	for (i = 0x3484; i <= 0x34a0; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x033c, 0xffff0000);
-	nv_wo32(ctx, 0x03a0, 0x0fff0000);
-	nv_wo32(ctx, 0x03a4, 0x0fff0000);
-	nv_wo32(ctx, 0x047c, 0x00000101);
-	nv_wo32(ctx, 0x0490, 0x00000111);
-	nv_wo32(ctx, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
-	nv_wo32(ctx, 0x05fc, 0x00000001);
-	nv_wo32(ctx, 0x0604, 0x00004000);
-	nv_wo32(ctx, 0x0610, 0x00000001);
-	nv_wo32(ctx, 0x0618, 0x00040000);
-	nv_wo32(ctx, 0x061c, 0x00010000);
-	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x269c, 0x3f800000);
-	nv_wo32(ctx, 0x26b0, 0x3f800000);
-	nv_wo32(ctx, 0x26dc, 0x40000000);
-	nv_wo32(ctx, 0x26e0, 0x3f800000);
-	nv_wo32(ctx, 0x26e4, 0x3f000000);
-	nv_wo32(ctx, 0x26ec, 0x40000000);
-	nv_wo32(ctx, 0x26f0, 0x3f800000);
-	nv_wo32(ctx, 0x26f8, 0xbf800000);
-	nv_wo32(ctx, 0x2700, 0xbf800000);
-	nv_wo32(ctx, 0x3024, 0x000fe000);
-	nv_wo32(ctx, 0x30a0, 0x000003f8);
-	nv_wo32(ctx, 0x33fc, 0x002fe000);
-	for (i = 0x341c; i <= 0x3438; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x0410, 0x00000101);
-	nv_wo32(ctx, 0x0424, 0x00000111);
-	nv_wo32(ctx, 0x0428, 0x00000060);
-	nv_wo32(ctx, 0x0444, 0x00000080);
-	nv_wo32(ctx, 0x0448, 0xffff0000);
-	nv_wo32(ctx, 0x044c, 0x00000001);
-	nv_wo32(ctx, 0x0460, 0x44400000);
-	nv_wo32(ctx, 0x048c, 0xffff0000);
-	for (i = 0x04e0; i < 0x04e8; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04ec, 0x00011100);
-	for (i = 0x0508; i < 0x0548; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x0550, 0x4b7fffff);
-	nv_wo32(ctx, 0x058c, 0x00000080);
-	nv_wo32(ctx, 0x0590, 0x30201000);
-	nv_wo32(ctx, 0x0594, 0x70605040);
-	nv_wo32(ctx, 0x0598, 0xb8a89888);
-	nv_wo32(ctx, 0x059c, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05b0, 0xb0000000);
-	for (i = 0x0600; i < 0x0640; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0640; i < 0x0680; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06c0; i < 0x0700; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x0700; i < 0x0740; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0740; i < 0x0780; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x085c, 0x00040000);
-	nv_wo32(ctx, 0x0860, 0x00010000);
-	for (i = 0x0864; i < 0x0874; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 1, 0x0436086c);
-		nv_wo32(ctx, i + 2, 0x000c001b);
-	}
-	for (i = 0x30b8; i < 0x30c8; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x344c, 0x3f800000);
-	nv_wo32(ctx, 0x3808, 0x3f800000);
-	nv_wo32(ctx, 0x381c, 0x3f800000);
-	nv_wo32(ctx, 0x3848, 0x40000000);
-	nv_wo32(ctx, 0x384c, 0x3f800000);
-	nv_wo32(ctx, 0x3850, 0x3f000000);
-	nv_wo32(ctx, 0x3858, 0x40000000);
-	nv_wo32(ctx, 0x385c, 0x3f800000);
-	nv_wo32(ctx, 0x3864, 0xbf800000);
-	nv_wo32(ctx, 0x386c, 0xbf800000);
-}
-
-static void
-nv34_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x040c, 0x01000101);
-	nv_wo32(ctx, 0x0420, 0x00000111);
-	nv_wo32(ctx, 0x0424, 0x00000060);
-	nv_wo32(ctx, 0x0440, 0x00000080);
-	nv_wo32(ctx, 0x0444, 0xffff0000);
-	nv_wo32(ctx, 0x0448, 0x00000001);
-	nv_wo32(ctx, 0x045c, 0x44400000);
-	nv_wo32(ctx, 0x0480, 0xffff0000);
-	for (i = 0x04d4; i < 0x04dc; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04e0, 0x00011100);
-	for (i = 0x04fc; i < 0x053c; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x0544, 0x4b7fffff);
-	nv_wo32(ctx, 0x057c, 0x00000080);
-	nv_wo32(ctx, 0x0580, 0x30201000);
-	nv_wo32(ctx, 0x0584, 0x70605040);
-	nv_wo32(ctx, 0x0588, 0xb8a89888);
-	nv_wo32(ctx, 0x058c, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05a0, 0xb0000000);
-	for (i = 0x05f0; i < 0x0630; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0630; i < 0x0670; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06b0; i < 0x06f0; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x06f0; i < 0x0730; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0730; i < 0x0770; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x0850, 0x00040000);
-	nv_wo32(ctx, 0x0854, 0x00010000);
-	for (i = 0x0858; i < 0x0868; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x15ac; i <= 0x271c ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 1, 0x0436086c);
-		nv_wo32(ctx, i + 2, 0x000c001b);
-	}
-	for (i = 0x274c; i < 0x275c; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x2ae0, 0x3f800000);
-	nv_wo32(ctx, 0x2e9c, 0x3f800000);
-	nv_wo32(ctx, 0x2eb0, 0x3f800000);
-	nv_wo32(ctx, 0x2edc, 0x40000000);
-	nv_wo32(ctx, 0x2ee0, 0x3f800000);
-	nv_wo32(ctx, 0x2ee4, 0x3f000000);
-	nv_wo32(ctx, 0x2eec, 0x40000000);
-	nv_wo32(ctx, 0x2ef0, 0x3f800000);
-	nv_wo32(ctx, 0x2ef8, 0xbf800000);
-	nv_wo32(ctx, 0x2f00, 0xbf800000);
-}
-
-static void
-nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x040c, 0x00000101);
-	nv_wo32(ctx, 0x0420, 0x00000111);
-	nv_wo32(ctx, 0x0424, 0x00000060);
-	nv_wo32(ctx, 0x0440, 0x00000080);
-	nv_wo32(ctx, 0x0444, 0xffff0000);
-	nv_wo32(ctx, 0x0448, 0x00000001);
-	nv_wo32(ctx, 0x045c, 0x44400000);
-	nv_wo32(ctx, 0x0488, 0xffff0000);
-	for (i = 0x04dc; i < 0x04e4; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04e8, 0x00011100);
-	for (i = 0x0504; i < 0x0544; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x054c, 0x4b7fffff);
-	nv_wo32(ctx, 0x0588, 0x00000080);
-	nv_wo32(ctx, 0x058c, 0x30201000);
-	nv_wo32(ctx, 0x0590, 0x70605040);
-	nv_wo32(ctx, 0x0594, 0xb8a89888);
-	nv_wo32(ctx, 0x0598, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05ac, 0xb0000000);
-	for (i = 0x0604; i < 0x0644; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0644; i < 0x0684; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06c4; i < 0x0704; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x0704; i < 0x0744; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0744; i < 0x0784; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x0860, 0x00040000);
-	nv_wo32(ctx, 0x0864, 0x00010000);
-	for (i = 0x0868; i < 0x0878; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 4, 0x0436086c);
-		nv_wo32(ctx, i + 8, 0x000c001b);
-	}
-	for (i = 0x30bc; i < 0x30cc; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x3450, 0x3f800000);
-	nv_wo32(ctx, 0x380c, 0x3f800000);
-	nv_wo32(ctx, 0x3820, 0x3f800000);
-	nv_wo32(ctx, 0x384c, 0x40000000);
-	nv_wo32(ctx, 0x3850, 0x3f800000);
-	nv_wo32(ctx, 0x3854, 0x3f000000);
-	nv_wo32(ctx, 0x385c, 0x40000000);
-	nv_wo32(ctx, 0x3860, 0x3f800000);
-	nv_wo32(ctx, 0x3868, 0xbf800000);
-	nv_wo32(ctx, 0x3870, 0xbf800000);
-}
-
-int
-nv20_graph_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct nouveau_gpuobj *grctx = NULL;
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &grctx);
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC,
+					   &chan);
+	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
 
-	/* Initialise default context values */
-	pgraph->grctx_init(grctx);
+	chan->chid = nouveau_fifo_chan(parent)->chid;
 
-	/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-	/* CTX_USER */
-	nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1c1c; i <= 0x248c; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x281c, 0x3f800000);
+	nv_wo32(chan, 0x2830, 0x3f800000);
+	nv_wo32(chan, 0x285c, 0x40000000);
+	nv_wo32(chan, 0x2860, 0x3f800000);
+	nv_wo32(chan, 0x2864, 0x3f000000);
+	nv_wo32(chan, 0x286c, 0x40000000);
+	nv_wo32(chan, 0x2870, 0x3f800000);
+	nv_wo32(chan, 0x2878, 0xbf800000);
+	nv_wo32(chan, 0x2880, 0xbf800000);
+	nv_wo32(chan, 0x34a4, 0x000fe000);
+	nv_wo32(chan, 0x3530, 0x000003f8);
+	nv_wo32(chan, 0x3540, 0x002fe000);
+	for (i = 0x355c; i <= 0x3578; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
 
-	nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->addr >> 4);
-	chan->engctx[engine] = grctx;
+int
+nv20_graph_context_init(struct nouveau_object *object)
+{
+	struct nv20_graph_priv *priv = (void *)object->engine;
+	struct nv20_graph_chan *chan = (void *)object;
+	int ret;
+
+	ret = nouveau_graph_context_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+int
+nv20_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv20_graph_priv *priv = (void *)object->engine;
+	struct nv20_graph_chan *chan = (void *)object;
+	int chid = -1;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+	if (nv_rd32(priv, 0x400144) & 0x00010000)
+		chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
+	if (chan->chid == chid) {
+		nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
+		nv_wr32(priv, 0x400788, 0x00000002);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+		nv_wr32(priv, 0x400144, 0x10000000);
+		nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
+	}
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
+	return nouveau_graph_context_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv20_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x20),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv20_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
+{
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv20_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
+
+	if (nv_device(engine)->card_type == NV_20) {
+		nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
+	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+void
+nv20_graph_intr(struct nouveau_subdev *subdev)
+{
+	struct nv20_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 inst = nv_ro32(priv->ctxtab, (chid * 4)) << 4;
+	u32 show = stat;
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nouveau_engctx_lookup_class(engine, inst, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nouveau_engctx_handle_put(handle);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_info(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			chid, subc, class, mthd, data);
+	}
+}
+
+static int
+nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv20_graph_cclass;
+	nv_engine(priv)->sclass = nv20_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
 	return 0;
 }
 
 void
-nv20_graph_context_del(struct nouveau_channel *chan, int engine)
+nv20_graph_dtor(struct nouveau_object *object)
 {
-	struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct nouveau_gpuobj *grctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-	/* Unload the context if it's the currently active one */
-	if (nv10_graph_channel(dev) == chan)
-		nv20_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
-
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-static void
-nv20_graph_set_tile_region(struct drm_device *dev, int i)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-
-	nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit);
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch);
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr);
-
-	if (dev_priv->card_type == NV_20) {
-		nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp);
-	}
+	struct nv20_graph_priv *priv = (void *)object;
+	nouveau_gpuobj_ref(NULL, &priv->ctxtab);
+	nouveau_graph_destroy(&priv->base);
 }
 
 int
-nv20_graph_init(struct drm_device *dev, int engine)
+nv20_graph_init(struct nouveau_object *object)
 {
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t tmp, vramsz;
-	int i;
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv20_graph_priv *priv = (void *)engine;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	u32 tmp, vramsz;
+	int ret, i;
 
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4);
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
 
-	nv20_graph_rdi(dev);
+	if (nv_device(priv)->chipset == 0x20) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
+		for (i = 0; i < 15; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	} else {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
+		for (i = 0; i < 32; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	}
 
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
-	nv_wr32(dev, 0x40009C           , 0x00000040);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+	nv_wr32(priv, 0x40009C           , 0x00000040);
 
-	if (dev_priv->chipset >= 0x25) {
-		nv_wr32(dev, 0x400890, 0x00a8cfff);
-		nv_wr32(dev, 0x400610, 0x304B1FB6);
-		nv_wr32(dev, 0x400B80, 0x1cbd3883);
-		nv_wr32(dev, 0x400B84, 0x44000000);
-		nv_wr32(dev, 0x400098, 0x40000080);
-		nv_wr32(dev, 0x400B88, 0x000000ff);
+	if (nv_device(priv)->chipset >= 0x25) {
+		nv_wr32(priv, 0x400890, 0x00a8cfff);
+		nv_wr32(priv, 0x400610, 0x304B1FB6);
+		nv_wr32(priv, 0x400B80, 0x1cbd3883);
+		nv_wr32(priv, 0x400B84, 0x44000000);
+		nv_wr32(priv, 0x400098, 0x40000080);
+		nv_wr32(priv, 0x400B88, 0x000000ff);
 
 	} else {
-		nv_wr32(dev, 0x400880, 0x0008c7df);
-		nv_wr32(dev, 0x400094, 0x00000005);
-		nv_wr32(dev, 0x400B80, 0x45eae20e);
-		nv_wr32(dev, 0x400B84, 0x24000000);
-		nv_wr32(dev, 0x400098, 0x00000040);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
+		nv_wr32(priv, 0x400880, 0x0008c7df);
+		nv_wr32(priv, 0x400094, 0x00000005);
+		nv_wr32(priv, 0x400B80, 0x45eae20e);
+		nv_wr32(priv, 0x400B84, 0x24000000);
+		nv_wr32(priv, 0x400098, 0x00000040);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
 	}
 
 	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv20_graph_set_tile_region(dev, i);
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
 
-	nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324));
+	nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
 
-	tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) & 0x0007ff00;
-	nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
-	tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) | 0x00020100;
-	nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
 
 	/* begin RAM config */
-	vramsz = pci_resource_len(dev->pdev, 0) - 1;
-	nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG1));
-	nv_wr32(dev, 0x400820, 0);
-	nv_wr32(dev, 0x400824, 0);
-	nv_wr32(dev, 0x400864, vramsz - 1);
-	nv_wr32(dev, 0x400868, vramsz - 1);
+	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
+	nv_wr32(priv, 0x400820, 0);
+	nv_wr32(priv, 0x400824, 0);
+	nv_wr32(priv, 0x400864, vramsz - 1);
+	nv_wr32(priv, 0x400868, vramsz - 1);
 
 	/* interesting.. the below overwrites some of the tile setup above.. */
-	nv_wr32(dev, 0x400B20, 0x00000000);
-	nv_wr32(dev, 0x400B04, 0xFFFFFFFF);
+	nv_wr32(priv, 0x400B20, 0x00000000);
+	nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
-
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
 	return 0;
 }
 
-int
-nv30_graph_init(struct drm_device *dev, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i;
-
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
-
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4);
-
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(dev, 0x400890, 0x01b463ff);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
-	nv_wr32(dev, 0x400B80, 0x1003d888);
-	nv_wr32(dev, 0x400B84, 0x0c000000);
-	nv_wr32(dev, 0x400098, 0x00000000);
-	nv_wr32(dev, 0x40009C, 0x0005ad00);
-	nv_wr32(dev, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
-	nv_wr32(dev, 0x4000a0, 0x00000000);
-	nv_wr32(dev, 0x4000a4, 0x00000008);
-	nv_wr32(dev, 0x4008a8, 0xb784a400);
-	nv_wr32(dev, 0x400ba0, 0x002f8685);
-	nv_wr32(dev, 0x400ba4, 0x00231f3f);
-	nv_wr32(dev, 0x4008a4, 0x40000020);
-
-	if (dev_priv->chipset == 0x34) {
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00200201);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000008);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000032);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000002);
-	}
-
-	nv_wr32(dev, 0x4000c0, 0x00000016);
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv20_graph_set_tile_region(dev, i);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
-	nv_wr32(dev, 0x0040075c             , 0x00000001);
-
-	/* begin RAM config */
-	/* vramsz = pci_resource_len(dev->pdev, 0) - 1; */
-	nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-	if (dev_priv->chipset != 0x34) {
-		nv_wr32(dev, 0x400750, 0x00EA0000);
-		nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x400750, 0x00EA0004);
-		nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG1));
-	}
-
-	return 0;
-}
-
-int
-nv20_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv20_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
-
-static void
-nv20_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x01f00000) >> 20;
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			}
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
-		}
-	}
-}
-
-static void
-nv20_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-	nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv20_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv20_graph_engine *pgraph;
-	int ret;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv20_graph_destroy;
-	pgraph->base.fini = nv20_graph_fini;
-	pgraph->base.context_new = nv20_graph_context_new;
-	pgraph->base.context_del = nv20_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-	pgraph->base.set_tile_region = nv20_graph_set_tile_region;
-
-	pgraph->grctx_user = 0x0028;
-	if (dev_priv->card_type == NV_20) {
-		pgraph->base.init = nv20_graph_init;
-		switch (dev_priv->chipset) {
-		case 0x20:
-			pgraph->grctx_init = nv20_graph_context_init;
-			pgraph->grctx_size = NV20_GRCTX_SIZE;
-			pgraph->grctx_user = 0x0000;
-			break;
-		case 0x25:
-		case 0x28:
-			pgraph->grctx_init = nv25_graph_context_init;
-			pgraph->grctx_size = NV25_GRCTX_SIZE;
-			break;
-		case 0x2a:
-			pgraph->grctx_init = nv2a_graph_context_init;
-			pgraph->grctx_size = NV2A_GRCTX_SIZE;
-			pgraph->grctx_user = 0x0000;
-			break;
-		default:
-			NV_ERROR(dev, "PGRAPH: unknown chipset\n");
-			kfree(pgraph);
-			return 0;
-		}
-	} else {
-		pgraph->base.init = nv30_graph_init;
-		switch (dev_priv->chipset) {
-		case 0x30:
-		case 0x31:
-			pgraph->grctx_init = nv30_31_graph_context_init;
-			pgraph->grctx_size = NV30_31_GRCTX_SIZE;
-			break;
-		case 0x34:
-			pgraph->grctx_init = nv34_graph_context_init;
-			pgraph->grctx_size = NV34_GRCTX_SIZE;
-			break;
-		case 0x35:
-		case 0x36:
-			pgraph->grctx_init = nv35_36_graph_context_init;
-			pgraph->grctx_size = NV35_36_GRCTX_SIZE;
-			break;
-		default:
-			NV_ERROR(dev, "PGRAPH: unknown chipset\n");
-			kfree(pgraph);
-			return 0;
-		}
-	}
-
-	/* Create Context Pointer Table */
-	ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
-				 &pgraph->ctxtab);
-	if (ret) {
-		kfree(pgraph);
-		return ret;
-	}
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv20_graph_isr);
-
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	if (dev_priv->card_type == NV_20) {
-		NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
-		NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
-		/* kelvin */
-		if (dev_priv->chipset < 0x25)
-			NVOBJ_CLASS(dev, 0x0097, GR);
-		else
-			NVOBJ_CLASS(dev, 0x0597, GR);
-	} else {
-		NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
-		NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
-		NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
-		NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
-		/* rankine */
-		if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0397, GR);
-		else
-		if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0697, GR);
-		else
-		if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0497, GR);
-	}
-
-	return 0;
-}
+struct nouveau_oclass
+nv20_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x20),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv20_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
new file mode 100644
index 0000000..2bea731
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
@@ -0,0 +1,31 @@
+#ifndef __NV20_GRAPH_H__
+#define __NV20_GRAPH_H__
+
+#include <core/enum.h>
+
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+struct nv20_graph_priv {
+	struct nouveau_graph base;
+	struct nouveau_gpuobj *ctxtab;
+};
+
+struct nv20_graph_chan {
+	struct nouveau_graph_chan base;
+	int chid;
+};
+
+extern struct nouveau_oclass nv25_graph_sclass[];
+int  nv20_graph_context_init(struct nouveau_object *);
+int  nv20_graph_context_fini(struct nouveau_object *, bool);
+
+void nv20_graph_tile_prog(struct nouveau_engine *, int);
+void nv20_graph_intr(struct nouveau_subdev *);
+
+void nv20_graph_dtor(struct nouveau_object *);
+int  nv20_graph_init(struct nouveau_object *);
+
+int  nv30_graph_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
new file mode 100644
index 0000000..b2b650d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
@@ -0,0 +1,167 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nouveau_oclass
+nv25_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
+	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv25_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x035c, 0xffff0000);
+	nv_wo32(chan, 0x03c0, 0x0fff0000);
+	nv_wo32(chan, 0x03c4, 0x0fff0000);
+	nv_wo32(chan, 0x049c, 0x00000101);
+	nv_wo32(chan, 0x04b0, 0x00000111);
+	nv_wo32(chan, 0x04c8, 0x00000080);
+	nv_wo32(chan, 0x04cc, 0xffff0000);
+	nv_wo32(chan, 0x04d0, 0x00000001);
+	nv_wo32(chan, 0x04e4, 0x44400000);
+	nv_wo32(chan, 0x04fc, 0x4b800000);
+	for (i = 0x0510; i <= 0x051c; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x0530; i <= 0x053c; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x0548; i <= 0x0554; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0558; i <= 0x0564; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x0568; i <= 0x0574; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x0598; i <= 0x05d4; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05e0, 0x4b7fffff);
+	nv_wo32(chan, 0x0620, 0x00000080);
+	nv_wo32(chan, 0x0624, 0x30201000);
+	nv_wo32(chan, 0x0628, 0x70605040);
+	nv_wo32(chan, 0x062c, 0xb0a09080);
+	nv_wo32(chan, 0x0630, 0xf0e0d0c0);
+	nv_wo32(chan, 0x0664, 0x00000001);
+	nv_wo32(chan, 0x066c, 0x00004000);
+	nv_wo32(chan, 0x0678, 0x00000001);
+	nv_wo32(chan, 0x0680, 0x00040000);
+	nv_wo32(chan, 0x0684, 0x00010000);
+	for (i = 0x1b04; i <= 0x2374; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x2704, 0x3f800000);
+	nv_wo32(chan, 0x2718, 0x3f800000);
+	nv_wo32(chan, 0x2744, 0x40000000);
+	nv_wo32(chan, 0x2748, 0x3f800000);
+	nv_wo32(chan, 0x274c, 0x3f000000);
+	nv_wo32(chan, 0x2754, 0x40000000);
+	nv_wo32(chan, 0x2758, 0x3f800000);
+	nv_wo32(chan, 0x2760, 0xbf800000);
+	nv_wo32(chan, 0x2768, 0xbf800000);
+	nv_wo32(chan, 0x308c, 0x000fe000);
+	nv_wo32(chan, 0x3108, 0x000003f8);
+	nv_wo32(chan, 0x3468, 0x002fe000);
+	for (i = 0x3484; i <= 0x34a0; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv25_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x25),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv25_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv25_graph_cclass;
+	nv_engine(priv)->sclass = nv25_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv25_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x25),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv25_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
new file mode 100644
index 0000000..700462f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
@@ -0,0 +1,134 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv2a_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x269c, 0x3f800000);
+	nv_wo32(chan, 0x26b0, 0x3f800000);
+	nv_wo32(chan, 0x26dc, 0x40000000);
+	nv_wo32(chan, 0x26e0, 0x3f800000);
+	nv_wo32(chan, 0x26e4, 0x3f000000);
+	nv_wo32(chan, 0x26ec, 0x40000000);
+	nv_wo32(chan, 0x26f0, 0x3f800000);
+	nv_wo32(chan, 0x26f8, 0xbf800000);
+	nv_wo32(chan, 0x2700, 0xbf800000);
+	nv_wo32(chan, 0x3024, 0x000fe000);
+	nv_wo32(chan, 0x30a0, 0x000003f8);
+	nv_wo32(chan, 0x33fc, 0x002fe000);
+	for (i = 0x341c; i <= 0x3438; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv2a_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x2a),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv2a_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv2a_graph_cclass;
+	nv_engine(priv)->sclass = nv25_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv2a_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x2a),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv2a_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
new file mode 100644
index 0000000..cedadaa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
@@ -0,0 +1,238 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv30_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv30_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x0410, 0x00000101);
+	nv_wo32(chan, 0x0424, 0x00000111);
+	nv_wo32(chan, 0x0428, 0x00000060);
+	nv_wo32(chan, 0x0444, 0x00000080);
+	nv_wo32(chan, 0x0448, 0xffff0000);
+	nv_wo32(chan, 0x044c, 0x00000001);
+	nv_wo32(chan, 0x0460, 0x44400000);
+	nv_wo32(chan, 0x048c, 0xffff0000);
+	for (i = 0x04e0; i < 0x04e8; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04ec, 0x00011100);
+	for (i = 0x0508; i < 0x0548; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0550, 0x4b7fffff);
+	nv_wo32(chan, 0x058c, 0x00000080);
+	nv_wo32(chan, 0x0590, 0x30201000);
+	nv_wo32(chan, 0x0594, 0x70605040);
+	nv_wo32(chan, 0x0598, 0xb8a89888);
+	nv_wo32(chan, 0x059c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05b0, 0xb0000000);
+	for (i = 0x0600; i < 0x0640; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0640; i < 0x0680; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c0; i < 0x0700; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0700; i < 0x0740; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0740; i < 0x0780; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x085c, 0x00040000);
+	nv_wo32(chan, 0x0860, 0x00010000);
+	for (i = 0x0864; i < 0x0874; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x30b8; i < 0x30c8; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x344c, 0x3f800000);
+	nv_wo32(chan, 0x3808, 0x3f800000);
+	nv_wo32(chan, 0x381c, 0x3f800000);
+	nv_wo32(chan, 0x3848, 0x40000000);
+	nv_wo32(chan, 0x384c, 0x3f800000);
+	nv_wo32(chan, 0x3850, 0x3f000000);
+	nv_wo32(chan, 0x3858, 0x40000000);
+	nv_wo32(chan, 0x385c, 0x3f800000);
+	nv_wo32(chan, 0x3864, 0xbf800000);
+	nv_wo32(chan, 0x386c, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv30_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x30),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv30_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv30_graph_cclass;
+	nv_engine(priv)->sclass = nv30_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+int
+nv30_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv20_graph_priv *priv = (void *)engine;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	int ret, i;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, 0x400890, 0x01b463ff);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
+	nv_wr32(priv, 0x400B80, 0x1003d888);
+	nv_wr32(priv, 0x400B84, 0x0c000000);
+	nv_wr32(priv, 0x400098, 0x00000000);
+	nv_wr32(priv, 0x40009C, 0x0005ad00);
+	nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
+	nv_wr32(priv, 0x4000a0, 0x00000000);
+	nv_wr32(priv, 0x4000a4, 0x00000008);
+	nv_wr32(priv, 0x4008a8, 0xb784a400);
+	nv_wr32(priv, 0x400ba0, 0x002f8685);
+	nv_wr32(priv, 0x400ba4, 0x00231f3f);
+	nv_wr32(priv, 0x4008a4, 0x40000020);
+
+	if (nv_device(priv)->chipset == 0x34) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
+	}
+
+	nv_wr32(priv, 0x4000c0, 0x00000016);
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, 0x0040075c             , 0x00000001);
+
+	/* begin RAM config */
+	/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	if (nv_device(priv)->chipset != 0x34) {
+		nv_wr32(priv, 0x400750, 0x00EA0000);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x400750, 0x00EA0004);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
+	}
+	return 0;
+}
+
+struct nouveau_oclass
+nv30_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x30),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv30_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
new file mode 100644
index 0000000..273f632
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
@@ -0,0 +1,168 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv34_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv34_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x01000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0480, 0xffff0000);
+	for (i = 0x04d4; i < 0x04dc; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e0, 0x00011100);
+	for (i = 0x04fc; i < 0x053c; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0544, 0x4b7fffff);
+	nv_wo32(chan, 0x057c, 0x00000080);
+	nv_wo32(chan, 0x0580, 0x30201000);
+	nv_wo32(chan, 0x0584, 0x70605040);
+	nv_wo32(chan, 0x0588, 0xb8a89888);
+	nv_wo32(chan, 0x058c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05a0, 0xb0000000);
+	for (i = 0x05f0; i < 0x0630; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0630; i < 0x0670; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06b0; i < 0x06f0; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x06f0; i < 0x0730; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0730; i < 0x0770; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0850, 0x00040000);
+	nv_wo32(chan, 0x0854, 0x00010000);
+	for (i = 0x0858; i < 0x0868; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x15ac; i <= 0x271c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x274c; i < 0x275c; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x2ae0, 0x3f800000);
+	nv_wo32(chan, 0x2e9c, 0x3f800000);
+	nv_wo32(chan, 0x2eb0, 0x3f800000);
+	nv_wo32(chan, 0x2edc, 0x40000000);
+	nv_wo32(chan, 0x2ee0, 0x3f800000);
+	nv_wo32(chan, 0x2ee4, 0x3f000000);
+	nv_wo32(chan, 0x2eec, 0x40000000);
+	nv_wo32(chan, 0x2ef0, 0x3f800000);
+	nv_wo32(chan, 0x2ef8, 0xbf800000);
+	nv_wo32(chan, 0x2f00, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv34_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x34),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv34_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv34_graph_cclass;
+	nv_engine(priv)->sclass = nv34_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv34_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x34),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv34_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
new file mode 100644
index 0000000..f40ee21
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
@@ -0,0 +1,166 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv35_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv35_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x00000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0488, 0xffff0000);
+	for (i = 0x04dc; i < 0x04e4; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e8, 0x00011100);
+	for (i = 0x0504; i < 0x0544; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x054c, 0x4b7fffff);
+	nv_wo32(chan, 0x0588, 0x00000080);
+	nv_wo32(chan, 0x058c, 0x30201000);
+	nv_wo32(chan, 0x0590, 0x70605040);
+	nv_wo32(chan, 0x0594, 0xb8a89888);
+	nv_wo32(chan, 0x0598, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05ac, 0xb0000000);
+	for (i = 0x0604; i < 0x0644; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0644; i < 0x0684; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c4; i < 0x0704; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0704; i < 0x0744; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0744; i < 0x0784; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0860, 0x00040000);
+	nv_wo32(chan, 0x0864, 0x00010000);
+	for (i = 0x0868; i < 0x0878; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 4, 0x0436086c);
+		nv_wo32(chan, i + 8, 0x000c001b);
+	}
+	for (i = 0x30bc; i < 0x30cc; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x3450, 0x3f800000);
+	nv_wo32(chan, 0x380c, 0x3f800000);
+	nv_wo32(chan, 0x3820, 0x3f800000);
+	nv_wo32(chan, 0x384c, 0x40000000);
+	nv_wo32(chan, 0x3850, 0x3f800000);
+	nv_wo32(chan, 0x3854, 0x3f000000);
+	nv_wo32(chan, 0x385c, 0x40000000);
+	nv_wo32(chan, 0x3860, 0x3f800000);
+	nv_wo32(chan, 0x3868, 0xbf800000);
+	nv_wo32(chan, 0x3870, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv35_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x35),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv35_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv35_graph_cclass;
+	nv_engine(priv)->sclass = nv35_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv35_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x35),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv35_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
index 466d215..2f9f2c6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
@@ -1,151 +1,238 @@
 /*
- * Copyright (C) 2007 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/engctx.h>
 
-struct nv40_graph_engine {
-	struct nouveau_exec_engine base;
-	u32 grctx_size;
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+#include "nv40.h"
+#include "regs.h"
+
+struct nv40_graph_priv {
+	struct nouveau_graph base;
+	u32 size;
 };
 
+struct nv40_graph_chan {
+	struct nouveau_graph_chan base;
+};
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
 static int
-nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+nv40_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *grctx = NULL;
-	unsigned long flags;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &grctx);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    20, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
 
-	/* Initialise default context values */
-	nv40_grctx_fill(dev, grctx);
-	nv_wo32(grctx, 0, grctx->addr);
-
-	/* init grctx pointer in ramfc, and on PFIFO if channel is
-	 * already active there
-	 */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_wo32(chan->ramfc, 0x38, grctx->addr >> 4);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-	if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
-		nv_wr32(dev, 0x0032e0, grctx->addr >> 4);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	chan->engctx[engine] = grctx;
-	return 0;
-}
-
-static void
-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->addr >> 4);
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	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 */
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-int
-nv40_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 1;
-	obj->class  = class;
-
-	nv_wo32(obj, 0x00, class);
+	nv_wo32(obj, 0x00, nv_mclass(obj));
 	nv_wo32(obj, 0x04, 0x00000000);
-#ifndef __BIG_ENDIAN
 	nv_wo32(obj, 0x08, 0x00000000);
-#else
-	nv_wo32(obj, 0x08, 0x01000000);
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
 #endif
 	nv_wo32(obj, 0x0c, 0x00000000);
 	nv_wo32(obj, 0x10, 0x00000000);
+	return 0;
+}
 
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
+struct nouveau_ofuncs
+nv40_graph_ofuncs = {
+	.ctor = nv40_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv40_graph_sclass[] = {
+	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */
+	{},
+};
+
+static struct nouveau_oclass
+nv44_graph_sclass[] = {
+	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv40_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv40_graph_priv *priv = (void *)engine;
+	struct nv40_graph_chan *chan;
+	int ret;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 16,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+static int
+nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
+	int ret = 0;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+
+	if (nv_rd32(priv, 0x40032c) == inst) {
+		if (suspend) {
+			nv_wr32(priv, 0x400720, 0x00000000);
+			nv_wr32(priv, 0x400784, inst);
+			nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
+			nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
+			if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
+				u32 insn = nv_rd32(priv, 0x400308);
+				nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
+				ret = -EBUSY;
+			}
+		}
+
+		nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
+	}
+
+	if (nv_rd32(priv, 0x400330) == inst)
+		nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
 	return ret;
 }
 
-static void
-nv40_graph_set_tile_region(struct drm_device *dev, int i)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
+static struct nouveau_oclass
+nv40_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = nv40_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
 
-	switch (dev_priv->chipset) {
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
+{
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv40_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
 	case 0x41: /* guess */
 	case 0x42:
 	case 0x43:
 	case 0x45: /* guess */
 	case 0x4e:
-		nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
 		break;
 	case 0x44:
 	case 0x4a:
-		nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
 		break;
 	case 0x46:
 	case 0x47:
@@ -154,149 +241,213 @@
 	case 0x4c:
 	case 0x67:
 	default:
-		nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+		nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
 		break;
 	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+static void
+nv40_graph_intr(struct nouveau_subdev *subdev)
+{
+	struct nv40_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 inst = (nv_rd32(priv, 0x40032c) & 0x000fffff) << 4;
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
+	u32 show = stat;
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nouveau_engctx_lookup_class(engine, inst, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nouveau_engctx_handle_put(handle);
+		}
+
+		if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+			nv_mask(priv, 0x402000, 0, 0);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch 0x%08x subc %d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 inst, subc, class, mthd, data);
+	}
 }
 
-/*
- * G70		0x47
- * G71		0x49
- * NV45		0x48
- * G72[M]	0x46
- * G73		0x4b
- * C51_G7X	0x4c
- * C51		0x4e
- */
-int
-nv40_graph_init(struct drm_device *dev, int engine)
+static int
+nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t vramsz;
-	int i, j;
+	struct nv40_graph_priv *priv;
+	int ret;
 
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv40_graph_intr;
+	nv_engine(priv)->cclass = &nv40_graph_cclass;
+	if (nv44_graph_class(priv))
+		nv_engine(priv)->sclass = nv44_graph_sclass;
+	else
+		nv_engine(priv)->sclass = nv40_graph_sclass;
+	nv_engine(priv)->tile_prog = nv40_graph_tile_prog;
+	return 0;
+}
+
+static int
+nv40_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	struct nv40_graph_priv *priv = (void *)engine;
+	int ret, i, j;
+	u32 vramsz;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
 	/* generate and upload context program */
-	nv40_grctx_init(dev, &pgraph->grctx_size);
+	nv40_grctx_init(nv_device(priv), &priv->size);
 
 	/* No context present currently */
-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
+	nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
 
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
 
-	j = nv_rd32(dev, 0x1540) & 0xff;
+	j = nv_rd32(priv, 0x1540) & 0xff;
 	if (j) {
 		for (i = 0; !(j & 1); j >>= 1, i++)
 			;
-		nv_wr32(dev, 0x405000, i);
+		nv_wr32(priv, 0x405000, i);
 	}
 
-	if (dev_priv->chipset == 0x40) {
-		nv_wr32(dev, 0x4009b0, 0x83280fff);
-		nv_wr32(dev, 0x4009b4, 0x000000a0);
+	if (nv_device(priv)->chipset == 0x40) {
+		nv_wr32(priv, 0x4009b0, 0x83280fff);
+		nv_wr32(priv, 0x4009b4, 0x000000a0);
 	} else {
-		nv_wr32(dev, 0x400820, 0x83280eff);
-		nv_wr32(dev, 0x400824, 0x000000a0);
+		nv_wr32(priv, 0x400820, 0x83280eff);
+		nv_wr32(priv, 0x400824, 0x000000a0);
 	}
 
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
 	case 0x45:
-		nv_wr32(dev, 0x4009b8, 0x0078e366);
-		nv_wr32(dev, 0x4009bc, 0x0000014c);
+		nv_wr32(priv, 0x4009b8, 0x0078e366);
+		nv_wr32(priv, 0x4009bc, 0x0000014c);
 		break;
 	case 0x41:
 	case 0x42: /* pciid also 0x00Cx */
 	/* case 0x0120: XXX (pciid) */
-		nv_wr32(dev, 0x400828, 0x007596ff);
-		nv_wr32(dev, 0x40082c, 0x00000108);
+		nv_wr32(priv, 0x400828, 0x007596ff);
+		nv_wr32(priv, 0x40082c, 0x00000108);
 		break;
 	case 0x43:
-		nv_wr32(dev, 0x400828, 0x0072cb77);
-		nv_wr32(dev, 0x40082c, 0x00000108);
+		nv_wr32(priv, 0x400828, 0x0072cb77);
+		nv_wr32(priv, 0x40082c, 0x00000108);
 		break;
 	case 0x44:
 	case 0x46: /* G72 */
 	case 0x4a:
 	case 0x4c: /* G7x-based C51 */
 	case 0x4e:
-		nv_wr32(dev, 0x400860, 0);
-		nv_wr32(dev, 0x400864, 0);
+		nv_wr32(priv, 0x400860, 0);
+		nv_wr32(priv, 0x400864, 0);
 		break;
 	case 0x47: /* G70 */
 	case 0x49: /* G71 */
 	case 0x4b: /* G73 */
-		nv_wr32(dev, 0x400828, 0x07830610);
-		nv_wr32(dev, 0x40082c, 0x0000016A);
+		nv_wr32(priv, 0x400828, 0x07830610);
+		nv_wr32(priv, 0x40082c, 0x0000016A);
 		break;
 	default:
 		break;
 	}
 
-	nv_wr32(dev, 0x400b38, 0x2ffff800);
-	nv_wr32(dev, 0x400b3c, 0x00006000);
+	nv_wr32(priv, 0x400b38, 0x2ffff800);
+	nv_wr32(priv, 0x400b3c, 0x00006000);
 
 	/* Tiling related stuff. */
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0x44:
 	case 0x4a:
-		nv_wr32(dev, 0x400bc4, 0x1003d888);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b500);
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b500);
 		break;
 	case 0x46:
-		nv_wr32(dev, 0x400bc4, 0x0000e024);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b520);
+		nv_wr32(priv, 0x400bc4, 0x0000e024);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b520);
 		break;
 	case 0x4c:
 	case 0x4e:
 	case 0x67:
-		nv_wr32(dev, 0x400bc4, 0x1003d888);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b540);
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b540);
 		break;
 	default:
 		break;
 	}
 
 	/* Turn all the tiling regions off. */
-	for (i = 0; i < nvfb_tile_nr(dev); i++)
-		nv40_graph_set_tile_region(dev, i);
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
 
 	/* begin RAM config */
-	vramsz = pci_resource_len(dev->pdev, 0) - 1;
-	switch (dev_priv->chipset) {
+	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
-		nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x4069A4, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4069A8, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x400820, 0);
-		nv_wr32(dev, 0x400824, 0);
-		nv_wr32(dev, 0x400864, vramsz);
-		nv_wr32(dev, 0x400868, vramsz);
+		nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400820, 0);
+		nv_wr32(priv, 0x400824, 0);
+		nv_wr32(priv, 0x400864, vramsz);
+		nv_wr32(priv, 0x400868, vramsz);
 		break;
 	default:
-		switch (dev_priv->chipset) {
+		switch (nv_device(priv)->chipset) {
 		case 0x41:
 		case 0x42:
 		case 0x43:
@@ -304,163 +455,33 @@
 		case 0x4e:
 		case 0x44:
 		case 0x4a:
-			nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
-			nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
+			nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
 			break;
 		default:
-			nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
-			nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
+			nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
 			break;
 		}
-		nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x400840, 0);
-		nv_wr32(dev, 0x400844, 0);
-		nv_wr32(dev, 0x4008A0, vramsz);
-		nv_wr32(dev, 0x4008A4, vramsz);
+		nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400840, 0);
+		nv_wr32(priv, 0x400844, 0);
+		nv_wr32(priv, 0x4008A0, vramsz);
+		nv_wr32(priv, 0x4008A4, vramsz);
 		break;
 	}
 
 	return 0;
 }
 
-static int
-nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	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;
-}
-
-static int
-nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *grctx;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		if (!dev_priv->channels.ptr[i])
-			continue;
-		grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
-
-		if (grctx && grctx->addr == inst)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nv40_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4;
-		u32 chid = nv40_graph_isr_chid(dev, inst);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			} else
-			if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
-				nv_mask(dev, 0x402000, 0, 0);
-			}
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d "
-				     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
-		}
-	}
-}
-
-static void
-nv40_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv40_graph_create(struct drm_device *dev)
-{
-	struct nv40_graph_engine *pgraph;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv40_graph_destroy;
-	pgraph->base.init = nv40_graph_init;
-	pgraph->base.fini = nv40_graph_fini;
-	pgraph->base.context_new = nv40_graph_context_new;
-	pgraph->base.context_del = nv40_graph_context_del;
-	pgraph->base.object_new = nv40_graph_object_new;
-	pgraph->base.set_tile_region = nv40_graph_set_tile_region;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv40_graph_isr);
-
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
-	/* curie */
-	if (nv44_graph_class(dev))
-		NVOBJ_CLASS(dev, 0x4497, GR);
-	else
-		NVOBJ_CLASS(dev, 0x4097, GR);
-
-	return 0;
-}
+struct nouveau_oclass
+nv40_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv40_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
new file mode 100644
index 0000000..d2ac975
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
@@ -0,0 +1,21 @@
+#ifndef __NV40_GRAPH_H__
+#define __NV40_GRAPH_H__
+
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_graph_class(void *priv)
+{
+	struct nouveau_device *device = nv_device(priv);
+
+	if ((device->chipset & 0xf0) == 0x60)
+		return 1;
+
+	return !(0x0baf & (1 << (device->chipset & 0x0f)));
+}
+
+void nv40_grctx_init(struct nouveau_device *, u32 *size);
+void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 28932c4..8955bdd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -1,266 +1,234 @@
 /*
- * Copyright (C) 2007 Ben Skeggs.
- * All Rights Reserved.
+ * Copyright 2012 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
-#include "nouveau_dma.h"
-#include "nv50_evo.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/engctx.h>
+#include <core/enum.h>
 
-struct nv50_graph_engine {
-	struct nouveau_exec_engine base;
-	u32 ctxprog[512];
-	u32 ctxprog_size;
-	u32 grctx_size;
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+
+#include "nv50.h"
+
+struct nv50_graph_priv {
+	struct nouveau_graph base;
+	spinlock_t lock;
+	u32 size;
 };
 
-static int
-nv50_graph_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-	u32 units = nv_rd32(dev, 0x001540);
-	int i;
+struct nv50_graph_chan {
+	struct nouveau_graph_chan base;
+};
 
-	NV_DEBUG(dev, "\n");
-
-	/* master reset */
-	nv_mask(dev, 0x000200, 0x00201000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00201000, 0x00201000);
-	nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
-
-	/* reset/enable traps and interrupts */
-	nv_wr32(dev, 0x400804, 0xc0000000);
-	nv_wr32(dev, 0x406800, 0xc0000000);
-	nv_wr32(dev, 0x400c04, 0xc0000000);
-	nv_wr32(dev, 0x401800, 0xc0000000);
-	nv_wr32(dev, 0x405018, 0xc0000000);
-	nv_wr32(dev, 0x402000, 0xc0000000);
-	for (i = 0; i < 16; i++) {
-		if (!(units & (1 << i)))
-			continue;
-
-		if (dev_priv->chipset < 0xa0) {
-			nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
-			nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
-			nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
-		} else {
-			nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
-			nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
-			nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
-		}
-	}
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-	nv_wr32(dev, 0x400500, 0x00010001);
-
-	/* upload context program, initialise ctxctl defaults */
-	nv_wr32(dev, 0x400324, 0x00000000);
-	for (i = 0; i < pgraph->ctxprog_size; i++)
-		nv_wr32(dev, 0x400328, pgraph->ctxprog[i]);
-	nv_wr32(dev, 0x400824, 0x00000000);
-	nv_wr32(dev, 0x400828, 0x00000000);
-	nv_wr32(dev, 0x40082c, 0x00000000);
-	nv_wr32(dev, 0x400830, 0x00000000);
-	nv_wr32(dev, 0x400724, 0x00000000);
-	nv_wr32(dev, 0x40032c, 0x00000000);
-	nv_wr32(dev, 0x400320, 4);	/* CTXCTL_CMD = NEWCTXDMA */
-
-	/* some unknown zcull magic */
-	switch (dev_priv->chipset & 0xf0) {
-	case 0x50:
-	case 0x80:
-	case 0x90:
-		nv_wr32(dev, 0x402ca8, 0x00000800);
-		break;
-	case 0xa0:
-	default:
-		nv_wr32(dev, 0x402cc0, 0x00000000);
-		if (dev_priv->chipset == 0xa0 ||
-		    dev_priv->chipset == 0xaa ||
-		    dev_priv->chipset == 0xac) {
-			nv_wr32(dev, 0x402ca8, 0x00000802);
-		} else {
-			nv_wr32(dev, 0x402cc0, 0x00000000);
-			nv_wr32(dev, 0x402ca8, 0x00000002);
-		}
-
-		break;
-	}
-
-	/* zero out zcull regions */
-	for (i = 0; i < 8; i++) {
-		nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000);
-	}
-
-	return 0;
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
 static int
-nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
+nv50_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	nv_wr32(dev, 0x40013c, 0x00000000);
-	return 0;
-}
-
-static int
-nv50_graph_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 *grctx = NULL;
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-	int hdr, ret;
-
-	NV_DEBUG(dev, "ch%d\n", chan->id);
-
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &grctx);
-	if (ret)
-		return ret;
-
-	hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-	nv_wo32(ramin, hdr + 0x00, 0x00190002);
-	nv_wo32(ramin, hdr + 0x04, grctx->addr + grctx->size - 1);
-	nv_wo32(ramin, hdr + 0x08, grctx->addr);
-	nv_wo32(ramin, hdr + 0x0c, 0);
-	nv_wo32(ramin, hdr + 0x10, 0);
-	nv_wo32(ramin, hdr + 0x14, 0x00010000);
-
-	nv50_grctx_fill(dev, grctx);
-	nv_wo32(grctx, 0x00000, chan->ramin->addr >> 12);
-
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, 1);
-	chan->engctx[NVOBJ_ENGINE_GR] = grctx;
-	return 0;
-}
-
-static void
-nv50_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;
-	int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-
-	for (i = hdr; i < hdr + 24; i += 4)
-		nv_wo32(chan->ramin, i, 0);
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, -1);
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nv50_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
-	obj->engine = 1;
-	obj->class  = class;
 
-	nv_wo32(obj, 0x00, class);
+	nv_wo32(obj, 0x00, nv_mclass(obj));
 	nv_wo32(obj, 0x04, 0x00000000);
 	nv_wo32(obj, 0x08, 0x00000000);
 	nv_wo32(obj, 0x0c, 0x00000000);
-	nvimem_flush(dev);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
+	return 0;
 }
 
-static void
-nv50_graph_tlb_flush(struct drm_device *dev, int engine)
+struct nouveau_ofuncs
+nv50_graph_ofuncs = {
+	.ctor = nv50_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv50_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x5097, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nv84_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8297, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nva0_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8397, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nva3_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8597, &nv50_graph_ofuncs },
+	{ 0x85c0, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nvaf_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x85c0, &nv50_graph_ofuncs },
+	{ 0x8697, &nv50_graph_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv50_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	nv50_vm_flush_engine(dev, 0);
+	struct nv50_graph_priv *priv = (void *)engine;
+	struct nv50_graph_chan *chan;
+	int ret;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 0,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	return 0;
 }
 
-static void
-nv84_graph_tlb_flush(struct drm_device *dev, int engine)
+static struct nouveau_oclass
+nv50_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv50_graph_tlb_flush(struct nouveau_engine *engine)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	nv50_vm_flush_engine(&engine->base, 0x00);
+	return 0;
+}
+
+static int
+nv84_graph_tlb_flush(struct nouveau_engine *engine)
+{
+	struct nouveau_timer *ptimer = nouveau_timer(engine);
+	struct nv50_graph_priv *priv = (void *)engine;
 	bool idle, timeout = false;
 	unsigned long flags;
 	u64 start;
 	u32 tmp;
 
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
 
-	start = nv_timer_read(dev);
+	start = ptimer->read(ptimer);
 	do {
 		idle = true;
 
-		for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
 
-		for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
 
-		for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
-	} while (!idle && !(timeout = nv_timer_read(dev) - start > 2000000000));
+	} while (!idle &&
+		 !(timeout = ptimer->read(ptimer) - start > 2000000000));
 
 	if (timeout) {
-		NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+		nv_error(priv, "PGRAPH TLB flush idle timeout fail: "
 			      "0x%08x 0x%08x 0x%08x 0x%08x\n",
-			 nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
-			 nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+			 nv_rd32(priv, 0x400700), nv_rd32(priv, 0x400380),
+			 nv_rd32(priv, 0x400384), nv_rd32(priv, 0x400388));
 	}
 
-	nv50_vm_flush_engine(dev, 0);
+	nv50_vm_flush_engine(&engine->base, 0x00);
 
-	nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return timeout ? -EBUSY : 0;
 }
 
 static struct nouveau_enum nv50_mp_exec_error_names[] = {
@@ -341,7 +309,7 @@
 	{}
 };
 
-static struct nouveau_bitfield nv50_graph_intr[] = {
+static struct nouveau_bitfield nv50_graph_intr_name[] = {
 	{ 0x00000001, "NOTIFY" },
 	{ 0x00000002, "COMPUTE_QUERY" },
 	{ 0x00000010, "ILLEGAL_MTHD" },
@@ -356,95 +324,93 @@
 };
 
 static void
-nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
+nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t units = nv_rd32(dev, 0x1540);
-	uint32_t addr, mp10, status, pc, oplow, ophigh;
+	u32 units = nv_rd32(priv, 0x1540);
+	u32 addr, mp10, status, pc, oplow, ophigh;
 	int i;
 	int mps = 0;
 	for (i = 0; i < 4; i++) {
 		if (!(units & 1 << (i+24)))
 			continue;
-		if (dev_priv->chipset < 0xa0)
+		if (nv_device(priv)->chipset < 0xa0)
 			addr = 0x408200 + (tpid << 12) + (i << 7);
 		else
 			addr = 0x408100 + (tpid << 11) + (i << 7);
-		mp10 = nv_rd32(dev, addr + 0x10);
-		status = nv_rd32(dev, addr + 0x14);
+		mp10 = nv_rd32(priv, addr + 0x10);
+		status = nv_rd32(priv, addr + 0x14);
 		if (!status)
 			continue;
 		if (display) {
-			nv_rd32(dev, addr + 0x20);
-			pc = nv_rd32(dev, addr + 0x24);
-			oplow = nv_rd32(dev, addr + 0x70);
-			ophigh = nv_rd32(dev, addr + 0x74);
-			NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
+			nv_rd32(priv, addr + 0x20);
+			pc = nv_rd32(priv, addr + 0x24);
+			oplow = nv_rd32(priv, addr + 0x70);
+			ophigh = nv_rd32(priv, addr + 0x74);
+			nv_error(priv, "TRAP_MP_EXEC - "
 					"TP %d MP %d: ", tpid, i);
 			nouveau_enum_print(nv50_mp_exec_error_names, status);
 			printk(" at %06x warp %d, opcode %08x %08x\n",
 					pc&0xffffff, pc >> 24,
 					oplow, ophigh);
 		}
-		nv_wr32(dev, addr + 0x10, mp10);
-		nv_wr32(dev, addr + 0x14, 0);
+		nv_wr32(priv, addr + 0x10, mp10);
+		nv_wr32(priv, addr + 0x14, 0);
 		mps++;
 	}
 	if (!mps && display)
-		NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
+		nv_error(priv, "TRAP_MP_EXEC - TP %d: "
 				"No MPs claiming errors?\n", tpid);
 }
 
 static void
-nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
-		uint32_t ustatus_new, int display, const char *name)
+nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
+		u32 ustatus_new, int display, const char *name)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	int tps = 0;
-	uint32_t units = nv_rd32(dev, 0x1540);
+	u32 units = nv_rd32(priv, 0x1540);
 	int i, r;
-	uint32_t ustatus_addr, ustatus;
+	u32 ustatus_addr, ustatus;
 	for (i = 0; i < 16; i++) {
 		if (!(units & (1 << i)))
 			continue;
-		if (dev_priv->chipset < 0xa0)
+		if (nv_device(priv)->chipset < 0xa0)
 			ustatus_addr = ustatus_old + (i << 12);
 		else
 			ustatus_addr = ustatus_new + (i << 11);
-		ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
+		ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
 		if (!ustatus)
 			continue;
 		tps++;
 		switch (type) {
 		case 6: /* texture error... unknown for now */
 			if (display) {
-				NV_ERROR(dev, "magic set %d:\n", i);
+				nv_error(priv, "magic set %d:\n", i);
 				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
-					NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
-						nv_rd32(dev, r));
+					nv_error(priv, "\t0x%08x: 0x%08x\n", r,
+						nv_rd32(priv, r));
 			}
 			break;
 		case 7: /* MP error */
 			if (ustatus & 0x04030000) {
-				nv50_pgraph_mp_trap(dev, i, display);
+				nv50_priv_mp_trap(priv, i, display);
 				ustatus &= ~0x04030000;
 			}
 			break;
 		case 8: /* TPDMA error */
 			{
-			uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
-			uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
-			uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
-			uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
-			uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
-			uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
-			uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
+			u32 e0c = nv_rd32(priv, ustatus_addr + 4);
+			u32 e10 = nv_rd32(priv, ustatus_addr + 8);
+			u32 e14 = nv_rd32(priv, ustatus_addr + 0xc);
+			u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
+			u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
+			u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
+			u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
 			/* 2d engine destination */
 			if (ustatus & 0x00000010) {
 				if (display) {
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
+					nv_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
 							i, e14, e10);
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000010;
@@ -452,9 +418,9 @@
 			/* Render target */
 			if (ustatus & 0x00000040) {
 				if (display) {
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
+					nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
 							i, e14, e10);
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000040;
@@ -464,19 +430,19 @@
 				if (display) {
 					if (e18 & 0x80000000) {
 						/* g[] read fault? */
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
 								i, e14, e10 | ((e18 >> 24) & 0x1f));
 						e18 &= ~0x1f000000;
 					} else if (e18 & 0xc) {
 						/* g[] write fault? */
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
 								i, e14, e10 | ((e18 >> 7) & 0x1f));
 						e18 &= ~0x00000f80;
 					} else {
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
 								i, e14, e10);
 					}
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000080;
@@ -486,23 +452,23 @@
 		}
 		if (ustatus) {
 			if (display)
-				NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+				nv_info(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
 		}
-		nv_wr32(dev, ustatus_addr, 0xc0000000);
+		nv_wr32(priv, ustatus_addr, 0xc0000000);
 	}
 
 	if (!tps && display)
-		NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
+		nv_info(priv, "%s - No TPs claiming errors?\n", name);
 }
 
 static int
-nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid)
+nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, u64 inst)
 {
-	u32 status = nv_rd32(dev, 0x400108);
+	u32 status = nv_rd32(priv, 0x400108);
 	u32 ustatus;
 
 	if (!status && display) {
-		NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n");
+		nv_error(priv, "TRAP: no units reporting traps?\n");
 		return 1;
 	}
 
@@ -510,72 +476,72 @@
 	 * COND, QUERY. If you get a trap from it, the command is still stuck
 	 * in DISPATCH and you need to do something about it. */
 	if (status & 0x001) {
-		ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
 		if (!ustatus && display) {
-			NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
+			nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
 		}
 
-		nv_wr32(dev, 0x400500, 0x00000000);
+		nv_wr32(priv, 0x400500, 0x00000000);
 
 		/* Known to be triggered by screwed up NOTIFY and COND... */
 		if (ustatus & 0x00000001) {
-			u32 addr = nv_rd32(dev, 0x400808);
+			u32 addr = nv_rd32(priv, 0x400808);
 			u32 subc = (addr & 0x00070000) >> 16;
 			u32 mthd = (addr & 0x00001ffc);
-			u32 datal = nv_rd32(dev, 0x40080c);
-			u32 datah = nv_rd32(dev, 0x400810);
-			u32 class = nv_rd32(dev, 0x400814);
-			u32 r848 = nv_rd32(dev, 0x400848);
+			u32 datal = nv_rd32(priv, 0x40080c);
+			u32 datah = nv_rd32(priv, 0x400810);
+			u32 class = nv_rd32(priv, 0x400814);
+			u32 r848 = nv_rd32(priv, 0x400848);
 
-			NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n");
+			nv_error(priv, "TRAP DISPATCH_FAULT\n");
 			if (display && (addr & 0x80000000)) {
-				NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+				nv_error(priv, "ch 0x%010llx "
 					     "subc %d class 0x%04x mthd 0x%04x "
 					     "data 0x%08x%08x "
 					     "400808 0x%08x 400848 0x%08x\n",
-					chid, inst, subc, class, mthd, datah,
+					inst, subc, class, mthd, datah,
 					datal, addr, r848);
 			} else
 			if (display) {
-				NV_INFO(dev, "PGRAPH - no stuck command?\n");
+				nv_error(priv, "no stuck command?\n");
 			}
 
-			nv_wr32(dev, 0x400808, 0);
-			nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
-			nv_wr32(dev, 0x400848, 0);
+			nv_wr32(priv, 0x400808, 0);
+			nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
+			nv_wr32(priv, 0x400848, 0);
 			ustatus &= ~0x00000001;
 		}
 
 		if (ustatus & 0x00000002) {
-			u32 addr = nv_rd32(dev, 0x40084c);
+			u32 addr = nv_rd32(priv, 0x40084c);
 			u32 subc = (addr & 0x00070000) >> 16;
 			u32 mthd = (addr & 0x00001ffc);
-			u32 data = nv_rd32(dev, 0x40085c);
-			u32 class = nv_rd32(dev, 0x400814);
+			u32 data = nv_rd32(priv, 0x40085c);
+			u32 class = nv_rd32(priv, 0x400814);
 
-			NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n");
+			nv_error(priv, "TRAP DISPATCH_QUERY\n");
 			if (display && (addr & 0x80000000)) {
-				NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+				nv_error(priv, "ch 0x%010llx "
 					     "subc %d class 0x%04x mthd 0x%04x "
 					     "data 0x%08x 40084c 0x%08x\n",
-					chid, inst, subc, class, mthd,
+					inst, subc, class, mthd,
 					data, addr);
 			} else
 			if (display) {
-				NV_INFO(dev, "PGRAPH - no stuck command?\n");
+				nv_error(priv, "no stuck command?\n");
 			}
 
-			nv_wr32(dev, 0x40084c, 0);
+			nv_wr32(priv, 0x40084c, 0);
 			ustatus &= ~0x00000002;
 		}
 
 		if (ustatus && display) {
-			NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown "
+			nv_error(priv, "TRAP_DISPATCH (unknown "
 				      "0x%08x)\n", ustatus);
 		}
 
-		nv_wr32(dev, 0x400804, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x001);
+		nv_wr32(priv, 0x400804, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x001);
 		status &= ~0x001;
 		if (!status)
 			return 0;
@@ -583,81 +549,81 @@
 
 	/* M2MF: Memory to memory copy engine. */
 	if (status & 0x002) {
-		u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
+		u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_M2MF");
+			nv_error(priv, "TRAP_M2MF");
 			nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808),
-				nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810));
+			nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
+				nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
 
 		}
 
 		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(dev, 0x400040, 2);
-		nv_wr32(dev, 0x400040, 0);
-		nv_wr32(dev, 0x406800, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x002);
+		nv_wr32(priv, 0x400040, 2);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x406800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x002);
 		status &= ~0x002;
 	}
 
 	/* VFETCH: Fetches data from vertex buffers. */
 	if (status & 0x004) {
-		u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
+		u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_VFETCH");
+			nv_error(priv, "TRAP_VFETCH");
 			nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08),
-				nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10));
+			nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
+				nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
 		}
 
-		nv_wr32(dev, 0x400c04, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x004);
+		nv_wr32(priv, 0x400c04, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x004);
 		status &= ~0x004;
 	}
 
 	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
 	if (status & 0x008) {
-		ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_STRMOUT");
+			nv_error(priv, "TRAP_STRMOUT");
 			nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808),
-				nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810));
+			nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
+				nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
 
 		}
 
 		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(dev, 0x400040, 0x80);
-		nv_wr32(dev, 0x400040, 0);
-		nv_wr32(dev, 0x401800, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x008);
+		nv_wr32(priv, 0x400040, 0x80);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x401800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x008);
 		status &= ~0x008;
 	}
 
 	/* CCACHE: Handles code and c[] caches and fills them. */
 	if (status & 0x010) {
-		ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_CCACHE");
+			nv_error(priv, "TRAP_CCACHE");
 			nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x"
+			nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
 				     " %08x %08x %08x\n",
-				nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004),
-				nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c),
-				nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014),
-				nv_rd32(dev, 0x40501c));
+				nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
+				nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
+				nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
+				nv_rd32(priv, 0x40501c));
 
 		}
 
-		nv_wr32(dev, 0x405018, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x010);
+		nv_wr32(priv, 0x405018, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x010);
 		status &= ~0x010;
 	}
 
@@ -665,201 +631,248 @@
 	 * remaining, so try to handle it anyway. Perhaps related to that
 	 * unknown DMA slot on tesla? */
 	if (status & 0x20) {
-		ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
 		if (display)
-			NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus);
-		nv_wr32(dev, 0x402000, 0xc0000000);
+			nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
+		nv_wr32(priv, 0x402000, 0xc0000000);
 		/* no status modifiction on purpose */
 	}
 
 	/* TEXTURE: CUDA texturing units */
 	if (status & 0x040) {
-		nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display,
-				    "PGRAPH - TRAP_TEXTURE");
-		nv_wr32(dev, 0x400108, 0x040);
+		nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
+				    "TRAP_TEXTURE");
+		nv_wr32(priv, 0x400108, 0x040);
 		status &= ~0x040;
 	}
 
 	/* MP: CUDA execution engines. */
 	if (status & 0x080) {
-		nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display,
-				    "PGRAPH - TRAP_MP");
-		nv_wr32(dev, 0x400108, 0x080);
+		nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
+				    "TRAP_MP");
+		nv_wr32(priv, 0x400108, 0x080);
 		status &= ~0x080;
 	}
 
 	/* TPDMA:  Handles TP-initiated uncached memory accesses:
 	 * l[], g[], stack, 2d surfaces, render targets. */
 	if (status & 0x100) {
-		nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display,
-				    "PGRAPH - TRAP_TPDMA");
-		nv_wr32(dev, 0x400108, 0x100);
+		nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
+				    "TRAP_TPDMA");
+		nv_wr32(priv, 0x400108, 0x100);
 		status &= ~0x100;
 	}
 
 	if (status) {
 		if (display)
-			NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status);
-		nv_wr32(dev, 0x400108, status);
+			nv_error(priv, "TRAP: unknown 0x%08x\n", status);
+		nv_wr32(priv, 0x400108, status);
 	}
 
 	return 1;
 }
 
-int
-nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
 static void
-nv50_graph_isr(struct drm_device *dev)
+nv50_graph_intr(struct nouveau_subdev *subdev)
 {
-	u32 stat;
+	struct nv50_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u64 inst = (u64)(nv_rd32(priv, 0x40032c) & 0x0fffffff) << 12;
+	u32 addr = nv_rd32(priv, 0x400704);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 class = nv_rd32(priv, 0x400814);
+	u32 show = stat;
 
-	while ((stat = nv_rd32(dev, 0x400100))) {
-		u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12;
-		u32 chid = nv50_graph_isr_chid(dev, inst);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400814);
-		u32 show = stat;
-
-		if (stat & 0x00000010) {
-			if (!nouveau_gpuobj_mthd_call2(dev, chid, class,
-						       mthd, data))
-				show &= ~0x00000010;
-		}
-
-		show = (show && nouveau_ratelimit()) ? show : 0;
-
-		if (show & 0x00100000) {
-			u32 ecode = nv_rd32(dev, 0x400110);
-			NV_INFO(dev, "PGRAPH - DATA_ERROR ");
-			nouveau_enum_print(nv50_data_error_names, ecode);
-			printk("\n");
-		}
-
-		if (stat & 0x00200000) {
-			if (!nv50_pgraph_trap_handler(dev, show, inst, chid))
-				show &= ~0x00200000;
-		}
-
-		nv_wr32(dev, 0x400100, stat);
-		nv_wr32(dev, 0x400500, 0x00010001);
-
-		if (show) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv50_graph_intr, show);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d "
-				     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
-			nv50_fb_vm_trap(dev, 1);
-		}
+	if (stat & 0x00000010) {
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (handle && !nv_call(handle->object, mthd, data))
+			show &= ~0x00000010;
+		nouveau_engctx_handle_put(handle);
 	}
 
-	if (nv_rd32(dev, 0x400824) & (1 << 31))
-		nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+	if (show & 0x00100000) {
+		u32 ecode = nv_rd32(priv, 0x400110);
+		nv_error(priv, "DATA_ERROR ");
+		nouveau_enum_print(nv50_data_error_names, ecode);
+		printk("\n");
+	}
+
+	if (stat & 0x00200000) {
+		if (!nv50_graph_trap_handler(priv, show, inst))
+			show &= ~0x00200000;
+	}
+
+	nv_wr32(priv, 0x400100, stat);
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv50_graph_intr_name, show);
+		printk("\n");
+		nv_error(priv, "ch 0x%010llx subc %d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 inst, subc, class, mthd, data);
+		nv50_fb_trap(nouveau_fb(priv), 1);
+	}
+
+	if (nv_rd32(priv, 0x400824) & (1 << 31))
+		nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
 }
 
-static void
-nv50_graph_destroy(struct drm_device *dev, int engine)
+static int
+nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-
-	nouveau_irq_unregister(dev, 12);
-	kfree(pgraph);
-}
-
-int
-nv50_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_graph_engine *pgraph;
+	struct nv50_graph_priv *priv;
 	int ret;
 
-	pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	ret = nv50_grctx_init(dev, pgraph->ctxprog, ARRAY_SIZE(pgraph->ctxprog),
-				  &pgraph->ctxprog_size,
-				  &pgraph->grctx_size);
-	if (ret) {
-		NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
-		kfree(pgraph);
-		return 0;
-	}
+	nv_subdev(priv)->unit = 0x00201000;
+	nv_subdev(priv)->intr = nv50_graph_intr;
+	nv_engine(priv)->cclass = &nv50_graph_cclass;
 
-	pgraph->base.destroy = nv50_graph_destroy;
-	pgraph->base.init = nv50_graph_init;
-	pgraph->base.fini = nv50_graph_fini;
-	pgraph->base.context_new = nv50_graph_context_new;
-	pgraph->base.context_del = nv50_graph_context_del;
-	pgraph->base.object_new = nv50_graph_object_new;
-	if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
-		pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+	switch (nv_device(priv)->chipset) {
+	case 0x50:
+		nv_engine(priv)->sclass = nv50_graph_sclass;
+		break;
+	case 0x84:
+	case 0x86:
+	case 0x92:
+	case 0x94:
+	case 0x96:
+	case 0x98:
+		nv_engine(priv)->sclass = nv84_graph_sclass;
+		break;
+	case 0xa0:
+	case 0xaa:
+	case 0xac:
+		nv_engine(priv)->sclass = nva0_graph_sclass;
+		break;
+	case 0xa3:
+	case 0xa5:
+	case 0xa8:
+		nv_engine(priv)->sclass = nva3_graph_sclass;
+		break;
+	case 0xaf:
+		nv_engine(priv)->sclass = nvaf_graph_sclass;
+		break;
+
+	};
+
+	if (nv_device(priv)->chipset == 0x50 ||
+	    nv_device(priv)->chipset == 0xac)
+		nv_engine(priv)->tlb_flush = nv50_graph_tlb_flush;
 	else
-		pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+		nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
 
-	nouveau_irq_register(dev, 12, nv50_graph_isr);
+	spin_lock_init(&priv->lock);
+	return 0;
+}
 
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+static int
+nv50_graph_init(struct nouveau_object *object)
+{
+	struct nv50_graph_priv *priv = (void *)object;
+	int ret, units, i;
 
-	/* tesla */
-	if (dev_priv->chipset == 0x50)
-		NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
-	else
-	if (dev_priv->chipset < 0xa0)
-		NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
-	else {
-		switch (dev_priv->chipset) {
-		case 0xa0:
-		case 0xaa:
-		case 0xac:
-			NVOBJ_CLASS(dev, 0x8397, GR);
-			break;
-		case 0xa3:
-		case 0xa5:
-		case 0xa8:
-			NVOBJ_CLASS(dev, 0x8597, GR);
-			break;
-		case 0xaf:
-			NVOBJ_CLASS(dev, 0x8697, GR);
-			break;
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
+	nv_wr32(priv, 0x40008c, 0x00000004);
+
+	/* reset/enable traps and interrupts */
+	nv_wr32(priv, 0x400804, 0xc0000000);
+	nv_wr32(priv, 0x406800, 0xc0000000);
+	nv_wr32(priv, 0x400c04, 0xc0000000);
+	nv_wr32(priv, 0x401800, 0xc0000000);
+	nv_wr32(priv, 0x405018, 0xc0000000);
+	nv_wr32(priv, 0x402000, 0xc0000000);
+
+	units = nv_rd32(priv, 0x001540);
+	for (i = 0; i < 16; i++) {
+		if (!(units & (1 << i)))
+			continue;
+
+		if (nv_device(priv)->chipset < 0xa0) {
+			nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
+		} else {
+			nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
 		}
 	}
 
-	/* compute */
-	NVOBJ_CLASS(dev, 0x50c0, GR);
-	if (dev_priv->chipset  > 0xa0 &&
-	    dev_priv->chipset != 0xaa &&
-	    dev_priv->chipset != 0xac)
-		NVOBJ_CLASS(dev, 0x85c0, GR);
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+	nv_wr32(priv, 0x400500, 0x00010001);
 
+	/* upload context program, initialise ctxctl defaults */
+	ret = nv50_grctx_init(nv_device(priv), &priv->size);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x400824, 0x00000000);
+	nv_wr32(priv, 0x400828, 0x00000000);
+	nv_wr32(priv, 0x40082c, 0x00000000);
+	nv_wr32(priv, 0x400830, 0x00000000);
+	nv_wr32(priv, 0x400724, 0x00000000);
+	nv_wr32(priv, 0x40032c, 0x00000000);
+	nv_wr32(priv, 0x400320, 4);	/* CTXCTL_CMD = NEWCTXDMA */
+
+	/* some unknown zcull magic */
+	switch (nv_device(priv)->chipset & 0xf0) {
+	case 0x50:
+	case 0x80:
+	case 0x90:
+		nv_wr32(priv, 0x402ca8, 0x00000800);
+		break;
+	case 0xa0:
+	default:
+		nv_wr32(priv, 0x402cc0, 0x00000000);
+		if (nv_device(priv)->chipset == 0xa0 ||
+		    nv_device(priv)->chipset == 0xaa ||
+		    nv_device(priv)->chipset == 0xac) {
+			nv_wr32(priv, 0x402ca8, 0x00000802);
+		} else {
+			nv_wr32(priv, 0x402cc0, 0x00000000);
+			nv_wr32(priv, 0x402ca8, 0x00000002);
+		}
+
+		break;
+	}
+
+	/* zero out zcull regions */
+	for (i = 0; i < 8; i++) {
+		nv_wr32(priv, 0x402c20 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c24 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c28 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c2c + (i * 8), 0x00000000);
+	}
 	return 0;
 }
+
+struct nouveau_oclass
+nv50_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv50_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
new file mode 100644
index 0000000..0505fb4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
@@ -0,0 +1,7 @@
+#ifndef __NV50_GRAPH_H__
+#define __NV50_GRAPH_H__
+
+int  nv50_grctx_init(struct nouveau_device *, u32 *size);
+void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
index f994d2f..db8aefc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,94 +22,92 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include "drmP.h"
-
-#include "nouveau_drv.h"
-#include <core/mm.h>
-#include <engine/fifo.h>
-
 #include "nvc0.h"
 #include "fuc/hubnvc0.fuc.h"
 #include "fuc/gpcnvc0.fuc.h"
 
-static void
-nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
-{
-	NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
-		nv_rd32(dev, base + 0x400));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
-		nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
-		nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
-void
-nvc0_graph_ctxctl_debug(struct drm_device *dev)
-{
-	u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
-	u32 gpc;
+static struct nouveau_oclass
+nvc0_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{}
+};
 
-	nvc0_graph_ctxctl_debug_unit(dev, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
-}
+static struct nouveau_oclass
+nvc1_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{ 0x9197, &nouveau_object_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nvc8_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{ 0x9197, &nouveau_object_ofuncs },
+	{ 0x9297, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
 
 int
-nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
+nvc0_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *args, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+	struct nouveau_vm *vm = nouveau_client(parent)->vm;
+	struct nvc0_graph_priv *priv = (void *)engine;
 	struct nvc0_graph_data *data = priv->mmio_data;
 	struct nvc0_graph_mmio *mmio = priv->mmio_list;
-	struct nvc0_graph_chan *grch;
-	struct nouveau_gpuobj *grctx;
+	struct nvc0_graph_chan *chan;
 	int ret, i;
 
-	grch = kzalloc(sizeof(*grch), GFP_KERNEL);
-	if (!grch)
-		return -ENOMEM;
-	chan->engctx[NVOBJ_ENGINE_GR] = grch;
-
-	ret = nouveau_gpuobj_new(dev, NULL, priv->size, 256, 0, &grch->grctx);
-	if (ret)
-		goto error;
-
-	ret = nouveau_gpuobj_map_vm(grch->grctx, chan->vm, NV_MEM_ACCESS_RW |
-				    NV_MEM_ACCESS_SYS, &grch->grctx_vma);
+	/* allocate memory for context, and fill with default values */
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 0x100,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
 
-	grctx = grch->grctx;
-
 	/* allocate memory for a "mmio list" buffer that's used by the HUB
 	 * fuc to modify some per-context register settings on first load
 	 * of the context.
 	 */
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x100, 0, &grch->mmio);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x100, 0, &chan->mmio);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_map_vm(grch->mmio, chan->vm,
+	ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
 				    NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
-				    &grch->mmio_vma);
+				    &chan->mmio_vma);
 	if (ret)
 		return ret;
 
 	/* allocate buffers referenced by mmio list */
 	for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
-		ret = nouveau_gpuobj_new(dev, NULL, data->size, data->align,
-					 0, &grch->data[i].mem);
+		ret = nouveau_gpuobj_new(parent, NULL, data->size, data->align,
+					 0, &chan->data[i].mem);
 		if (ret)
 			return ret;
 
-		ret = nouveau_gpuobj_map_vm(grch->data[i].mem, chan->vm,
-					    data->access,
-					   &grch->data[i].vma);
+		ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
+					   &chan->data[i].vma);
 		if (ret)
 			return ret;
 
@@ -122,495 +120,193 @@
 		u32 data = mmio->data;
 
 		if (mmio->shift) {
-			u64 info = grch->data[mmio->buffer].vma.offset;
+			u64 info = chan->data[mmio->buffer].vma.offset;
 			data |= info >> mmio->shift;
 		}
 
-		nv_wo32(grch->mmio, grch->mmio_nr++ * 4, addr);
-		nv_wo32(grch->mmio, grch->mmio_nr++ * 4, data);
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
 		mmio++;
 	}
 
 	for (i = 0; i < priv->size; i += 4)
-		nv_wo32(grch->grctx, i, priv->data[i / 4]);
-
-	nv_wo32(chan->ramin, 0x0210, lower_32_bits(grch->grctx_vma.offset) | 4);
-	nv_wo32(chan->ramin, 0x0214, upper_32_bits(grch->grctx_vma.offset));
-	nvimem_flush(dev);
+		nv_wo32(chan, i, priv->data[i / 4]);
 
 	if (!priv->firmware) {
-		nv_wo32(grctx, 0x00, grch->mmio_nr / 2);
-		nv_wo32(grctx, 0x04, grch->mmio_vma.offset >> 8);
+		nv_wo32(chan, 0x00, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
 	} else {
-		nv_wo32(grctx, 0xf4, 0);
-		nv_wo32(grctx, 0xf8, 0);
-		nv_wo32(grctx, 0x10, grch->mmio_nr / 2);
-		nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio_vma.offset));
-		nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio_vma.offset));
-		nv_wo32(grctx, 0x1c, 1);
-		nv_wo32(grctx, 0x20, 0);
-		nv_wo32(grctx, 0x28, 0);
-		nv_wo32(grctx, 0x2c, 0);
+		nv_wo32(chan, 0xf4, 0);
+		nv_wo32(chan, 0xf8, 0);
+		nv_wo32(chan, 0x10, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x1c, 1);
+		nv_wo32(chan, 0x20, 0);
+		nv_wo32(chan, 0x28, 0);
+		nv_wo32(chan, 0x2c, 0);
 	}
-	nvimem_flush(dev);
-	return 0;
 
-error:
-	priv->base.context_del(chan, engine);
-	return ret;
+	return 0;
 }
 
 void
-nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
+nvc0_graph_context_dtor(struct nouveau_object *object)
 {
-	struct nvc0_graph_chan *grch = chan->engctx[engine];
+	struct nvc0_graph_chan *chan = (void *)object;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(grch->data); i++) {
-		nouveau_gpuobj_unmap(&grch->data[i].vma);
-		nouveau_gpuobj_ref(NULL, &grch->data[i].mem);
+	for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
+		nouveau_gpuobj_unmap(&chan->data[i].vma);
+		nouveau_gpuobj_ref(NULL, &chan->data[i].mem);
 	}
 
-	nouveau_gpuobj_unmap(&grch->mmio_vma);
-	nouveau_gpuobj_ref(NULL, &grch->mmio);
+	nouveau_gpuobj_unmap(&chan->mmio_vma);
+	nouveau_gpuobj_ref(NULL, &chan->mmio);
 
-	nouveau_gpuobj_unmap(&grch->grctx_vma);
-	nouveau_gpuobj_ref(NULL, &grch->grctx);
-	chan->engctx[engine] = NULL;
+	nouveau_graph_context_destroy(&chan->base);
 }
 
-static int
-nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
+static struct nouveau_oclass
+nvc0_graph_cclass = {
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
 {
-	return 0;
+	nv_error(priv, "%06x - done 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x400));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
+		 nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
+		 nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
 }
 
-static int
-nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend)
+void
+nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
 {
-	return 0;
+	u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
+	u32 gpc;
+
+	nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
+	for (gpc = 0; gpc < gpcnr; gpc++)
+		nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
 }
 
 static void
-nvc0_graph_init_obj418880(struct drm_device *dev)
+nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
 {
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int i;
-
-	nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nvc0_graph_init_regs(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x400080, 0x003083c2);
-	nv_wr32(dev, 0x400088, 0x00006fe7);
-	nv_wr32(dev, 0x40008c, 0x00000000);
-	nv_wr32(dev, 0x400090, 0x00000030);
-	nv_wr32(dev, 0x40013c, 0x013901f7);
-	nv_wr32(dev, 0x400140, 0x00000100);
-	nv_wr32(dev, 0x400144, 0x00000000);
-	nv_wr32(dev, 0x400148, 0x00000110);
-	nv_wr32(dev, 0x400138, 0x00000000);
-	nv_wr32(dev, 0x400130, 0x00000000);
-	nv_wr32(dev, 0x400134, 0x00000000);
-	nv_wr32(dev, 0x400124, 0x00000002);
-}
-
-static void
-nvc0_graph_init_gpc_0(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8];
-	u8  tpnr[GPC_MAX];
-	int i, gpc, tpc;
-
-	nv_wr32(dev, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */
-
-	/*
-	 *      TP      ROP UNKVAL(magic_not_rop_nr)
-	 * 450: 4/0/0/0 2        3
-	 * 460: 3/4/0/0 4        1
-	 * 465: 3/4/4/0 4        7
-	 * 470: 3/3/4/4 5        5
-	 * 480: 3/4/4/4 6        6
-	 */
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
-	nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
-}
-
-static void
-nvc0_graph_init_units(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x409c24, 0x000f0000);
-	nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */
-	nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */
-	nv_wr32(dev, 0x408030, 0xc0000000);
-	nv_wr32(dev, 0x40601c, 0xc0000000);
-	nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */
-	nv_wr32(dev, 0x406018, 0xc0000000);
-	nv_wr32(dev, 0x405840, 0xc0000000);
-	nv_wr32(dev, 0x405844, 0x00ffffff);
-	nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
-}
-
-static void
-nvc0_graph_init_gpc_1(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int gpc, tp;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tp = 0; tp < priv->tpc_nr[gpc]; tp++) {
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x508), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x50c), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x224), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x48c), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x084), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x644), 0x001ffffe);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x64c), 0x0000000f);
-		}
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nvc0_graph_init_rop(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-static void
-nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
-		    struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-		nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
-	}
-}
-
-static int
-nvc0_graph_init_ctxctl(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 r000260;
-	int i;
-
-	if (priv->firmware) {
-		/* load fuc microcode */
-		r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-		nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c,
-						   &priv->fuc409d);
-		nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac,
-						   &priv->fuc41ad);
-		nv_wr32(dev, 0x000260, r000260);
-
-		/* start both of them running */
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x41a10c, 0x00000000);
-		nv_wr32(dev, 0x40910c, 0x00000000);
-		nv_wr32(dev, 0x41a100, 0x00000002);
-		nv_wr32(dev, 0x409100, 0x00000002);
-		if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
-			NV_INFO(dev, "0x409800 wait failed\n");
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x7fffffff);
-		nv_wr32(dev, 0x409504, 0x00000021);
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000010);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
-			return -EBUSY;
-		}
-		priv->size = nv_rd32(dev, 0x409800);
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000016);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000025);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
-			return -EBUSY;
-		}
-
-		goto done;
-	}
-
-	/* load HUB microcode */
-	r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-	nv_wr32(dev, 0x4091c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
-		nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]);
-
-	nv_wr32(dev, 0x409180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, 0x409188, i >> 6);
-		nv_wr32(dev, 0x409184, nvc0_grhub_code[i]);
-	}
-
-	/* load GPC microcode */
-	nv_wr32(dev, 0x41a1c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
-		nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]);
-
-	nv_wr32(dev, 0x41a180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, 0x41a188, i >> 6);
-		nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]);
-	}
-	nv_wr32(dev, 0x000260, r000260);
-
-	/* start HUB ucode running, it'll init the GPCs */
-	nv_wr32(dev, 0x409800, dev_priv->chipset);
-	nv_wr32(dev, 0x40910c, 0x00000000);
-	nv_wr32(dev, 0x409100, 0x00000002);
-	if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
-		NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n");
-		nvc0_graph_ctxctl_debug(dev);
-		return -EBUSY;
-	}
-
-	priv->size = nv_rd32(dev, 0x409804);
-done:
-	if (priv->data == NULL) {
-		int ret = nvc0_grctx_generate(dev);
-		if (ret) {
-			NV_ERROR(dev, "PGRAPH: failed to construct context\n");
-			return ret;
-		}
-
-		return 1;
-	}
-
-	return 0;
-}
-
-static int
-nvc0_graph_init(struct drm_device *dev, int engine)
-{
-	int ret;
-
-reset:
-	nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
-
-	nvc0_graph_init_obj418880(dev);
-	nvc0_graph_init_regs(dev);
-	/*nvc0_graph_init_unitplemented_magics(dev);*/
-	nvc0_graph_init_gpc_0(dev);
-	/*nvc0_graph_init_unitplemented_c242(dev);*/
-
-	nv_wr32(dev, 0x400500, 0x00010001);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-
-	nvc0_graph_init_units(dev);
-	nvc0_graph_init_gpc_1(dev);
-	nvc0_graph_init_rop(dev);
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400118, 0xffffffff);
-	nv_wr32(dev, 0x400130, 0xffffffff);
-	nv_wr32(dev, 0x40011c, 0xffffffff);
-	nv_wr32(dev, 0x400134, 0xffffffff);
-	nv_wr32(dev, 0x400054, 0x34ce3464);
-
-	ret = nvc0_graph_init_ctxctl(dev);
-	if (ret) {
-		if (ret == 1)
-			goto reset;
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nvc0_graph_ctxctl_isr(struct drm_device *dev)
-{
-	u32 ustat = nv_rd32(dev, 0x409c18);
+	u32 ustat = nv_rd32(priv, 0x409c18);
 
 	if (ustat & 0x00000001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
+		nv_error(priv, "CTXCTRL ucode error\n");
 	if (ustat & 0x00080000)
-		NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
+		nv_error(priv, "CTXCTRL watchdog timeout\n");
 	if (ustat & ~0x00080001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
+		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
 
-	nvc0_graph_ctxctl_debug(dev);
-	nv_wr32(dev, 0x409c20, ustat);
+	nvc0_graph_ctxctl_debug(priv);
+	nv_wr32(priv, 0x409c20, ustat);
 }
 
 static void
-nvc0_graph_isr(struct drm_device *dev)
+nvc0_graph_intr(struct nouveau_subdev *subdev)
 {
-	u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-	u32 chid = nvc0_graph_isr_chid(dev, inst);
-	u32 stat = nv_rd32(dev, 0x400100);
-	u32 addr = nv_rd32(dev, 0x400704);
+	struct nvc0_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u32 addr = nv_rd32(priv, 0x400704);
 	u32 mthd = (addr & 0x00003ffc);
 	u32 subc = (addr & 0x00070000) >> 16;
-	u32 data = nv_rd32(dev, 0x400708);
-	u32 code = nv_rd32(dev, 0x400110);
-	u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 code = nv_rd32(priv, 0x400110);
+	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
 
 	if (stat & 0x00000010) {
-		if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
-			NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (!handle || nv_call(handle->object, mthd, data)) {
+			nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
 				     "subc %d class 0x%04x mthd 0x%04x "
 				     "data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
+				 inst, subc, class, mthd, data);
 		}
-		nv_wr32(dev, 0x400100, 0x00000010);
+		nouveau_engctx_handle_put(handle);
+		nv_wr32(priv, 0x400100, 0x00000010);
 		stat &= ~0x00000010;
 	}
 
 	if (stat & 0x00000020) {
-		NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+		nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
 			     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00000020);
+			inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00000020);
 		stat &= ~0x00000020;
 	}
 
 	if (stat & 0x00100000) {
-		NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+		nv_error(priv, "DATA_ERROR [");
 		nouveau_enum_print(nv50_data_error_names, code);
-		printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+		printk("] ch 0x%010llx subc %d class 0x%04x "
 		       "mthd 0x%04x data 0x%08x\n",
-		       chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00100000);
+		       inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00100000);
 		stat &= ~0x00100000;
 	}
 
 	if (stat & 0x00200000) {
-		u32 trap = nv_rd32(dev, 0x400108);
-		NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap);
-		nv_wr32(dev, 0x400108, trap);
-		nv_wr32(dev, 0x400100, 0x00200000);
+		u32 trap = nv_rd32(priv, 0x400108);
+		nv_error(priv, "TRAP ch 0x%010llx status 0x%08x\n", inst, trap);
+		nv_wr32(priv, 0x400108, trap);
+		nv_wr32(priv, 0x400100, 0x00200000);
 		stat &= ~0x00200000;
 	}
 
 	if (stat & 0x00080000) {
-		nvc0_graph_ctxctl_isr(dev);
-		nv_wr32(dev, 0x400100, 0x00080000);
+		nvc0_graph_ctxctl_isr(priv);
+		nv_wr32(priv, 0x400100, 0x00080000);
 		stat &= ~0x00080000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
-		nv_wr32(dev, 0x400100, stat);
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, 0x400100, stat);
 	}
 
-	nv_wr32(dev, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400500, 0x00010001);
 }
 
-static int
-nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
-		     struct nvc0_graph_fuc *fuc)
+int
+nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
+		   struct nvc0_graph_fuc *fuc)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = nv_device(priv);
 	const struct firmware *fw;
 	char f[32];
 	int ret;
 
-	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
-	ret = request_firmware(&fw, f, &dev->pdev->dev);
+	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
+	ret = request_firmware(&fw, f, &device->pdev->dev);
 	if (ret) {
 		snprintf(f, sizeof(f), "nouveau/%s", fwname);
-		ret = request_firmware(&fw, f, &dev->pdev->dev);
+		ret = request_firmware(&fw, f, &device->pdev->dev);
 		if (ret) {
-			NV_ERROR(dev, "failed to load %s\n", fwname);
+			nv_error(priv, "failed to load %s\n", fwname);
 			return ret;
 		}
 	}
@@ -621,99 +317,77 @@
 	return (fuc->data != NULL) ? 0 : -ENOMEM;
 }
 
-static void
-nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+static int
+nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
 {
-	if (fuc->data) {
-		kfree(fuc->data);
-		fuc->data = NULL;
-	}
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
-
-	nvc0_graph_destroy_fw(&priv->fuc409c);
-	nvc0_graph_destroy_fw(&priv->fuc409d);
-	nvc0_graph_destroy_fw(&priv->fuc41ac);
-	nvc0_graph_destroy_fw(&priv->fuc41ad);
-
-	nouveau_irq_unregister(dev, 12);
-
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-	if (priv->data)
-		kfree(priv->data);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(priv);
-}
-
-int
-nvc0_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = nv_device(parent);
 	struct nvc0_graph_priv *priv;
-	int ret, gpc, i;
-	u32 fermi;
+	bool enable = true;
+	int ret, i;
 
-	fermi = nvc0_graph_class(dev);
-	if (!fermi) {
-		NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-		return 0;
+	switch (device->chipset) {
+	case 0xd9: /* known broken without binary driver firmware */
+		enable = false;
+		break;
+	default:
+		break;
 	}
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	ret = nouveau_graph_create(parent, engine, oclass, enable, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	priv->base.destroy = nvc0_graph_destroy;
-	priv->base.init = nvc0_graph_init;
-	priv->base.fini = nvc0_graph_fini;
-	priv->base.context_new = nvc0_graph_context_new;
-	priv->base.context_del = nvc0_graph_context_del;
-	priv->base.object_new = nvc0_graph_object_new;
+	nv_subdev(priv)->unit = 0x18001000;
+	nv_subdev(priv)->intr = nvc0_graph_intr;
+	nv_engine(priv)->cclass = &nvc0_graph_cclass;
 
-	NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
-	nouveau_irq_register(dev, 12, nvc0_graph_isr);
-
-	if (nouveau_ctxfw) {
-		NV_INFO(dev, "PGRAPH: using external firmware\n");
-		if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
-		    nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
-		    nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
-		    nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
-			ret = 0;
-			goto error;
-		}
+	if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) {
+		nv_info(priv, "using external firmware\n");
+		if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
+		    nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
+		    nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
+		    nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
+			return -EINVAL;
 		priv->firmware = true;
 	}
 
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
-	if (ret)
-		goto error;
+	switch (nvc0_graph_class(priv)) {
+	case 0x9097:
+		nv_engine(priv)->sclass = nvc0_graph_sclass;
+		break;
+	case 0x9197:
+		nv_engine(priv)->sclass = nvc1_graph_sclass;
+		break;
+	case 0x9297:
+		nv_engine(priv)->sclass = nvc8_graph_sclass;
+		break;
+	}
 
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
 	if (ret)
-		goto error;
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+	if (ret)
+		return ret;
 
 	for (i = 0; i < 0x1000; i += 4) {
 		nv_wo32(priv->unk4188b4, i, 0x00000010);
 		nv_wo32(priv->unk4188b8, i, 0x00000010);
 	}
 
-	priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
-	priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-		priv->tpc_total += priv->tpc_nr[gpc];
+	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
+	for (i = 0; i < priv->gpc_nr; i++) {
+		priv->tpc_nr[i]  = nv_rd32(priv, GPC_UNIT(i, 0x2608));
+		priv->tpc_total += priv->tpc_nr[i];
 	}
 
-	/*XXX: these need figuring out... */
-	switch (dev_priv->chipset) {
+	/*XXX: these need figuring out... though it might not even matter */
+	switch (nv_device(priv)->chipset) {
 	case 0xc0:
 		if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
 			priv->magic_not_rop_nr = 0x07;
@@ -748,24 +422,348 @@
 		break;
 	}
 
-	if (!priv->magic_not_rop_nr) {
-		NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-			 priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
-			 priv->tpc_nr[3], priv->rop_nr);
-		priv->magic_not_rop_nr = 0x00;
+	return 0;
+}
+
+static void
+nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
+{
+	if (fuc->data) {
+		kfree(fuc->data);
+		fuc->data = NULL;
+	}
+}
+
+void
+nvc0_graph_dtor(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+
+	if (priv->data)
+		kfree(priv->data);
+
+	nvc0_graph_dtor_fw(&priv->fuc409c);
+	nvc0_graph_dtor_fw(&priv->fuc409d);
+	nvc0_graph_dtor_fw(&priv->fuc41ac);
+	nvc0_graph_dtor_fw(&priv->fuc41ad);
+
+	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+	nouveau_graph_destroy(&priv->base);
+}
+
+static void
+nvc0_graph_init_obj418880(struct nvc0_graph_priv *priv)
+{
+	int i;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+}
+
+static void
+nvc0_graph_init_regs(struct nvc0_graph_priv *priv)
+{
+	nv_wr32(priv, 0x400080, 0x003083c2);
+	nv_wr32(priv, 0x400088, 0x00006fe7);
+	nv_wr32(priv, 0x40008c, 0x00000000);
+	nv_wr32(priv, 0x400090, 0x00000030);
+	nv_wr32(priv, 0x40013c, 0x013901f7);
+	nv_wr32(priv, 0x400140, 0x00000100);
+	nv_wr32(priv, 0x400144, 0x00000000);
+	nv_wr32(priv, 0x400148, 0x00000110);
+	nv_wr32(priv, 0x400138, 0x00000000);
+	nv_wr32(priv, 0x400130, 0x00000000);
+	nv_wr32(priv, 0x400134, 0x00000000);
+	nv_wr32(priv, 0x400124, 0x00000002);
+}
+
+static void
+nvc0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
+{
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8];
+	u8  tpcnr[GPC_MAX];
+	int i, gpc, tpc;
+
+	nv_wr32(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */
+
+	/*
+	 *      TP      ROP UNKVAL(magic_not_rop_nr)
+	 * 450: 4/0/0/0 2        3
+	 * 460: 3/4/0/0 4        1
+	 * 465: 3/4/4/0 4        7
+	 * 470: 3/3/4/4 5        5
+	 * 480: 3/4/4/4 6        6
+	 */
+
+	memset(data, 0x00, sizeof(data));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
 	}
 
-	NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
-	NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-	NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
-	if (fermi >= 0x9197)
-		NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */
-	if (fermi >= 0x9297)
-		NVOBJ_CLASS(dev, 0x9297, GR); /* 3D (NVC8-) */
-	NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
-	return 0;
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
 
-error:
-	nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
-	return ret;
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
+						  priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
 }
+
+static void
+nvc0_graph_init_units(struct nvc0_graph_priv *priv)
+{
+	nv_wr32(priv, 0x409c24, 0x000f0000);
+	nv_wr32(priv, 0x404000, 0xc0000000); /* DISPATCH */
+	nv_wr32(priv, 0x404600, 0xc0000000); /* M2MF */
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x40601c, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000); /* MACRO */
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+}
+
+static void
+nvc0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
+{
+	int gpc, tpc;
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+}
+
+static void
+nvc0_graph_init_rop(struct nvc0_graph_priv *priv)
+{
+	int rop;
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+}
+
+void
+nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
+		   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
+{
+	int i;
+
+	nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
+	for (i = 0; i < data->size / 4; i++)
+		nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
+
+	nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
+	for (i = 0; i < code->size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, fuc_base + 0x0188, i >> 6);
+		nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
+	}
+}
+
+static int
+nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
+{
+	u32 r000260;
+	int i;
+
+	if (priv->firmware) {
+		/* load fuc microcode */
+		r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+		nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c,
+						   &priv->fuc409d);
+		nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac,
+						   &priv->fuc41ad);
+		nv_wr32(priv, 0x000260, r000260);
+
+		/* start both of them running */
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x41a10c, 0x00000000);
+		nv_wr32(priv, 0x40910c, 0x00000000);
+		nv_wr32(priv, 0x41a100, 0x00000002);
+		nv_wr32(priv, 0x409100, 0x00000002);
+		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
+			nv_info(priv, "0x409800 wait failed\n");
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x7fffffff);
+		nv_wr32(priv, 0x409504, 0x00000021);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000010);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x10 timeout\n");
+			return -EBUSY;
+		}
+		priv->size = nv_rd32(priv, 0x409800);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000016);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x16 timeout\n");
+			return -EBUSY;
+		}
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000025);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x25 timeout\n");
+			return -EBUSY;
+		}
+
+		if (priv->data == NULL) {
+			int ret = nvc0_grctx_generate(priv);
+			if (ret) {
+				nv_error(priv, "failed to construct context\n");
+				return ret;
+			}
+		}
+
+		return 0;
+	}
+
+	/* load HUB microcode */
+	r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x4091c0, 0x01000000);
+	for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
+		nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]);
+
+	nv_wr32(priv, 0x409180, 0x01000000);
+	for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x409188, i >> 6);
+		nv_wr32(priv, 0x409184, nvc0_grhub_code[i]);
+	}
+
+	/* load GPC microcode */
+	nv_wr32(priv, 0x41a1c0, 0x01000000);
+	for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
+		nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]);
+
+	nv_wr32(priv, 0x41a180, 0x01000000);
+	for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x41a188, i >> 6);
+		nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]);
+	}
+	nv_wr32(priv, 0x000260, r000260);
+
+	/* start HUB ucode running, it'll init the GPCs */
+	nv_wr32(priv, 0x409800, nv_device(priv)->chipset);
+	nv_wr32(priv, 0x40910c, 0x00000000);
+	nv_wr32(priv, 0x409100, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+		nv_error(priv, "HUB_INIT timed out\n");
+		nvc0_graph_ctxctl_debug(priv);
+		return -EBUSY;
+	}
+
+	priv->size = nv_rd32(priv, 0x409804);
+	if (priv->data == NULL) {
+		int ret = nvc0_grctx_generate(priv);
+		if (ret) {
+			nv_error(priv, "failed to construct context\n");
+			return ret;
+		}
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+nvc0_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+	int ret;
+
+reset:
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nvc0_graph_init_obj418880(priv);
+	nvc0_graph_init_regs(priv);
+	/*nvc0_graph_init_unitplemented_magics(priv);*/
+	nvc0_graph_init_gpc_0(priv);
+	/*nvc0_graph_init_unitplemented_c242(priv);*/
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nvc0_graph_init_units(priv);
+	nvc0_graph_init_gpc_1(priv);
+	nvc0_graph_init_rop(priv);
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+
+	ret = nvc0_graph_init_ctxctl(priv);
+	if (ret) {
+		if (ret == 1)
+			goto reset;
+		return ret;
+	}
+
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
index 30ea3ab..26f8268 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
@@ -25,6 +25,18 @@
 #ifndef __NVC0_GRAPH_H__
 #define __NVC0_GRAPH_H__
 
+#include <core/client.h>
+#include <core/handle.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+
 #define GPC_MAX 4
 #define TPC_MAX 32
 
@@ -53,7 +65,7 @@
 };
 
 struct nvc0_graph_priv {
-	struct nouveau_exec_engine base;
+	struct nouveau_graph base;
 
 	struct nvc0_graph_fuc fuc409c;
 	struct nvc0_graph_fuc fuc409d;
@@ -78,11 +90,10 @@
 };
 
 struct nvc0_graph_chan {
-	struct nouveau_gpuobj *grctx;
-	struct nouveau_vma     grctx_vma;
+	struct nouveau_graph_chan base;
 
 	struct nouveau_gpuobj *mmio;
-	struct nouveau_vma     mmio_vma;
+	struct nouveau_vma mmio_vma;
 	int mmio_nr;
 	struct {
 		struct nouveau_gpuobj *mem;
@@ -91,11 +102,11 @@
 };
 
 static inline u32
-nvc0_graph_class(struct drm_device *priv)
+nvc0_graph_class(void *obj)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
+	struct nouveau_device *device = nv_device(obj);
 
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0xc0:
 	case 0xc3:
 	case 0xc4:
@@ -115,17 +126,16 @@
 	}
 }
 
-void nv_icmd(struct drm_device *priv, u32 icmd, u32 data);
+void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data);
 
 static inline void
-nv_mthd(struct drm_device *priv, u32 class, u32 mthd, u32 data)
+nv_mthd(struct nvc0_graph_priv *priv, u32 class, u32 mthd, u32 data)
 {
 	nv_wr32(priv, 0x40448c, data);
 	nv_wr32(priv, 0x404488, 0x80000000 | (mthd << 14) | class);
 }
 
 struct nvc0_grctx {
-	struct drm_device *dev;
 	struct nvc0_graph_priv *priv;
 	struct nvc0_graph_data *data;
 	struct nvc0_graph_mmio *mmio;
@@ -135,18 +145,18 @@
 	u64 addr;
 };
 
-int  nvc0_grctx_generate(struct drm_device *);
-int  nvc0_grctx_init(struct drm_device *, struct nvc0_graph_priv *,
-		     struct nvc0_grctx *);
+int  nvc0_grctx_generate(struct nvc0_graph_priv *);
+int  nvc0_grctx_init(struct nvc0_graph_priv *, struct nvc0_grctx *);
 void nvc0_grctx_data(struct nvc0_grctx *, u32, u32, u32);
 void nvc0_grctx_mmio(struct nvc0_grctx *, u32, u32, u32, u32);
 int  nvc0_grctx_fini(struct nvc0_grctx *);
 
-int  nve0_grctx_generate(struct drm_device *);
+int  nve0_grctx_generate(struct nvc0_graph_priv *);
 
 #define mmio_data(s,a,p) nvc0_grctx_data(&info, (s), (a), (p))
 #define mmio_list(r,d,s,b) nvc0_grctx_mmio(&info, (r), (d), (s), (b))
 
+void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
 int  nvc0_graph_ctor_fw(struct nvc0_graph_priv *, const char *,
 			struct nvc0_graph_fuc *);
 void nvc0_graph_dtor(struct nouveau_object *);
@@ -157,9 +167,4 @@
 			     struct nouveau_object **);
 void nvc0_graph_context_dtor(struct nouveau_object *);
 
-void nvc0_graph_ctxctl_debug(struct drm_device *);
-
-int  nvc0_graph_context_new(struct nouveau_channel *, int);
-void nvc0_graph_context_del(struct nouveau_channel *, int);
-
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
index a3a4ee7..c79748a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,586 +22,213 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include "drmP.h"
-
-#include "nouveau_drv.h"
-#include <core/mm.h>
-#include <engine/fifo.h>
-
 #include "nvc0.h"
 
-static void
-nve0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
-{
-	NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
-		nv_rd32(dev, base + 0x400));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
-		nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
-		nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nve0_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0xa040, &nouveau_object_ofuncs },
+	{ 0xa097, &nouveau_object_ofuncs },
+	{ 0xa0c0, &nouveau_object_ofuncs },
+	{ 0xa0b5, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nve0_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0xe0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
 
 static void
-nve0_graph_ctxctl_debug(struct drm_device *dev)
+nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
 {
-	u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
-	u32 gpc;
-
-	nve0_graph_ctxctl_debug_unit(dev, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
-}
-
-static int
-nve0_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	return 0;
-}
-
-static int
-nve0_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	return 0;
-}
-
-static void
-nve0_graph_init_obj418880(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int i;
-
-	nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nve0_graph_init_regs(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x400080, 0x003083c2);
-	nv_wr32(dev, 0x400088, 0x0001ffe7);
-	nv_wr32(dev, 0x40008c, 0x00000000);
-	nv_wr32(dev, 0x400090, 0x00000030);
-	nv_wr32(dev, 0x40013c, 0x003901f7);
-	nv_wr32(dev, 0x400140, 0x00000100);
-	nv_wr32(dev, 0x400144, 0x00000000);
-	nv_wr32(dev, 0x400148, 0x00000110);
-	nv_wr32(dev, 0x400138, 0x00000000);
-	nv_wr32(dev, 0x400130, 0x00000000);
-	nv_wr32(dev, 0x400134, 0x00000000);
-	nv_wr32(dev, 0x400124, 0x00000002);
-}
-
-static void
-nve0_graph_init_units(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x409ffc, 0x00000000);
-	nv_wr32(dev, 0x409c14, 0x00003e3e);
-	nv_wr32(dev, 0x409c24, 0x000f0000);
-
-	nv_wr32(dev, 0x404000, 0xc0000000);
-	nv_wr32(dev, 0x404600, 0xc0000000);
-	nv_wr32(dev, 0x408030, 0xc0000000);
-	nv_wr32(dev, 0x404490, 0xc0000000);
-	nv_wr32(dev, 0x406018, 0xc0000000);
-	nv_wr32(dev, 0x407020, 0xc0000000);
-	nv_wr32(dev, 0x405840, 0xc0000000);
-	nv_wr32(dev, 0x405844, 0x00ffffff);
-
-	nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
-
-}
-
-static void
-nve0_graph_init_gpc_0(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8];
-	u8  tpcnr[GPC_MAX];
-	int i, gpc, tpc;
-
-	nv_wr32(dev, GPC_UNIT(0, 0x3018), 0x00000001);
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
-	nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
-}
-
-static void
-nve0_graph_init_gpc_1(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int gpc, tpc;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x3038), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nve0_graph_init_rop(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-static void
-nve0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
-		    struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-		nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
-	}
-}
-
-static int
-nve0_graph_init_ctxctl(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 r000260;
-
-	/* load fuc microcode */
-	r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-	nve0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
-	nve0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
-	nv_wr32(dev, 0x000260, r000260);
-
-	/* start both of them running */
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x41a10c, 0x00000000);
-	nv_wr32(dev, 0x40910c, 0x00000000);
-	nv_wr32(dev, 0x41a100, 0x00000002);
-	nv_wr32(dev, 0x409100, 0x00000002);
-	if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
-		NV_INFO(dev, "0x409800 wait failed\n");
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x7fffffff);
-	nv_wr32(dev, 0x409504, 0x00000021);
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000010);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
-		return -EBUSY;
-	}
-	priv->size = nv_rd32(dev, 0x409800);
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000016);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000025);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000030);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x30 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409810, 0xb00095c8);
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000031);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x31 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409810, 0x00080420);
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000032);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x32 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409614, 0x00000070);
-	nv_wr32(dev, 0x409614, 0x00000770);
-	nv_wr32(dev, 0x40802c, 0x00000001);
-
-	if (priv->data == NULL) {
-		int ret = nve0_grctx_generate(dev);
-		if (ret) {
-			NV_ERROR(dev, "PGRAPH: failed to construct context\n");
-			return ret;
-		}
-
-		return 1;
-	}
-
-	return 0;
-}
-
-static int
-nve0_graph_init(struct drm_device *dev, int engine)
-{
-	int ret;
-
-reset:
-	nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
-
-	nve0_graph_init_obj418880(dev);
-	nve0_graph_init_regs(dev);
-	nve0_graph_init_gpc_0(dev);
-
-	nv_wr32(dev, 0x400500, 0x00010001);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-
-	nve0_graph_init_units(dev);
-	nve0_graph_init_gpc_1(dev);
-	nve0_graph_init_rop(dev);
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400118, 0xffffffff);
-	nv_wr32(dev, 0x400130, 0xffffffff);
-	nv_wr32(dev, 0x40011c, 0xffffffff);
-	nv_wr32(dev, 0x400134, 0xffffffff);
-	nv_wr32(dev, 0x400054, 0x34ce3464);
-
-	ret = nve0_graph_init_ctxctl(dev);
-	if (ret) {
-		if (ret == 1)
-			goto reset;
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-nve0_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nve0_graph_ctxctl_isr(struct drm_device *dev)
-{
-	u32 ustat = nv_rd32(dev, 0x409c18);
+	u32 ustat = nv_rd32(priv, 0x409c18);
 
 	if (ustat & 0x00000001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
+		nv_error(priv, "CTXCTRL ucode error\n");
 	if (ustat & 0x00080000)
-		NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
+		nv_error(priv, "CTXCTRL watchdog timeout\n");
 	if (ustat & ~0x00080001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
+		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
 
-	nve0_graph_ctxctl_debug(dev);
-	nv_wr32(dev, 0x409c20, ustat);
+	nvc0_graph_ctxctl_debug(priv);
+	nv_wr32(priv, 0x409c20, ustat);
 }
 
 static void
-nve0_graph_trap_isr(struct drm_device *dev, int chid)
+nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst)
 {
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 trap = nv_rd32(dev, 0x400108);
+	u32 trap = nv_rd32(priv, 0x400108);
 	int rop;
 
 	if (trap & 0x00000001) {
-		u32 stat = nv_rd32(dev, 0x404000);
-		NV_INFO(dev, "PGRAPH: DISPATCH ch %d 0x%08x\n", chid, stat);
-		nv_wr32(dev, 0x404000, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x00000001);
+		u32 stat = nv_rd32(priv, 0x404000);
+		nv_error(priv, "DISPATCH ch 0x%010llx 0x%08x\n", inst, stat);
+		nv_wr32(priv, 0x404000, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000001);
 		trap &= ~0x00000001;
 	}
 
 	if (trap & 0x00000010) {
-		u32 stat = nv_rd32(dev, 0x405840);
-		NV_INFO(dev, "PGRAPH: SHADER ch %d 0x%08x\n", chid, stat);
-		nv_wr32(dev, 0x405840, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x00000010);
+		u32 stat = nv_rd32(priv, 0x405840);
+		nv_error(priv, "SHADER ch 0x%010llx 0x%08x\n", inst, stat);
+		nv_wr32(priv, 0x405840, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000010);
 		trap &= ~0x00000010;
 	}
 
 	if (trap & 0x02000000) {
 		for (rop = 0; rop < priv->rop_nr; rop++) {
-			u32 statz = nv_rd32(dev, ROP_UNIT(rop, 0x070));
-			u32 statc = nv_rd32(dev, ROP_UNIT(rop, 0x144));
-			NV_INFO(dev, "PGRAPH: ROP%d ch %d 0x%08x 0x%08x\n",
-				     rop, chid, statz, statc);
-			nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-			nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
+			u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
+			u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
+			nv_error(priv, "ROP%d ch 0x%010llx 0x%08x 0x%08x\n",
+				     rop, inst, statz, statc);
+			nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+			nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
 		}
-		nv_wr32(dev, 0x400108, 0x02000000);
+		nv_wr32(priv, 0x400108, 0x02000000);
 		trap &= ~0x02000000;
 	}
 
 	if (trap) {
-		NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap);
-		nv_wr32(dev, 0x400108, trap);
+		nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap);
+		nv_wr32(priv, 0x400108, trap);
 	}
 }
 
 static void
-nve0_graph_isr(struct drm_device *dev)
+nve0_graph_intr(struct nouveau_subdev *subdev)
 {
-	u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-	u32 chid = nve0_graph_isr_chid(dev, inst);
-	u32 stat = nv_rd32(dev, 0x400100);
-	u32 addr = nv_rd32(dev, 0x400704);
+	struct nvc0_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u32 addr = nv_rd32(priv, 0x400704);
 	u32 mthd = (addr & 0x00003ffc);
 	u32 subc = (addr & 0x00070000) >> 16;
-	u32 data = nv_rd32(dev, 0x400708);
-	u32 code = nv_rd32(dev, 0x400110);
-	u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 code = nv_rd32(priv, 0x400110);
+	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
 
 	if (stat & 0x00000010) {
-		if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
-			NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (!handle || nv_call(handle->object, mthd, data)) {
+			nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
 				     "subc %d class 0x%04x mthd 0x%04x "
 				     "data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
+				 inst, subc, class, mthd, data);
 		}
-		nv_wr32(dev, 0x400100, 0x00000010);
+		nouveau_engctx_handle_put(handle);
+		nv_wr32(priv, 0x400100, 0x00000010);
 		stat &= ~0x00000010;
 	}
 
 	if (stat & 0x00000020) {
-		NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+		nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
 			     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00000020);
+			 inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00000020);
 		stat &= ~0x00000020;
 	}
 
 	if (stat & 0x00100000) {
-		NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+		nv_error(priv, "DATA_ERROR [");
 		nouveau_enum_print(nv50_data_error_names, code);
-		printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+		printk("] ch 0x%010llx subc %d class 0x%04x "
 		       "mthd 0x%04x data 0x%08x\n",
-		       chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00100000);
+		       inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00100000);
 		stat &= ~0x00100000;
 	}
 
 	if (stat & 0x00200000) {
-		nve0_graph_trap_isr(dev, chid);
-		nv_wr32(dev, 0x400100, 0x00200000);
+		nve0_graph_trap_isr(priv, inst);
+		nv_wr32(priv, 0x400100, 0x00200000);
 		stat &= ~0x00200000;
 	}
 
 	if (stat & 0x00080000) {
-		nve0_graph_ctxctl_isr(dev);
-		nv_wr32(dev, 0x400100, 0x00080000);
+		nve0_graph_ctxctl_isr(priv);
+		nv_wr32(priv, 0x400100, 0x00080000);
 		stat &= ~0x00080000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
-		nv_wr32(dev, 0x400100, stat);
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, 0x400100, stat);
 	}
 
-	nv_wr32(dev, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400500, 0x00010001);
 }
 
 static int
-nve0_graph_create_fw(struct drm_device *dev, const char *fwname,
-		     struct nvc0_graph_fuc *fuc)
+nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	const struct firmware *fw;
-	char f[32];
-	int ret;
+	struct nvc0_graph_priv *priv;
+	int ret, i;
 
-	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
-	ret = request_firmware(&fw, f, &dev->pdev->dev);
+	ret = nouveau_graph_create(parent, engine, oclass, false, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	fuc->size = fw->size;
-	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
-	release_firmware(fw);
-	return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
+	nv_subdev(priv)->unit = 0x18001000;
+	nv_subdev(priv)->intr = nve0_graph_intr;
+	nv_engine(priv)->cclass = &nve0_graph_cclass;
+	nv_engine(priv)->sclass = nve0_graph_sclass;
 
-static void
-nve0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
-{
-	if (fuc->data) {
-		kfree(fuc->data);
-		fuc->data = NULL;
-	}
-}
-
-static void
-nve0_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
-
-	nve0_graph_destroy_fw(&priv->fuc409c);
-	nve0_graph_destroy_fw(&priv->fuc409d);
-	nve0_graph_destroy_fw(&priv->fuc41ac);
-	nve0_graph_destroy_fw(&priv->fuc41ad);
-
-	nouveau_irq_unregister(dev, 12);
-
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-	if (priv->data)
-		kfree(priv->data);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(priv);
-}
-
-int
-nve0_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_graph_priv *priv;
-	int ret, gpc, i;
-	u32 kepler;
-
-	kepler = nvc0_graph_class(dev);
-	if (!kepler) {
-		NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-		return 0;
-	}
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.destroy = nve0_graph_destroy;
-	priv->base.init = nve0_graph_init;
-	priv->base.fini = nve0_graph_fini;
-	priv->base.context_new = nvc0_graph_context_new;
-	priv->base.context_del = nvc0_graph_context_del;
-	priv->base.object_new = nve0_graph_object_new;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
-	nouveau_irq_register(dev, 12, nve0_graph_isr);
-
-	NV_INFO(dev, "PGRAPH: using external firmware\n");
-	if (nve0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
-	    nve0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
-	    nve0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
-	    nve0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
-		ret = 0;
-		goto error;
-	}
+	nv_info(priv, "using external firmware\n");
+	if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
+	    nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
+	    nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
+	    nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
+		return -EINVAL;
 	priv->firmware = true;
 
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8);
 	if (ret)
-		goto error;
+		return ret;
 
 	for (i = 0; i < 0x1000; i += 4) {
 		nv_wo32(priv->unk4188b4, i, 0x00000010);
 		nv_wo32(priv->unk4188b8, i, 0x00000010);
 	}
 
-	priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
-	priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-		priv->tpc_total += priv->tpc_nr[gpc];
+	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
+	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+	for (i = 0; i < priv->gpc_nr; i++) {
+		priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
+		priv->tpc_total += priv->tpc_nr[i];
 	}
 
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0xe4:
 		if (priv->tpc_total == 8)
 			priv->magic_not_rop_nr = 3;
@@ -616,21 +243,275 @@
 		break;
 	}
 
-	if (!priv->magic_not_rop_nr) {
-		NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-			 priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
-			 priv->tpc_nr[3], priv->rop_nr);
-		priv->magic_not_rop_nr = 0x00;
+	return 0;
+}
+
+static void
+nve0_graph_init_obj418880(struct nvc0_graph_priv *priv)
+{
+	int i;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+}
+
+static void
+nve0_graph_init_regs(struct nvc0_graph_priv *priv)
+{
+	nv_wr32(priv, 0x400080, 0x003083c2);
+	nv_wr32(priv, 0x400088, 0x0001ffe7);
+	nv_wr32(priv, 0x40008c, 0x00000000);
+	nv_wr32(priv, 0x400090, 0x00000030);
+	nv_wr32(priv, 0x40013c, 0x003901f7);
+	nv_wr32(priv, 0x400140, 0x00000100);
+	nv_wr32(priv, 0x400144, 0x00000000);
+	nv_wr32(priv, 0x400148, 0x00000110);
+	nv_wr32(priv, 0x400138, 0x00000000);
+	nv_wr32(priv, 0x400130, 0x00000000);
+	nv_wr32(priv, 0x400134, 0x00000000);
+	nv_wr32(priv, 0x400124, 0x00000002);
+}
+
+static void
+nve0_graph_init_units(struct nvc0_graph_priv *priv)
+{
+	nv_wr32(priv, 0x409ffc, 0x00000000);
+	nv_wr32(priv, 0x409c14, 0x00003e3e);
+	nv_wr32(priv, 0x409c24, 0x000f0000);
+
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x407020, 0xc0000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+}
+
+static void
+nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
+{
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8];
+	u8  tpcnr[GPC_MAX];
+	int i, gpc, tpc;
+
+	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+	memset(data, 0x00, sizeof(data));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
 	}
 
-	NVOBJ_CLASS(dev, 0xa097, GR); /* subc 0: 3D */
-	NVOBJ_CLASS(dev, 0xa0c0, GR); /* subc 1: COMPUTE */
-	NVOBJ_CLASS(dev, 0xa040, GR); /* subc 2: P2MF */
-	NVOBJ_CLASS(dev, 0x902d, GR); /* subc 3: 2D */
-	NVOBJ_CLASS(dev, 0xa0b5, GR); /* subc 4: COPY */
-	return 0;
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
 
-error:
-	nve0_graph_destroy(dev, NVOBJ_ENGINE_GR);
-	return ret;
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
+						  priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
 }
+
+static void
+nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
+{
+	int gpc, tpc;
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+}
+
+static void
+nve0_graph_init_rop(struct nvc0_graph_priv *priv)
+{
+	int rop;
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+}
+
+static int
+nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
+{
+	u32 r000260;
+
+	/* load fuc microcode */
+	r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+	nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d);
+	nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
+	nv_wr32(priv, 0x000260, r000260);
+
+	/* start both of them running */
+	nv_wr32(priv, 0x409840, 0xffffffff);
+	nv_wr32(priv, 0x41a10c, 0x00000000);
+	nv_wr32(priv, 0x40910c, 0x00000000);
+	nv_wr32(priv, 0x41a100, 0x00000002);
+	nv_wr32(priv, 0x409100, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
+		nv_error(priv, "0x409800 wait failed\n");
+
+	nv_wr32(priv, 0x409840, 0xffffffff);
+	nv_wr32(priv, 0x409500, 0x7fffffff);
+	nv_wr32(priv, 0x409504, 0x00000021);
+
+	nv_wr32(priv, 0x409840, 0xffffffff);
+	nv_wr32(priv, 0x409500, 0x00000000);
+	nv_wr32(priv, 0x409504, 0x00000010);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x10 timeout\n");
+		return -EBUSY;
+	}
+	priv->size = nv_rd32(priv, 0x409800);
+
+	nv_wr32(priv, 0x409840, 0xffffffff);
+	nv_wr32(priv, 0x409500, 0x00000000);
+	nv_wr32(priv, 0x409504, 0x00000016);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x16 timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x409840, 0xffffffff);
+	nv_wr32(priv, 0x409500, 0x00000000);
+	nv_wr32(priv, 0x409504, 0x00000025);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x25 timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x409800, 0x00000000);
+	nv_wr32(priv, 0x409500, 0x00000001);
+	nv_wr32(priv, 0x409504, 0x00000030);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x30 timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x409810, 0xb00095c8);
+	nv_wr32(priv, 0x409800, 0x00000000);
+	nv_wr32(priv, 0x409500, 0x00000001);
+	nv_wr32(priv, 0x409504, 0x00000031);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x31 timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x409810, 0x00080420);
+	nv_wr32(priv, 0x409800, 0x00000000);
+	nv_wr32(priv, 0x409500, 0x00000001);
+	nv_wr32(priv, 0x409504, 0x00000032);
+	if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+		nv_error(priv, "fuc09 req 0x32 timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x409614, 0x00000070);
+	nv_wr32(priv, 0x409614, 0x00000770);
+	nv_wr32(priv, 0x40802c, 0x00000001);
+
+	if (priv->data == NULL) {
+		int ret = nve0_grctx_generate(priv);
+		if (ret) {
+			nv_error(priv, "failed to construct context\n");
+			return ret;
+		}
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+nve0_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+	int ret;
+
+reset:
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nve0_graph_init_obj418880(priv);
+	nve0_graph_init_regs(priv);
+	nve0_graph_init_gpc_0(priv);
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nve0_graph_init_units(priv);
+	nve0_graph_init_gpc_1(priv);
+	nve0_graph_init_rop(priv);
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+
+	ret = nve0_graph_init_ctxctl(priv);
+	if (ret) {
+		if (ret == 1)
+			goto reset;
+		return ret;
+	}
+
+	return 0;
+}
+
+struct nouveau_oclass
+nve0_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0xe0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nve0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nve0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
new file mode 100644
index 0000000..9c715a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
@@ -0,0 +1,269 @@
+#ifndef __NOUVEAU_GRAPH_REGS_H__
+#define __NOUVEAU_GRAPH_REGS_H__
+
+#define NV04_PGRAPH_DEBUG_0                                0x00400080
+#define NV04_PGRAPH_DEBUG_1                                0x00400084
+#define NV04_PGRAPH_DEBUG_2                                0x00400088
+#define NV04_PGRAPH_DEBUG_3                                0x0040008c
+#define NV10_PGRAPH_DEBUG_4                                0x00400090
+#define NV03_PGRAPH_INTR                                   0x00400100
+#define NV03_PGRAPH_NSTATUS                                0x00400104
+#    define NV04_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<11)
+#    define NV04_PGRAPH_NSTATUS_INVALID_STATE                 (1<<12)
+#    define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<13)
+#    define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<14)
+#    define NV10_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<23)
+#    define NV10_PGRAPH_NSTATUS_INVALID_STATE                 (1<<24)
+#    define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<25)
+#    define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<26)
+#define NV03_PGRAPH_NSOURCE                                0x00400108
+#    define NV03_PGRAPH_NSOURCE_NOTIFICATION                   (1<<0)
+#    define NV03_PGRAPH_NSOURCE_DATA_ERROR                     (1<<1)
+#    define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR               (1<<2)
+#    define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION                (1<<3)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_COLOR                    (1<<4)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_ZETA                     (1<<5)
+#    define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD                   (1<<6)
+#    define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION               (1<<7)
+#    define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION               (1<<8)
+#    define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION               (1<<9)
+#    define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION               (1<<10)
+#    define NV03_PGRAPH_NSOURCE_STATE_INVALID                 (1<<11)
+#    define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY                 (1<<12)
+#    define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE                 (1<<13)
+#    define NV03_PGRAPH_NSOURCE_METHOD_CNT                    (1<<14)
+#    define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION              (1<<15)
+#    define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION            (1<<16)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A                   (1<<17)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B                   (1<<18)
+#define NV03_PGRAPH_INTR_EN                                0x00400140
+#define NV40_PGRAPH_INTR_EN                                0x0040013C
+#    define NV_PGRAPH_INTR_NOTIFY                              (1<<0)
+#    define NV_PGRAPH_INTR_MISSING_HW                          (1<<4)
+#    define NV_PGRAPH_INTR_CONTEXT_SWITCH                     (1<<12)
+#    define NV_PGRAPH_INTR_BUFFER_NOTIFY                      (1<<16)
+#    define NV_PGRAPH_INTR_ERROR                              (1<<20)
+#define NV10_PGRAPH_CTX_CONTROL                            0x00400144
+#define NV10_PGRAPH_CTX_USER                               0x00400148
+#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
+#define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160	\
+							   + 0x4*(i) + 0x20*(j))
+#define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
+#define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
+#define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
+#define NV04_PGRAPH_CTX_CONTROL                            0x00400170
+#define NV04_PGRAPH_CTX_USER                               0x00400174
+#define NV04_PGRAPH_CTX_CACHE1                             0x00400180
+#define NV03_PGRAPH_CTX_CONTROL                            0x00400190
+#define NV03_PGRAPH_CTX_USER                               0x00400194
+#define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
+#define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
+#define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
+#define NV40_PGRAPH_CTXCTL_0304                            0x00400304
+#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK              0xff000000
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT                     24
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK              0x00ffffff
+#define NV40_PGRAPH_CTXCTL_0310                            0x00400310
+#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE                  0x00000020
+#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD                  0x00000040
+#define NV40_PGRAPH_CTXCTL_030C                            0x0040030c
+#define NV40_PGRAPH_CTXCTL_UCODE_INDEX                     0x00400324
+#define NV40_PGRAPH_CTXCTL_UCODE_DATA                      0x00400328
+#define NV40_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV40_PGRAPH_CTXCTL_CUR_LOADED                      0x01000000
+#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE                    0x000FFFFF
+#define NV40_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x000fffff
+#define NV50_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV50_PGRAPH_CTXCTL_CUR_LOADED                      0x80000000
+#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE                    0x00ffffff
+#define NV50_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x00ffffff
+#define NV03_PGRAPH_ABS_X_RAM                              0x00400400
+#define NV03_PGRAPH_ABS_Y_RAM                              0x00400480
+#define NV03_PGRAPH_X_MISC                                 0x00400500
+#define NV03_PGRAPH_Y_MISC                                 0x00400504
+#define NV04_PGRAPH_VALID1                                 0x00400508
+#define NV04_PGRAPH_SOURCE_COLOR                           0x0040050C
+#define NV04_PGRAPH_MISC24_0                               0x00400510
+#define NV03_PGRAPH_XY_LOGIC_MISC0                         0x00400514
+#define NV03_PGRAPH_XY_LOGIC_MISC1                         0x00400518
+#define NV03_PGRAPH_XY_LOGIC_MISC2                         0x0040051C
+#define NV03_PGRAPH_XY_LOGIC_MISC3                         0x00400520
+#define NV03_PGRAPH_CLIPX_0                                0x00400524
+#define NV03_PGRAPH_CLIPX_1                                0x00400528
+#define NV03_PGRAPH_CLIPY_0                                0x0040052C
+#define NV03_PGRAPH_CLIPY_1                                0x00400530
+#define NV03_PGRAPH_ABS_ICLIP_XMAX                         0x00400534
+#define NV03_PGRAPH_ABS_ICLIP_YMAX                         0x00400538
+#define NV03_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C
+#define NV03_PGRAPH_ABS_UCLIP_YMIN                         0x00400540
+#define NV03_PGRAPH_ABS_UCLIP_XMAX                         0x00400544
+#define NV03_PGRAPH_ABS_UCLIP_YMAX                         0x00400548
+#define NV03_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560
+#define NV03_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564
+#define NV03_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568
+#define NV03_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C
+#define NV04_PGRAPH_MISC24_1                               0x00400570
+#define NV04_PGRAPH_MISC24_2                               0x00400574
+#define NV04_PGRAPH_VALID2                                 0x00400578
+#define NV04_PGRAPH_PASSTHRU_0                             0x0040057C
+#define NV04_PGRAPH_PASSTHRU_1                             0x00400580
+#define NV04_PGRAPH_PASSTHRU_2                             0x00400584
+#define NV10_PGRAPH_DIMX_TEXTURE                           0x00400588
+#define NV10_PGRAPH_WDIMX_TEXTURE                          0x0040058C
+#define NV04_PGRAPH_COMBINE_0_ALPHA                        0x00400590
+#define NV04_PGRAPH_COMBINE_0_COLOR                        0x00400594
+#define NV04_PGRAPH_COMBINE_1_ALPHA                        0x00400598
+#define NV04_PGRAPH_COMBINE_1_COLOR                        0x0040059C
+#define NV04_PGRAPH_FORMAT_0                               0x004005A8
+#define NV04_PGRAPH_FORMAT_1                               0x004005AC
+#define NV04_PGRAPH_FILTER_0                               0x004005B0
+#define NV04_PGRAPH_FILTER_1                               0x004005B4
+#define NV03_PGRAPH_MONO_COLOR0                            0x00400600
+#define NV04_PGRAPH_ROP3                                   0x00400604
+#define NV04_PGRAPH_BETA_AND                               0x00400608
+#define NV04_PGRAPH_BETA_PREMULT                           0x0040060C
+#define NV04_PGRAPH_LIMIT_VIOL_PIX                         0x00400610
+#define NV04_PGRAPH_FORMATS                                0x00400618
+#define NV10_PGRAPH_DEBUG_2                                0x00400620
+#define NV04_PGRAPH_BOFFSET0                               0x00400640
+#define NV04_PGRAPH_BOFFSET1                               0x00400644
+#define NV04_PGRAPH_BOFFSET2                               0x00400648
+#define NV04_PGRAPH_BOFFSET3                               0x0040064C
+#define NV04_PGRAPH_BOFFSET4                               0x00400650
+#define NV04_PGRAPH_BOFFSET5                               0x00400654
+#define NV04_PGRAPH_BBASE0                                 0x00400658
+#define NV04_PGRAPH_BBASE1                                 0x0040065C
+#define NV04_PGRAPH_BBASE2                                 0x00400660
+#define NV04_PGRAPH_BBASE3                                 0x00400664
+#define NV04_PGRAPH_BBASE4                                 0x00400668
+#define NV04_PGRAPH_BBASE5                                 0x0040066C
+#define NV04_PGRAPH_BPITCH0                                0x00400670
+#define NV04_PGRAPH_BPITCH1                                0x00400674
+#define NV04_PGRAPH_BPITCH2                                0x00400678
+#define NV04_PGRAPH_BPITCH3                                0x0040067C
+#define NV04_PGRAPH_BPITCH4                                0x00400680
+#define NV04_PGRAPH_BLIMIT0                                0x00400684
+#define NV04_PGRAPH_BLIMIT1                                0x00400688
+#define NV04_PGRAPH_BLIMIT2                                0x0040068C
+#define NV04_PGRAPH_BLIMIT3                                0x00400690
+#define NV04_PGRAPH_BLIMIT4                                0x00400694
+#define NV04_PGRAPH_BLIMIT5                                0x00400698
+#define NV04_PGRAPH_BSWIZZLE2                              0x0040069C
+#define NV04_PGRAPH_BSWIZZLE5                              0x004006A0
+#define NV03_PGRAPH_STATUS                                 0x004006B0
+#define NV04_PGRAPH_STATUS                                 0x00400700
+#    define NV40_PGRAPH_STATUS_SYNC_STALL                  0x00004000
+#define NV04_PGRAPH_TRAPPED_ADDR                           0x00400704
+#define NV04_PGRAPH_TRAPPED_DATA                           0x00400708
+#define NV04_PGRAPH_SURFACE                                0x0040070C
+#define NV10_PGRAPH_TRAPPED_DATA_HIGH                      0x0040070C
+#define NV04_PGRAPH_STATE                                  0x00400710
+#define NV10_PGRAPH_SURFACE                                0x00400710
+#define NV04_PGRAPH_NOTIFY                                 0x00400714
+#define NV10_PGRAPH_STATE                                  0x00400714
+#define NV10_PGRAPH_NOTIFY                                 0x00400718
+
+#define NV04_PGRAPH_FIFO                                   0x00400720
+
+#define NV04_PGRAPH_BPIXEL                                 0x00400724
+#define NV10_PGRAPH_RDI_INDEX                              0x00400750
+#define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
+#define NV10_PGRAPH_RDI_DATA                               0x00400754
+#define NV04_PGRAPH_DMA_PITCH                              0x00400760
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
+#define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
+#define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
+#define NV10_PGRAPH_DMA_PITCH                              0x00400770
+#define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
+#define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
+#define NV20_PGRAPH_CHANNEL_CTX_TABLE                      0x00400780
+#define NV20_PGRAPH_CHANNEL_CTX_POINTER                    0x00400784
+#define NV20_PGRAPH_CHANNEL_CTX_XFER                       0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD                  0x00000001
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE                  0x00000002
+#define NV04_PGRAPH_PATT_COLOR0                            0x00400800
+#define NV04_PGRAPH_PATT_COLOR1                            0x00400804
+#define NV04_PGRAPH_PATTERN                                0x00400808
+#define NV04_PGRAPH_PATTERN_SHAPE                          0x00400810
+#define NV04_PGRAPH_CHROMA                                 0x00400814
+#define NV04_PGRAPH_CONTROL0                               0x00400818
+#define NV04_PGRAPH_CONTROL1                               0x0040081C
+#define NV04_PGRAPH_CONTROL2                               0x00400820
+#define NV04_PGRAPH_BLEND                                  0x00400824
+#define NV04_PGRAPH_STORED_FMT                             0x00400830
+#define NV04_PGRAPH_PATT_COLORRAM                          0x00400900
+#define NV20_PGRAPH_TILE(i)                                (0x00400900 + (i*16))
+#define NV20_PGRAPH_TLIMIT(i)                              (0x00400904 + (i*16))
+#define NV20_PGRAPH_TSIZE(i)                               (0x00400908 + (i*16))
+#define NV20_PGRAPH_TSTATUS(i)                             (0x0040090C + (i*16))
+#define NV20_PGRAPH_ZCOMP(i)                               (0x00400980 + 4*(i))
+#define NV10_PGRAPH_TILE(i)                                (0x00400B00 + (i*16))
+#define NV10_PGRAPH_TLIMIT(i)                              (0x00400B04 + (i*16))
+#define NV10_PGRAPH_TSIZE(i)                               (0x00400B08 + (i*16))
+#define NV10_PGRAPH_TSTATUS(i)                             (0x00400B0C + (i*16))
+#define NV04_PGRAPH_U_RAM                                  0x00400D00
+#define NV47_PGRAPH_TILE(i)                                (0x00400D00 + (i*16))
+#define NV47_PGRAPH_TLIMIT(i)                              (0x00400D04 + (i*16))
+#define NV47_PGRAPH_TSIZE(i)                               (0x00400D08 + (i*16))
+#define NV47_PGRAPH_TSTATUS(i)                             (0x00400D0C + (i*16))
+#define NV04_PGRAPH_V_RAM                                  0x00400D40
+#define NV04_PGRAPH_W_RAM                                  0x00400D80
+#define NV10_PGRAPH_COMBINER0_IN_ALPHA                     0x00400E40
+#define NV10_PGRAPH_COMBINER1_IN_ALPHA                     0x00400E44
+#define NV10_PGRAPH_COMBINER0_IN_RGB                       0x00400E48
+#define NV10_PGRAPH_COMBINER1_IN_RGB                       0x00400E4C
+#define NV10_PGRAPH_COMBINER_COLOR0                        0x00400E50
+#define NV10_PGRAPH_COMBINER_COLOR1                        0x00400E54
+#define NV10_PGRAPH_COMBINER0_OUT_ALPHA                    0x00400E58
+#define NV10_PGRAPH_COMBINER1_OUT_ALPHA                    0x00400E5C
+#define NV10_PGRAPH_COMBINER0_OUT_RGB                      0x00400E60
+#define NV10_PGRAPH_COMBINER1_OUT_RGB                      0x00400E64
+#define NV10_PGRAPH_COMBINER_FINAL0                        0x00400E68
+#define NV10_PGRAPH_COMBINER_FINAL1                        0x00400E6C
+#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL                  0x00400F00
+#define NV10_PGRAPH_WINDOWCLIP_VERTICAL                    0x00400F20
+#define NV10_PGRAPH_XFMODE0                                0x00400F40
+#define NV10_PGRAPH_XFMODE1                                0x00400F44
+#define NV10_PGRAPH_GLOBALSTATE0                           0x00400F48
+#define NV10_PGRAPH_GLOBALSTATE1                           0x00400F4C
+#define NV10_PGRAPH_PIPE_ADDRESS                           0x00400F50
+#define NV10_PGRAPH_PIPE_DATA                              0x00400F54
+#define NV04_PGRAPH_DMA_START_0                            0x00401000
+#define NV04_PGRAPH_DMA_START_1                            0x00401004
+#define NV04_PGRAPH_DMA_LENGTH                             0x00401008
+#define NV04_PGRAPH_DMA_MISC                               0x0040100C
+#define NV04_PGRAPH_DMA_DATA_0                             0x00401020
+#define NV04_PGRAPH_DMA_DATA_1                             0x00401024
+#define NV04_PGRAPH_DMA_RM                                 0x00401030
+#define NV04_PGRAPH_DMA_A_XLATE_INST                       0x00401040
+#define NV04_PGRAPH_DMA_A_CONTROL                          0x00401044
+#define NV04_PGRAPH_DMA_A_LIMIT                            0x00401048
+#define NV04_PGRAPH_DMA_A_TLB_PTE                          0x0040104C
+#define NV04_PGRAPH_DMA_A_TLB_TAG                          0x00401050
+#define NV04_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054
+#define NV04_PGRAPH_DMA_A_OFFSET                           0x00401058
+#define NV04_PGRAPH_DMA_A_SIZE                             0x0040105C
+#define NV04_PGRAPH_DMA_A_Y_SIZE                           0x00401060
+#define NV04_PGRAPH_DMA_B_XLATE_INST                       0x00401080
+#define NV04_PGRAPH_DMA_B_CONTROL                          0x00401084
+#define NV04_PGRAPH_DMA_B_LIMIT                            0x00401088
+#define NV04_PGRAPH_DMA_B_TLB_PTE                          0x0040108C
+#define NV04_PGRAPH_DMA_B_TLB_TAG                          0x00401090
+#define NV04_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094
+#define NV04_PGRAPH_DMA_B_OFFSET                           0x00401098
+#define NV04_PGRAPH_DMA_B_SIZE                             0x0040109C
+#define NV04_PGRAPH_DMA_B_Y_SIZE                           0x004010A0
+#define NV40_PGRAPH_TILE1(i)                               (0x00406900 + (i*16))
+#define NV40_PGRAPH_TLIMIT1(i)                             (0x00406904 + (i*16))
+#define NV40_PGRAPH_TSIZE1(i)                              (0x00406908 + (i*16))
+#define NV40_PGRAPH_TSTATUS1(i)                            (0x0040690C + (i*16))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
index a0258c7..7a1bc76 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,159 +22,62 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+#include <core/engine/graph/nv40.h>
 
-struct nv31_mpeg_engine {
-	struct nouveau_exec_engine base;
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <subdev/instmem.h>
+
+#include <engine/mpeg.h>
+
+struct nv31_mpeg_priv {
+	struct nouveau_mpeg base;
 	atomic_t refcount;
 };
 
+struct nv31_mpeg_chan {
+	struct nouveau_object base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
 
 static int
-nv31_mpeg_context_new(struct nouveau_channel *chan, int engine)
+nv31_mpeg_object_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
 {
-	struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
-
-	if (!atomic_add_unless(&pmpeg->refcount, 1, 1))
-		return -EBUSY;
-
-	chan->engctx[engine] = (void *)0xdeadcafe;
-	return 0;
-}
-
-static void
-nv31_mpeg_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
-	atomic_dec(&pmpeg->refcount);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nv40_mpeg_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 *ctx = NULL;
-	unsigned long flags;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	NV_DEBUG(dev, "ch%d\n", chan->id);
-
-	ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &ctx);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    20, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
 
-	nv_wo32(ctx, 0x78, 0x02001ec1);
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-	if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
-		nv_wr32(dev, 0x00330c, ctx->addr >> 4);
-	nv_wo32(chan->ramfc, 0x54, ctx->addr >> 4);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	chan->engctx[engine] = ctx;
-	return 0;
-}
-
-static void
-nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nouveau_gpuobj *ctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	unsigned long flags;
-	u32 inst = 0x80000000 | (ctx->addr >> 4);
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
-	if (nv_rd32(dev, 0x00b318) == inst)
-		nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	nouveau_gpuobj_ref(NULL, &ctx);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nv31_mpeg_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 2;
-	obj->class  = class;
-
-	nv_wo32(obj, 0x00, class);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
-}
-
-static int
-nv31_mpeg_init(struct drm_device *dev, int engine)
-{
-	struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
-	int i;
-
-	/* VPE init */
-	nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
-	nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
-	nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
-
-	for (i = 0; i < nvfb_tile_nr(dev); i++)
-		pmpeg->base.set_tile_region(dev, i);
-
-	/* PMPEG init */
-	nv_wr32(dev, 0x00b32c, 0x00000000);
-	nv_wr32(dev, 0x00b314, 0x00000100);
-	nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031);
-	nv_wr32(dev, 0x00b300, 0x02001ec1);
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
-
-	nv_wr32(dev, 0x00b100, 0xffffffff);
-	nv_wr32(dev, 0x00b140, 0xffffffff);
-
-	if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
-		NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
-		return -EBUSY;
-	}
-
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
 	return 0;
 }
 
 static int
-nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
+nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
 {
-	/*XXX: context save? */
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
-	nv_wr32(dev, 0x00b140, 0x00000000);
-	return 0;
-}
-
-static int
-nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct drm_device *dev = chan->dev;
-	u32 inst = data << 4;
-	u32 dma0 = nv_ri32(dev, inst + 0);
-	u32 dma1 = nv_ri32(dev, inst + 4);
-	u32 dma2 = nv_ri32(dev, inst + 8);
+	struct nouveau_instmem *imem = nouveau_instmem(object);
+	struct nv31_mpeg_priv *priv = (void *)object->engine;
+	u32 inst = *(u32 *)arg << 4;
+	u32 dma0 = nv_ro32(imem, inst + 0);
+	u32 dma1 = nv_ro32(imem, inst + 4);
+	u32 dma2 = nv_ro32(imem, inst + 8);
 	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
 	u32 size = dma1 + 1;
 
@@ -184,160 +87,215 @@
 
 	if (mthd == 0x0190) {
 		/* DMA_CMD */
-		nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
-		nv_wr32(dev, 0x00b334, base);
-		nv_wr32(dev, 0x00b324, size);
+		nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+		nv_wr32(priv, 0x00b334, base);
+		nv_wr32(priv, 0x00b324, size);
 	} else
 	if (mthd == 0x01a0) {
 		/* DMA_DATA */
-		nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
-		nv_wr32(dev, 0x00b360, base);
-		nv_wr32(dev, 0x00b364, size);
+		nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+		nv_wr32(priv, 0x00b360, base);
+		nv_wr32(priv, 0x00b364, size);
 	} else {
 		/* DMA_IMAGE, VRAM only */
 		if (dma0 & 0x000c0000)
 			return -EINVAL;
 
-		nv_wr32(dev, 0x00b370, base);
-		nv_wr32(dev, 0x00b374, size);
+		nv_wr32(priv, 0x00b370, base);
+		nv_wr32(priv, 0x00b374, size);
 	}
 
 	return 0;
 }
 
+struct nouveau_ofuncs
+nv31_mpeg_ofuncs = {
+	.ctor = nv31_mpeg_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+struct nouveau_omthds
+nv31_mpeg_omthds[] = {
+	{ 0x0190, nv31_mpeg_mthd_dma },
+	{ 0x01a0, nv31_mpeg_mthd_dma },
+	{ 0x01b0, nv31_mpeg_mthd_dma },
+	{}
+};
+
+struct nouveau_oclass
+nv31_mpeg_sclass[] = {
+	{ 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
 static int
-nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+nv31_mpeg_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *ctx;
-	unsigned long flags;
-	int i;
+	struct nv31_mpeg_priv *priv = (void *)engine;
+	struct nv31_mpeg_chan *chan;
+	int ret;
 
-	/* hardcode drm channel id on nv3x, so swmthd lookup works */
-	if (dev_priv->card_type < NV_40)
-		return 0;
+	if (!atomic_add_unless(&priv->refcount, 1, 1))
+		return -EBUSY;
 
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		if (!dev_priv->channels.ptr[i])
-			continue;
+	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-		ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
-		if (ctx && ctx->addr == inst)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
+	return 0;
 }
 
 static void
-nv31_vpe_set_tile_region(struct drm_device *dev, int i)
+nv31_mpeg_context_dtor(struct nouveau_object *object)
 {
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-	nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
-	nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
-	nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+	struct nv31_mpeg_priv *priv = (void *)object->engine;
+	struct nv31_mpeg_chan *chan = (void *)object;
+	atomic_dec(&priv->refcount);
+	nouveau_object_destroy(&chan->base);
 }
 
-static void
-nv31_mpeg_isr(struct drm_device *dev)
+static struct nouveau_oclass
+nv31_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x31),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv31_mpeg_context_ctor,
+		.dtor = nv31_mpeg_context_dtor,
+		.init = nouveau_object_init,
+		.fini = nouveau_object_fini,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+void
+nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i)
 {
-	u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
-	u32 chid = nv31_mpeg_isr_chid(dev, inst);
-	u32 stat = nv_rd32(dev, 0x00b100);
-	u32 type = nv_rd32(dev, 0x00b230);
-	u32 mthd = nv_rd32(dev, 0x00b234);
-	u32 data = nv_rd32(dev, 0x00b238);
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nv31_mpeg_priv *priv = (void *)engine;
+
+	nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
+	nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
+	nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+void
+nv31_mpeg_intr(struct nouveau_subdev *subdev)
+{
+	struct nv31_mpeg_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 inst = (nv_rd32(priv, 0x00b318) & 0x000fffff) << 4;
+	u32 stat = nv_rd32(priv, 0x00b100);
+	u32 type = nv_rd32(priv, 0x00b230);
+	u32 mthd = nv_rd32(priv, 0x00b234);
+	u32 data = nv_rd32(priv, 0x00b238);
 	u32 show = stat;
 
 	if (stat & 0x01000000) {
 		/* happens on initial binding of the object */
-		if (type == 0x00000020 && mthd == 0x0000) {
-			nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+		if (handle && type == 0x00000020 && mthd == 0x0000) {
+			nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
 			show &= ~0x01000000;
 		}
 
-		if (type == 0x00000010) {
-			if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+		if (handle && type == 0x00000010) {
+			handle = nouveau_engctx_lookup_class(engine, inst, 0x3174);
+
+			if (handle && !nv_call(handle->object, mthd, data)) {
+				nouveau_engctx_handle_put(handle);
 				show &= ~0x01000000;
+			}
 		}
 	}
 
-	nv_wr32(dev, 0x00b100, stat);
-	nv_wr32(dev, 0x00b230, 0x00000001);
+	nv_wr32(priv, 0x00b100, stat);
+	nv_wr32(priv, 0x00b230, 0x00000001);
 
-	if (show && nouveau_ratelimit()) {
-		NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			chid, inst, stat, type, mthd, data);
+	if (show) {
+		nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 inst, stat, type, mthd, data);
 	}
 }
 
-static void
-nv31_vpe_isr(struct drm_device *dev)
+static int
+nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	if (nv_rd32(dev, 0x00b100))
-		nv31_mpeg_isr(dev);
+	struct nv31_mpeg_priv *priv;
+	int ret;
 
-	if (nv_rd32(dev, 0x00b800)) {
-		u32 stat = nv_rd32(dev, 0x00b800);
-		NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
-		nv_wr32(dev, 0xb800, stat);
-	}
-}
+	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-static void
-nv31_mpeg_destroy(struct drm_device *dev, int engine)
-{
-	struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 0);
-
-	NVOBJ_ENGINE_DEL(dev, MPEG);
-	kfree(pmpeg);
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv31_mpeg_intr;
+	nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+	nv_engine(priv)->sclass = nv31_mpeg_sclass;
+	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+	return 0;
 }
 
 int
-nv31_mpeg_create(struct drm_device *dev)
+nv31_mpeg_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv31_mpeg_engine *pmpeg;
+	struct nouveau_engine *engine = nv_engine(object->engine);
+	struct nv31_mpeg_priv *priv = (void *)engine;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	int ret, i;
 
-	pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
-	if (!pmpeg)
-		return -ENOMEM;
-	atomic_set(&pmpeg->refcount, 0);
+	ret = nouveau_mpeg_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pmpeg->base.destroy = nv31_mpeg_destroy;
-	pmpeg->base.init = nv31_mpeg_init;
-	pmpeg->base.fini = nv31_mpeg_fini;
-	if (dev_priv->card_type < NV_40) {
-		pmpeg->base.context_new = nv31_mpeg_context_new;
-		pmpeg->base.context_del = nv31_mpeg_context_del;
-	} else {
-		pmpeg->base.context_new = nv40_mpeg_context_new;
-		pmpeg->base.context_del = nv40_mpeg_context_del;
+	/* VPE init */
+	nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+	nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	/* PMPEG init */
+	nv_wr32(priv, 0x00b32c, 0x00000000);
+	nv_wr32(priv, 0x00b314, 0x00000100);
+	nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+	nv_wr32(priv, 0x00b300, 0x02001ec1);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+	nv_wr32(priv, 0x00b100, 0xffffffff);
+	nv_wr32(priv, 0x00b140, 0xffffffff);
+
+	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
+		return -EBUSY;
 	}
-	pmpeg->base.object_new = nv31_mpeg_object_new;
 
-	/* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
-	 * all VPE engines, for this driver's purposes the PMPEG engine
-	 * will be treated as the "master" and handle the global VPE
-	 * bits too
-	 */
-	pmpeg->base.set_tile_region = nv31_vpe_set_tile_region;
-	nouveau_irq_register(dev, 0, nv31_vpe_isr);
-
-	NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
-	NVOBJ_CLASS(dev, 0x3174, MPEG);
-	NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma);
-	NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma);
-	NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma);
-
-#if 0
-	NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
-	NVOBJ_CLASS(dev, 0x4075, ME);
-#endif
 	return 0;
-
 }
+
+struct nouveau_oclass
+nv31_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x31),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv31_mpeg_ctor,
+		.dtor = _nouveau_mpeg_dtor,
+		.init = nv31_mpeg_init,
+		.fini = _nouveau_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
new file mode 100644
index 0000000..1241857
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <subdev/instmem.h>
+
+#include <engine/mpeg.h>
+#include <engine/graph/nv40.h>
+
+struct nv40_mpeg_priv {
+	struct nouveau_mpeg base;
+};
+
+struct nv40_mpeg_chan {
+	struct nouveau_mpeg base;
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv40_mpeg_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nv40_mpeg_chan *chan;
+	int ret;
+
+	ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
+					  264 * 4, 16,
+					  NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv40_mpeg_context_fini(struct nouveau_object *object, bool suspend)
+{
+
+	struct nv40_mpeg_priv *priv = (void *)object->engine;
+	struct nv40_mpeg_chan *chan = (void *)object;
+	u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
+
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
+	if (nv_rd32(priv, 0x00b318) == inst)
+		nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv40_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_mpeg_context_ctor,
+		.dtor = _nouveau_mpeg_context_dtor,
+		.init = _nouveau_mpeg_context_init,
+		.fini = nv40_mpeg_context_fini,
+		.rd32 = _nouveau_mpeg_context_rd32,
+		.wr32 = _nouveau_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_mpeg_intr(struct nouveau_subdev *subdev)
+{
+	struct nv40_mpeg_priv *priv = (void *)subdev;
+	u32 stat;
+
+	if ((stat = nv_rd32(priv, 0x00b100)))
+		nv31_mpeg_intr(subdev);
+
+	if ((stat = nv_rd32(priv, 0x00b800))) {
+		nv_error(priv, "PMSRCH 0x%08x\n", stat);
+		nv_wr32(priv, 0x00b800, stat);
+	}
+}
+
+static int
+nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv40_mpeg_priv *priv;
+	int ret;
+
+	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv40_mpeg_intr;
+	nv_engine(priv)->cclass = &nv40_mpeg_cclass;
+	nv_engine(priv)->sclass = nv31_mpeg_sclass;
+	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv40_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_mpeg_ctor,
+		.dtor = _nouveau_mpeg_dtor,
+		.init = nv31_mpeg_init,
+		.fini = _nouveau_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
index 4e3292e..8678a99 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,218 +22,219 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 
-struct nv50_mpeg_engine {
-	struct nouveau_exec_engine base;
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+#include <engine/mpeg.h>
+
+struct nv50_mpeg_priv {
+	struct nouveau_mpeg base;
 };
 
-static inline u32
-CTX_PTR(struct drm_device *dev, u32 offset)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+struct nv50_mpeg_chan {
+	struct nouveau_mpeg_chan base;
+};
 
-	if (dev_priv->chipset == 0x50)
-		offset += 0x0260;
-	else
-		offset += 0x0060;
-
-	return offset;
-}
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
 
 static int
-nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+nv50_mpeg_object_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *ramin = chan->ramin;
-	struct nouveau_gpuobj *ctx = NULL;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	NV_DEBUG(dev, "ch%d\n", chan->id);
-
-	ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &ctx);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
 
-	nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
-	nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->addr + ctx->size - 1);
-	nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->addr);
-	nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
-	nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
-	nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
-
-	nv_wo32(ctx, 0x70, 0x00801ec1);
-	nv_wo32(ctx, 0x7c, 0x0000037c);
-	nvimem_flush(dev);
-
-	chan->engctx[engine] = ctx;
-	return 0;
-}
-
-static void
-nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nouveau_gpuobj *ctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	int i;
-
-	for (i = 0x00; i <= 0x14; i += 4)
-		nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
-
-	nouveau_gpuobj_ref(NULL, &ctx);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
-		     u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 2;
-	obj->class  = class;
-
-	nv_wo32(obj, 0x00, class);
+	nv_wo32(obj, 0x00, nv_mclass(obj));
 	nv_wo32(obj, 0x04, 0x00000000);
 	nv_wo32(obj, 0x08, 0x00000000);
 	nv_wo32(obj, 0x0c, 0x00000000);
-	nvimem_flush(dev);
+	return 0;
+}
 
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
+struct nouveau_ofuncs
+nv50_mpeg_ofuncs = {
+	.ctor = nv50_mpeg_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv50_mpeg_sclass[] = {
+	{ 0x3174, &nv50_mpeg_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+int
+nv50_mpeg_context_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nouveau_bar *bar = nouveau_bar(parent);
+	struct nv50_mpeg_chan *chan;
+	int ret;
+
+	ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
+					  0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv_wo32(chan, 0x0070, 0x00801ec1);
+	nv_wo32(chan, 0x007c, 0x0000037c);
+	bar->flush(bar);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv50_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_mpeg_context_ctor,
+		.dtor = _nouveau_mpeg_context_dtor,
+		.init = _nouveau_mpeg_context_init,
+		.fini = _nouveau_mpeg_context_fini,
+		.rd32 = _nouveau_mpeg_context_rd32,
+		.wr32 = _nouveau_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+int
+nv50_mpeg_tlb_flush(struct nouveau_engine *engine)
+{
+	nv50_vm_flush_engine(&engine->base, 0x08);
+	return 0;
+}
+
+void
+nv50_mpeg_intr(struct nouveau_subdev *subdev)
+{
+	struct nv50_mpeg_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x00b100);
+	u32 type = nv_rd32(priv, 0x00b230);
+	u32 mthd = nv_rd32(priv, 0x00b234);
+	u32 data = nv_rd32(priv, 0x00b238);
+	u32 show = stat;
+
+	if (stat & 0x01000000) {
+		/* happens on initial binding of the object */
+		if (type == 0x00000020 && mthd == 0x0000) {
+			nv_wr32(priv, 0x00b308, 0x00000100);
+			show &= ~0x01000000;
+		}
+	}
+
+	if (show) {
+		nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+			stat, type, mthd, data);
+	}
+
+	nv_wr32(priv, 0x00b100, stat);
+	nv_wr32(priv, 0x00b230, 0x00000001);
+	nv50_fb_trap(nouveau_fb(priv), 1);
 }
 
 static void
-nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+nv50_vpe_intr(struct nouveau_subdev *subdev)
 {
-	nv50_vm_flush_engine(dev, 0x08);
+	struct nv50_mpeg_priv *priv = (void *)subdev;
+
+	if (nv_rd32(priv, 0x00b100))
+		nv50_mpeg_intr(subdev);
+
+	if (nv_rd32(priv, 0x00b800)) {
+		u32 stat = nv_rd32(priv, 0x00b800);
+		nv_info(priv, "PMSRCH: 0x%08x\n", stat);
+		nv_wr32(priv, 0xb800, stat);
+	}
 }
 
 static int
-nv50_mpeg_init(struct drm_device *dev, int engine)
+nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	nv_wr32(dev, 0x00b32c, 0x00000000);
-	nv_wr32(dev, 0x00b314, 0x00000100);
-	nv_wr32(dev, 0x00b0e0, 0x0000001a);
+	struct nv50_mpeg_priv *priv;
+	int ret;
 
-	nv_wr32(dev, 0x00b220, 0x00000044);
-	nv_wr32(dev, 0x00b300, 0x00801ec1);
-	nv_wr32(dev, 0x00b390, 0x00000000);
-	nv_wr32(dev, 0x00b394, 0x00000000);
-	nv_wr32(dev, 0x00b398, 0x00000000);
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, 0x00b100, 0xffffffff);
-	nv_wr32(dev, 0x00b140, 0xffffffff);
+	nv_subdev(priv)->unit = 0x00400002;
+	nv_subdev(priv)->intr = nv50_vpe_intr;
+	nv_engine(priv)->cclass = &nv50_mpeg_cclass;
+	nv_engine(priv)->sclass = nv50_mpeg_sclass;
+	nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
+	return 0;
+}
 
-	if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
-		NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+int
+nv50_mpeg_init(struct nouveau_object *object)
+{
+	struct nv50_mpeg_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_mpeg_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x00b32c, 0x00000000);
+	nv_wr32(priv, 0x00b314, 0x00000100);
+	nv_wr32(priv, 0x00b0e0, 0x0000001a);
+
+	nv_wr32(priv, 0x00b220, 0x00000044);
+	nv_wr32(priv, 0x00b300, 0x00801ec1);
+	nv_wr32(priv, 0x00b390, 0x00000000);
+	nv_wr32(priv, 0x00b394, 0x00000000);
+	nv_wr32(priv, 0x00b398, 0x00000000);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+	nv_wr32(priv, 0x00b100, 0xffffffff);
+	nv_wr32(priv, 0x00b140, 0xffffffff);
+
+	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
 		return -EBUSY;
 	}
 
 	return 0;
 }
 
-static int
-nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
-	nv_wr32(dev, 0x00b140, 0x00000000);
-	return 0;
-}
-
-static void
-nv50_mpeg_isr(struct drm_device *dev)
-{
-	u32 stat = nv_rd32(dev, 0x00b100);
-	u32 type = nv_rd32(dev, 0x00b230);
-	u32 mthd = nv_rd32(dev, 0x00b234);
-	u32 data = nv_rd32(dev, 0x00b238);
-	u32 show = stat;
-
-	if (stat & 0x01000000) {
-		/* happens on initial binding of the object */
-		if (type == 0x00000020 && mthd == 0x0000) {
-			nv_wr32(dev, 0x00b308, 0x00000100);
-			show &= ~0x01000000;
-		}
-	}
-
-	if (show && nouveau_ratelimit()) {
-		NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			stat, type, mthd, data);
-	}
-
-	nv_wr32(dev, 0x00b100, stat);
-	nv_wr32(dev, 0x00b230, 0x00000001);
-	nv50_fb_vm_trap(dev, 1);
-}
-
-static void
-nv50_vpe_isr(struct drm_device *dev)
-{
-	if (nv_rd32(dev, 0x00b100))
-		nv50_mpeg_isr(dev);
-
-	if (nv_rd32(dev, 0x00b800)) {
-		u32 stat = nv_rd32(dev, 0x00b800);
-		NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
-		nv_wr32(dev, 0xb800, stat);
-	}
-}
-
-static void
-nv50_mpeg_destroy(struct drm_device *dev, int engine)
-{
-	struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 0);
-
-	NVOBJ_ENGINE_DEL(dev, MPEG);
-	kfree(pmpeg);
-}
-
-int
-nv50_mpeg_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_mpeg_engine *pmpeg;
-
-	pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
-	if (!pmpeg)
-		return -ENOMEM;
-
-	pmpeg->base.destroy = nv50_mpeg_destroy;
-	pmpeg->base.init = nv50_mpeg_init;
-	pmpeg->base.fini = nv50_mpeg_fini;
-	pmpeg->base.context_new = nv50_mpeg_context_new;
-	pmpeg->base.context_del = nv50_mpeg_context_del;
-	pmpeg->base.object_new = nv50_mpeg_object_new;
-	pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
-
-	if (dev_priv->chipset == 0x50) {
-		nouveau_irq_register(dev, 0, nv50_vpe_isr);
-		NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
-		NVOBJ_CLASS(dev, 0x3174, MPEG);
-#if 0
-		NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
-		NVOBJ_CLASS(dev, 0x4075, ME);
-#endif
-	} else {
-		nouveau_irq_register(dev, 0, nv50_mpeg_isr);
-		NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
-		NVOBJ_CLASS(dev, 0x8274, MPEG);
-	}
-
-	return 0;
-
-}
+struct nouveau_oclass
+nv50_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_mpeg_ctor,
+		.dtor = _nouveau_mpeg_dtor,
+		.init = nv50_mpeg_init,
+		.fini = _nouveau_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
new file mode 100644
index 0000000..8f805b4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+#include <engine/mpeg.h>
+
+struct nv84_mpeg_priv {
+	struct nouveau_mpeg base;
+};
+
+struct nv84_mpeg_chan {
+	struct nouveau_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv84_mpeg_sclass[] = {
+	{ 0x8274, &nv50_mpeg_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv84_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_mpeg_context_ctor,
+		.dtor = _nouveau_mpeg_context_dtor,
+		.init = _nouveau_mpeg_context_init,
+		.fini = _nouveau_mpeg_context_fini,
+		.rd32 = _nouveau_mpeg_context_rd32,
+		.wr32 = _nouveau_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv84_mpeg_priv *priv;
+	int ret;
+
+	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv50_mpeg_intr;
+	nv_engine(priv)->cclass = &nv84_mpeg_cclass;
+	nv_engine(priv)->sclass = nv84_mpeg_sclass;
+	nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
+	return 0;
+}
+
+struct nouveau_oclass
+nv84_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_mpeg_ctor,
+		.dtor = _nouveau_mpeg_dtor,
+		.init = nv50_mpeg_init,
+		.fini = _nouveau_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
index 384de6d..50e7e0d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,56 +22,154 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 
-struct nv98_ppp_engine {
-	struct nouveau_exec_engine base;
+#include <engine/ppp.h>
+
+struct nv98_ppp_priv {
+	struct nouveau_ppp base;
 };
 
-static int
-nv98_ppp_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	if (!(nv_rd32(dev, 0x000200) & 0x00000002))
-		return 0;
+struct nv98_ppp_chan {
+	struct nouveau_ppp_chan base;
+};
 
-	nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * PPP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_ppp_sclass[] = {
+	{},
+};
+
+/*******************************************************************************
+ * PPPP context
+ ******************************************************************************/
 
 static int
-nv98_ppp_init(struct drm_device *dev, int engine)
+nv98_ppp_context_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
 {
-	nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+	struct nv98_ppp_chan *priv;
+	int ret;
+
+	ret = nouveau_ppp_context_create(parent, engine, oclass, NULL,
+					 0, 0, 0, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
 static void
-nv98_ppp_destroy(struct drm_device *dev, int engine)
+nv98_ppp_context_dtor(struct nouveau_object *object)
 {
-	struct nv98_ppp_engine *pppp = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, PPP);
-
-	kfree(pppp);
+	struct nv98_ppp_chan *priv = (void *)object;
+	nouveau_ppp_context_destroy(&priv->base);
 }
 
-int
-nv98_ppp_create(struct drm_device *dev)
+static int
+nv98_ppp_context_init(struct nouveau_object *object)
 {
-	struct nv98_ppp_engine *pppp;
+	struct nv98_ppp_chan *priv = (void *)object;
+	int ret;
 
-	pppp = kzalloc(sizeof(*pppp), GFP_KERNEL);
-	if (!pppp)
-		return -ENOMEM;
+	ret = nouveau_ppp_context_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pppp->base.destroy = nv98_ppp_destroy;
-	pppp->base.init = nv98_ppp_init;
-	pppp->base.fini = nv98_ppp_fini;
-
-	NVOBJ_ENGINE_ADD(dev, PPP, &pppp->base);
 	return 0;
 }
+
+static int
+nv98_ppp_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv98_ppp_chan *priv = (void *)object;
+	return nouveau_ppp_context_fini(&priv->base, suspend);
+}
+
+static struct nouveau_oclass
+nv98_ppp_cclass = {
+	.handle = NV_ENGCTX(PPP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_ppp_context_ctor,
+		.dtor = nv98_ppp_context_dtor,
+		.init = nv98_ppp_context_init,
+		.fini = nv98_ppp_context_fini,
+		.rd32 = _nouveau_ppp_context_rd32,
+		.wr32 = _nouveau_ppp_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PPPP engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv98_ppp_intr(struct nouveau_subdev *subdev)
+{
+}
+
+static int
+nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv98_ppp_priv *priv;
+	int ret;
+
+	ret = nouveau_ppp_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00400002;
+	nv_subdev(priv)->intr = nv98_ppp_intr;
+	nv_engine(priv)->cclass = &nv98_ppp_cclass;
+	nv_engine(priv)->sclass = nv98_ppp_sclass;
+	return 0;
+}
+
+static void
+nv98_ppp_dtor(struct nouveau_object *object)
+{
+	struct nv98_ppp_priv *priv = (void *)object;
+	nouveau_ppp_destroy(&priv->base);
+}
+
+static int
+nv98_ppp_init(struct nouveau_object *object)
+{
+	struct nv98_ppp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_ppp_init(&priv->base);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv98_ppp_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv98_ppp_priv *priv = (void *)object;
+	return nouveau_ppp_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv98_ppp_oclass = {
+	.handle = NV_ENGINE(PPP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_ppp_ctor,
+		.dtor = nv98_ppp_dtor,
+		.init = nv98_ppp_init,
+		.fini = nv98_ppp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
new file mode 100644
index 0000000..f48da75
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <engine/software.h>
+#include <engine/fifo.h>
+
+struct nv04_software_priv {
+	struct nouveau_software base;
+};
+
+struct nv04_software_chan {
+	struct nouveau_software_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv04_software_set_ref(struct nouveau_object *object, u32 mthd,
+		      void *data, u32 size)
+{
+	struct nouveau_object *channel = (void *)nv_engctx(object->parent);
+	struct nouveau_fifo_chan *fifo = (void *)channel->parent;
+	atomic_set(&fifo->refcnt, *(u32*)data);
+	return 0;
+}
+
+static int
+nv04_software_flip(struct nouveau_object *object, u32 mthd,
+		   void *args, u32 size)
+{
+	struct nv04_software_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nouveau_omthds
+nv04_software_omthds[] = {
+	{ 0x0150, nv04_software_set_ref },
+	{ 0x0500, nv04_software_flip },
+	{}
+};
+
+static struct nouveau_oclass
+nv04_software_sclass[] = {
+	{ 0x006e, &nouveau_object_ofuncs, nv04_software_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv04_software_context_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
+{
+	struct nv04_software_chan *chan;
+	int ret;
+
+	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nouveau_oclass
+nv04_software_cclass = {
+	.handle = NV_ENGCTX(SW, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_software_context_ctor,
+		.dtor = _nouveau_software_context_dtor,
+		.init = _nouveau_software_context_init,
+		.fini = _nouveau_software_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv04_software_priv *priv;
+	int ret;
+
+	ret = nouveau_software_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nv04_software_cclass;
+	nv_engine(priv)->sclass = nv04_software_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_software_oclass = {
+	.handle = NV_ENGINE(SW, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_software_ctor,
+		.dtor = _nouveau_software_dtor,
+		.init = _nouveau_software_init,
+		.fini = _nouveau_software_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
new file mode 100644
index 0000000..46dada5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <engine/software.h>
+
+struct nv10_software_priv {
+	struct nouveau_software base;
+};
+
+struct nv10_software_chan {
+	struct nouveau_software_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv10_software_flip(struct nouveau_object *object, u32 mthd,
+		   void *args, u32 size)
+{
+	struct nv10_software_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nouveau_omthds
+nv10_software_omthds[] = {
+	{ 0x0500, nv10_software_flip },
+	{}
+};
+
+static struct nouveau_oclass
+nv10_software_sclass[] = {
+	{ 0x016e, &nouveau_object_ofuncs, nv10_software_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv10_software_context_ctor(struct nouveau_object *parent,
+		      struct nouveau_object *engine,
+		      struct nouveau_oclass *oclass, void *data, u32 size,
+		      struct nouveau_object **pobject)
+{
+	struct nv10_software_chan *chan;
+	int ret;
+
+	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nouveau_oclass
+nv10_software_cclass = {
+	.handle = NV_ENGCTX(SW, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_software_context_ctor,
+		.dtor = _nouveau_software_context_dtor,
+		.init = _nouveau_software_context_init,
+		.fini = _nouveau_software_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv10_software_priv *priv;
+	int ret;
+
+	ret = nouveau_software_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nv10_software_cclass;
+	nv_engine(priv)->sclass = nv10_software_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv10_software_oclass = {
+	.handle = NV_ENGINE(SW, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_software_ctor,
+		.dtor = _nouveau_software_dtor,
+		.init = _nouveau_software_init,
+		.fini = _nouveau_software_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
new file mode 100644
index 0000000..6b88971
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/namedb.h>
+#include <core/handle.h>
+#include <core/gpuobj.h>
+
+#include <engine/software.h>
+#include <engine/disp.h>
+
+struct nv50_software_priv {
+	struct nouveau_software base;
+};
+
+struct nv50_software_chan {
+	struct nouveau_software_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
+{
+	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+	struct nouveau_fifo_chan *fifo = (void *)nv_object(chan)->parent;
+	struct nouveau_handle *handle;
+	int ret = -EINVAL;
+
+	handle = nouveau_namedb_get(nv_namedb(fifo), *(u32 *)args);
+	if (!handle)
+		return -ENOENT;
+
+	if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+		struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object);
+		chan->base.vblank.ctxdma = gpuobj->node->offset >> 4;
+		ret = 0;
+	}
+	nouveau_namedb_put(handle);
+	return ret;
+}
+
+static int
+nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
+				 void *args, u32 size)
+{
+	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+	chan->base.vblank.offset = *(u32 *)args;
+	return 0;
+}
+
+static int
+nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
+				void *args, u32 size)
+{
+	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+	chan->base.vblank.value = *(u32 *)args;
+	return 0;
+}
+
+static int
+nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
+				  void *args, u32 size)
+{
+	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+	struct nouveau_disp *disp = nouveau_disp(object);
+	unsigned long flags;
+	u32 crtc = *(u32 *)args;
+
+	if (crtc > 1)
+		return -EINVAL;
+
+	disp->vblank.get(disp->vblank.data, crtc);
+
+	spin_lock_irqsave(&disp->vblank.lock, flags);
+	list_add(&chan->base.vblank.head, &disp->vblank.list);
+	chan->base.vblank.crtc = crtc;
+	spin_unlock_irqrestore(&disp->vblank.lock, flags);
+	return 0;
+}
+
+static int
+nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nouveau_omthds
+nv50_software_omthds[] = {
+	{ 0x018c, nv50_software_mthd_dma_vblsem },
+	{ 0x0400, nv50_software_mthd_vblsem_offset },
+	{ 0x0404, nv50_software_mthd_vblsem_value },
+	{ 0x0408, nv50_software_mthd_vblsem_release },
+	{ 0x0500, nv50_software_mthd_flip },
+	{}
+};
+
+static struct nouveau_oclass
+nv50_software_sclass[] = {
+	{ 0x506e, &nouveau_object_ofuncs, nv50_software_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv50_software_context_ctor(struct nouveau_object *parent,
+			   struct nouveau_object *engine,
+			   struct nouveau_oclass *oclass, void *data, u32 size,
+			   struct nouveau_object **pobject)
+{
+	struct nv50_software_chan *chan;
+	int ret;
+
+	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+	return 0;
+}
+
+static struct nouveau_oclass
+nv50_software_cclass = {
+	.handle = NV_ENGCTX(SW, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_software_context_ctor,
+		.dtor = _nouveau_software_context_dtor,
+		.init = _nouveau_software_context_init,
+		.fini = _nouveau_software_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv50_software_priv *priv;
+	int ret;
+
+	ret = nouveau_software_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nv50_software_cclass;
+	nv_engine(priv)->sclass = nv50_software_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv50_software_oclass = {
+	.handle = NV_ENGINE(SW, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_software_ctor,
+		.dtor = _nouveau_software_dtor,
+		.init = _nouveau_software_init,
+		.fini = _nouveau_software_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
new file mode 100644
index 0000000..e3be78f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012 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 <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+
+#include <engine/software.h>
+#include <engine/disp.h>
+
+struct nvc0_software_priv {
+	struct nouveau_software base;
+};
+
+struct nvc0_software_chan {
+	struct nouveau_software_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
+				 void *args, u32 size)
+{
+	struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
+	u64 data = *(u32 *)args;
+	if (mthd == 0x0400) {
+		chan->base.vblank.offset &= 0x00ffffffffULL;
+		chan->base.vblank.offset |= data << 32;
+	} else {
+		chan->base.vblank.offset &= 0xff00000000ULL;
+		chan->base.vblank.offset |= data;
+	}
+	return 0;
+}
+
+static int
+nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
+				void *args, u32 size)
+{
+	struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
+	chan->base.vblank.value = *(u32 *)args;
+	return 0;
+}
+
+static int
+nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
+				  void *args, u32 size)
+{
+	struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
+	struct nouveau_disp *disp = nouveau_disp(object);
+	unsigned long flags;
+	u32 crtc = *(u32 *)args;
+
+	if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
+		return -EINVAL;
+
+	disp->vblank.get(disp->vblank.data, crtc);
+
+	spin_lock_irqsave(&disp->vblank.lock, flags);
+	list_add(&chan->base.vblank.head, &disp->vblank.list);
+	chan->base.vblank.crtc = crtc;
+	spin_unlock_irqrestore(&disp->vblank.lock, flags);
+	return 0;
+}
+
+static int
+nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nouveau_omthds
+nvc0_software_omthds[] = {
+	{ 0x0400, nvc0_software_mthd_vblsem_offset },
+	{ 0x0404, nvc0_software_mthd_vblsem_offset },
+	{ 0x0408, nvc0_software_mthd_vblsem_value },
+	{ 0x040c, nvc0_software_mthd_vblsem_release },
+	{ 0x0500, nvc0_software_mthd_flip },
+	{}
+};
+
+static struct nouveau_oclass
+nvc0_software_sclass[] = {
+	{ 0x906e, &nouveau_object_ofuncs, nvc0_software_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nvc0_software_context_ctor(struct nouveau_object *parent,
+			   struct nouveau_object *engine,
+			   struct nouveau_oclass *oclass, void *data, u32 size,
+			   struct nouveau_object **pobject)
+{
+	struct nvc0_software_chan *chan;
+	int ret;
+
+	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+	return 0;
+}
+
+static struct nouveau_oclass
+nvc0_software_cclass = {
+	.handle = NV_ENGCTX(SW, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_software_context_ctor,
+		.dtor = _nouveau_software_context_dtor,
+		.init = _nouveau_software_context_init,
+		.fini = _nouveau_software_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		   struct nouveau_oclass *oclass, void *data, u32 size,
+		   struct nouveau_object **pobject)
+{
+	struct nvc0_software_priv *priv;
+	int ret;
+
+	ret = nouveau_software_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nvc0_software_cclass;
+	nv_engine(priv)->sclass = nvc0_software_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_software_oclass = {
+	.handle = NV_ENGINE(SW, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_software_ctor,
+		.dtor = _nouveau_software_dtor,
+		.init = _nouveau_software_init,
+		.fini = _nouveau_software_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
index 5e164a6..dd23c80 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Red Hat Inc.
+ * Copyright 2012 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"),
@@ -22,61 +22,154 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
 
-/*XXX: This stub is currently used on NV98+ also, as soon as this becomes
- *     more than just an enable/disable stub this needs to be split out to
- *     nv98_vp.c...
- */
+#include <engine/vp.h>
 
-struct nv84_vp_engine {
-	struct nouveau_exec_engine base;
+struct nv84_vp_priv {
+	struct nouveau_vp base;
 };
 
-static int
-nv84_vp_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	if (!(nv_rd32(dev, 0x000200) & 0x00020000))
-		return 0;
+struct nv84_vp_chan {
+	struct nouveau_vp_chan base;
+};
 
-	nv_mask(dev, 0x000200, 0x00020000, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * VP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv84_vp_sclass[] = {
+	{},
+};
+
+/*******************************************************************************
+ * PVP context
+ ******************************************************************************/
 
 static int
-nv84_vp_init(struct drm_device *dev, int engine)
+nv84_vp_context_ctor(struct nouveau_object *parent,
+		     struct nouveau_object *engine,
+		     struct nouveau_oclass *oclass, void *data, u32 size,
+		     struct nouveau_object **pobject)
 {
-	nv_mask(dev, 0x000200, 0x00020000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00020000, 0x00020000);
+	struct nv84_vp_chan *priv;
+	int ret;
+
+	ret = nouveau_vp_context_create(parent, engine, oclass, NULL,
+					0, 0, 0, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
 static void
-nv84_vp_destroy(struct drm_device *dev, int engine)
+nv84_vp_context_dtor(struct nouveau_object *object)
 {
-	struct nv84_vp_engine *pvp = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, VP);
-
-	kfree(pvp);
+	struct nv84_vp_chan *priv = (void *)object;
+	nouveau_vp_context_destroy(&priv->base);
 }
 
-int
-nv84_vp_create(struct drm_device *dev)
+static int
+nv84_vp_context_init(struct nouveau_object *object)
 {
-	struct nv84_vp_engine *pvp;
+	struct nv84_vp_chan *priv = (void *)object;
+	int ret;
 
-	pvp = kzalloc(sizeof(*pvp), GFP_KERNEL);
-	if (!pvp)
-		return -ENOMEM;
+	ret = nouveau_vp_context_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pvp->base.destroy = nv84_vp_destroy;
-	pvp->base.init = nv84_vp_init;
-	pvp->base.fini = nv84_vp_fini;
-
-	NVOBJ_ENGINE_ADD(dev, VP, &pvp->base);
 	return 0;
 }
+
+static int
+nv84_vp_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv84_vp_chan *priv = (void *)object;
+	return nouveau_vp_context_fini(&priv->base, suspend);
+}
+
+static struct nouveau_oclass
+nv84_vp_cclass = {
+	.handle = NV_ENGCTX(VP, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_vp_context_ctor,
+		.dtor = nv84_vp_context_dtor,
+		.init = nv84_vp_context_init,
+		.fini = nv84_vp_context_fini,
+		.rd32 = _nouveau_vp_context_rd32,
+		.wr32 = _nouveau_vp_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PVP engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv84_vp_intr(struct nouveau_subdev *subdev)
+{
+}
+
+static int
+nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	     struct nouveau_oclass *oclass, void *data, u32 size,
+	     struct nouveau_object **pobject)
+{
+	struct nv84_vp_priv *priv;
+	int ret;
+
+	ret = nouveau_vp_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x01020000;
+	nv_subdev(priv)->intr = nv84_vp_intr;
+	nv_engine(priv)->cclass = &nv84_vp_cclass;
+	nv_engine(priv)->sclass = nv84_vp_sclass;
+	return 0;
+}
+
+static void
+nv84_vp_dtor(struct nouveau_object *object)
+{
+	struct nv84_vp_priv *priv = (void *)object;
+	nouveau_vp_destroy(&priv->base);
+}
+
+static int
+nv84_vp_init(struct nouveau_object *object)
+{
+	struct nv84_vp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nouveau_vp_init(&priv->base);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv84_vp_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv84_vp_priv *priv = (void *)object;
+	return nouveau_vp_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv84_vp_oclass = {
+	.handle = NV_ENGINE(VP, 0x84),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv84_vp_ctor,
+		.dtor = nv84_vp_dtor,
+		.init = nv84_vp_init,
+		.fini = nv84_vp_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ramht.h b/drivers/gpu/drm/nouveau/core/include/core/ramht.h
index c82de98..47e4cac 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/ramht.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/ramht.h
@@ -1,55 +1,23 @@
-/*
- * 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
- */
-
 #ifndef __NOUVEAU_RAMHT_H__
 #define __NOUVEAU_RAMHT_H__
 
-struct nouveau_ramht_entry {
-	struct list_head head;
-	struct nouveau_channel *channel;
-	struct nouveau_gpuobj *gpuobj;
-	u32 handle;
-};
+#include <core/gpuobj.h>
 
 struct nouveau_ramht {
-	struct drm_device *dev;
-	struct kref refcount;
-	spinlock_t lock;
-	struct nouveau_gpuobj *gpuobj;
-	struct list_head entries;
+	struct nouveau_gpuobj base;
 	int bits;
 };
 
-extern int  nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *,
-			      struct nouveau_ramht **);
-extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
-			      struct nouveau_channel *unref_channel);
+int  nouveau_ramht_insert(struct nouveau_ramht *, int chid,
+			  u32 handle, u32 context);
+void nouveau_ramht_remove(struct nouveau_ramht *, int cookie);
+int  nouveau_ramht_new(struct nouveau_object *, struct nouveau_object *,
+		       u32 size, u32 align, struct nouveau_ramht **);
 
-extern int  nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
-				 struct nouveau_gpuobj *);
-extern int  nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
-extern struct nouveau_gpuobj *
-nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
+static inline void
+nouveau_ramht_ref(struct nouveau_ramht *obj, struct nouveau_ramht **ref)
+{
+	nouveau_gpuobj_ref(&obj->base, (struct nouveau_gpuobj **)ref);
+}
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
new file mode 100644
index 0000000..75d1ed5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
@@ -0,0 +1,45 @@
+#ifndef __NOUVEAU_BSP_H__
+#define __NOUVEAU_BSP_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_bsp_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_bsp_context_create(p,e,c,g,s,a,f,d)                            \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_bsp_context_destroy(d)                                         \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_bsp_context_init(d)                                            \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_bsp_context_fini(d,s)                                          \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_bsp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_bsp_context_init _nouveau_engctx_init
+#define _nouveau_bsp_context_fini _nouveau_engctx_fini
+#define _nouveau_bsp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_bsp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_bsp {
+	struct nouveau_engine base;
+};
+
+#define nouveau_bsp_create(p,e,c,d)                                            \
+	nouveau_engine_create((p), (e), (c), true, "PBSP", "bsp", (d))
+#define nouveau_bsp_destroy(d)                                                 \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_bsp_init(d)                                                    \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_bsp_fini(d,s)                                                  \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_bsp_dtor _nouveau_engine_dtor
+#define _nouveau_bsp_init _nouveau_engine_init
+#define _nouveau_bsp_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv84_bsp_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
new file mode 100644
index 0000000..23bb9df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
@@ -0,0 +1,47 @@
+#ifndef __NOUVEAU_COPY_H__
+#define __NOUVEAU_COPY_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_copy_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_copy_context_create(p,e,c,g,s,a,f,d)                           \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_copy_context_destroy(d)                                        \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_copy_context_init(d)                                           \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_copy_context_fini(d,s)                                         \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_copy_context_dtor _nouveau_engctx_dtor
+#define _nouveau_copy_context_init _nouveau_engctx_init
+#define _nouveau_copy_context_fini _nouveau_engctx_fini
+#define _nouveau_copy_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_copy_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_copy {
+	struct nouveau_engine base;
+};
+
+#define nouveau_copy_create(p,e,c,y,i,d)                                       \
+	nouveau_engine_create((p), (e), (c), (y), "PCE"#i, "copy"#i, (d))
+#define nouveau_copy_destroy(d)                                                \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_copy_init(d)                                                   \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_copy_fini(d,s)                                                 \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_copy_dtor _nouveau_engine_dtor
+#define _nouveau_copy_init _nouveau_engine_init
+#define _nouveau_copy_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nva3_copy_oclass;
+extern struct nouveau_oclass nvc0_copy0_oclass;
+extern struct nouveau_oclass nvc0_copy1_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
new file mode 100644
index 0000000..e3674743
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
@@ -0,0 +1,46 @@
+#ifndef __NOUVEAU_CRYPT_H__
+#define __NOUVEAU_CRYPT_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_crypt_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_crypt_context_create(p,e,c,g,s,a,f,d)                          \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_crypt_context_destroy(d)                                       \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_crypt_context_init(d)                                          \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_crypt_context_fini(d,s)                                        \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_crypt_context_dtor _nouveau_engctx_dtor
+#define _nouveau_crypt_context_init _nouveau_engctx_init
+#define _nouveau_crypt_context_fini _nouveau_engctx_fini
+#define _nouveau_crypt_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_crypt_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_crypt {
+	struct nouveau_engine base;
+};
+
+#define nouveau_crypt_create(p,e,c,d)                                          \
+	nouveau_engine_create((p), (e), (c), true, "PCRYPT", "crypt", (d))
+#define nouveau_crypt_destroy(d)                                               \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_crypt_init(d)                                                  \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_crypt_fini(d,s)                                                \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_crypt_dtor _nouveau_engine_dtor
+#define _nouveau_crypt_init _nouveau_engine_init
+#define _nouveau_crypt_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv84_crypt_oclass;
+extern struct nouveau_oclass nv98_crypt_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
new file mode 100644
index 0000000..38ec125
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
@@ -0,0 +1,44 @@
+#ifndef __NOUVEAU_DISP_H__
+#define __NOUVEAU_DISP_H__
+
+#include <core/object.h>
+#include <core/engine.h>
+#include <core/device.h>
+
+struct nouveau_disp {
+	struct nouveau_engine base;
+
+	struct {
+		struct list_head list;
+		spinlock_t lock;
+		void (*notify)(void *, int);
+		void (*get)(void *, int);
+		void (*put)(void *, int);
+		void *data;
+	} vblank;
+};
+
+static inline struct nouveau_disp *
+nouveau_disp(void *obj)
+{
+	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
+}
+
+#define nouveau_disp_create(p,e,c,i,x,d)                                       \
+	nouveau_engine_create((p), (e), (c), true, (i), (x), (d))
+#define nouveau_disp_destroy(d)                                                \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_disp_init(d)                                                   \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_disp_fini(d,s)                                                 \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_disp_dtor _nouveau_engine_dtor
+#define _nouveau_disp_init _nouveau_engine_init
+#define _nouveau_disp_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv04_disp_oclass;
+extern struct nouveau_oclass nv50_disp_oclass;
+extern struct nouveau_oclass nvd0_disp_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
new file mode 100644
index 0000000..700ccbb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
@@ -0,0 +1,57 @@
+#ifndef __NOUVEAU_DMAOBJ_H__
+#define __NOUVEAU_DMAOBJ_H__
+
+#include <core/object.h>
+#include <core/engine.h>
+
+struct nouveau_gpuobj;
+
+struct nouveau_dmaobj {
+	struct nouveau_object base;
+	u32 target;
+	u32 access;
+	u64 start;
+	u64 limit;
+};
+
+#define nouveau_dmaobj_create(p,e,c,a,s,d)                                     \
+	nouveau_dmaobj_create_((p), (e), (c), (a), (s), sizeof(**d), (void **)d)
+#define nouveau_dmaobj_destroy(p)                                              \
+	nouveau_object_destroy(&(p)->base)
+#define nouveau_dmaobj_init(p)                                                 \
+	nouveau_object_init(&(p)->base)
+#define nouveau_dmaobj_fini(p,s)                                               \
+	nouveau_object_fini(&(p)->base, (s))
+
+int nouveau_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
+			   struct nouveau_oclass *, void *data, u32 size,
+			   int length, void **);
+
+#define _nouveau_dmaobj_dtor nouveau_object_destroy
+#define _nouveau_dmaobj_init nouveau_object_init
+#define _nouveau_dmaobj_fini nouveau_object_fini
+
+struct nouveau_dmaeng {
+	struct nouveau_engine base;
+	int (*bind)(struct nouveau_dmaeng *, struct nouveau_object *parent,
+		    struct nouveau_dmaobj *, struct nouveau_gpuobj **);
+};
+
+#define nouveau_dmaeng_create(p,e,c,d)                                         \
+	nouveau_engine_create((p), (e), (c), true, "DMAOBJ", "dmaobj", (d))
+#define nouveau_dmaeng_destroy(p)                                              \
+	nouveau_engine_destroy(&(p)->base)
+#define nouveau_dmaeng_init(p)                                                 \
+	nouveau_engine_init(&(p)->base)
+#define nouveau_dmaeng_fini(p,s)                                               \
+	nouveau_engine_fini(&(p)->base, (s))
+
+#define _nouveau_dmaeng_dtor _nouveau_engine_dtor
+#define _nouveau_dmaeng_init _nouveau_engine_init
+#define _nouveau_dmaeng_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv04_dmaeng_oclass;
+extern struct nouveau_oclass nv50_dmaeng_oclass;
+extern struct nouveau_oclass nvc0_dmaeng_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
index ce99cab..65ee929 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
@@ -1,32 +1,109 @@
 #ifndef __NOUVEAU_FIFO_H__
 #define __NOUVEAU_FIFO_H__
 
-struct nouveau_fifo_priv {
-	struct nouveau_exec_engine base;
-	u32 channels;
-};
+#include <core/namedb.h>
+#include <core/gpuobj.h>
+#include <core/engine.h>
 
 struct nouveau_fifo_chan {
+	struct nouveau_namedb base;
+	struct nouveau_dmaobj *pushdma;
+	struct nouveau_gpuobj *pushgpu;
+	void __iomem *user;
+	u32 size;
+	u16 chid;
+	atomic_t refcnt; /* NV04_NVSW_SET_REF */
 };
 
-bool nv04_fifo_cache_pull(struct drm_device *, bool);
-void nv04_fifo_context_del(struct nouveau_channel *, int);
-int  nv04_fifo_fini(struct drm_device *, int, bool);
-int  nv04_fifo_init(struct drm_device *, int);
-void nv04_fifo_isr(struct drm_device *);
-void nv04_fifo_destroy(struct drm_device *, int);
+static inline struct nouveau_fifo_chan *
+nouveau_fifo_chan(void *obj)
+{
+	return (void *)nv_namedb(obj);
+}
 
-void nv50_fifo_playlist_update(struct drm_device *);
-void nv50_fifo_destroy(struct drm_device *, int);
-void nv50_fifo_tlb_flush(struct drm_device *, int);
+#define nouveau_fifo_channel_create(p,e,c,b,a,s,n,m,d)                         \
+	nouveau_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n),        \
+				     (m), sizeof(**d), (void **)d)
+#define nouveau_fifo_channel_init(p)                                           \
+	nouveau_namedb_init(&(p)->base)
+#define nouveau_fifo_channel_fini(p,s)                                         \
+	nouveau_namedb_fini(&(p)->base, (s))
 
-int  nv04_fifo_create(struct drm_device *);
-int  nv10_fifo_create(struct drm_device *);
-int  nv17_fifo_create(struct drm_device *);
-int  nv40_fifo_create(struct drm_device *);
-int  nv50_fifo_create(struct drm_device *);
-int  nv84_fifo_create(struct drm_device *);
-int  nvc0_fifo_create(struct drm_device *);
-int  nve0_fifo_create(struct drm_device *);
+int  nouveau_fifo_channel_create_(struct nouveau_object *,
+				  struct nouveau_object *,
+				  struct nouveau_oclass *,
+				  int bar, u32 addr, u32 size, u32 push,
+				  u32 engmask, int len, void **);
+void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
+
+#define _nouveau_fifo_channel_init _nouveau_namedb_init
+#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
+
+void _nouveau_fifo_channel_dtor(struct nouveau_object *);
+u32  _nouveau_fifo_channel_rd32(struct nouveau_object *, u32);
+void _nouveau_fifo_channel_wr32(struct nouveau_object *, u32, u32);
+
+struct nouveau_fifo_base {
+	struct nouveau_gpuobj base;
+};
+
+#define nouveau_fifo_context_create(p,e,c,g,s,a,f,d)                           \
+	nouveau_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
+#define nouveau_fifo_context_destroy(p)                                        \
+	nouveau_gpuobj_destroy(&(p)->base)
+#define nouveau_fifo_context_init(p)                                           \
+	nouveau_gpuobj_init(&(p)->base)
+#define nouveau_fifo_context_fini(p,s)                                         \
+	nouveau_gpuobj_fini(&(p)->base, (s))
+
+#define _nouveau_fifo_context_dtor _nouveau_gpuobj_dtor
+#define _nouveau_fifo_context_init _nouveau_gpuobj_init
+#define _nouveau_fifo_context_fini _nouveau_gpuobj_fini
+#define _nouveau_fifo_context_rd32 _nouveau_gpuobj_rd32
+#define _nouveau_fifo_context_wr32 _nouveau_gpuobj_wr32
+
+struct nouveau_fifo {
+	struct nouveau_engine base;
+
+	struct nouveau_object **channel;
+	spinlock_t lock;
+	u16 min;
+	u16 max;
+
+	void (*pause)(struct nouveau_fifo *, unsigned long *);
+	void (*start)(struct nouveau_fifo *, unsigned long *);
+};
+
+static inline struct nouveau_fifo *
+nouveau_fifo(void *obj)
+{
+	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_FIFO];
+}
+
+#define nouveau_fifo_create(o,e,c,fc,lc,d)                                     \
+	nouveau_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
+#define nouveau_fifo_init(p)                                                   \
+	nouveau_engine_init(&(p)->base)
+#define nouveau_fifo_fini(p,s)                                                 \
+	nouveau_engine_fini(&(p)->base, (s))
+
+int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *,
+			 struct nouveau_oclass *, int min, int max,
+			 int size, void **);
+void nouveau_fifo_destroy(struct nouveau_fifo *);
+
+#define _nouveau_fifo_init _nouveau_engine_init
+#define _nouveau_fifo_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv04_fifo_oclass;
+extern struct nouveau_oclass nv10_fifo_oclass;
+extern struct nouveau_oclass nv17_fifo_oclass;
+extern struct nouveau_oclass nv40_fifo_oclass;
+extern struct nouveau_oclass nv50_fifo_oclass;
+extern struct nouveau_oclass nv84_fifo_oclass;
+extern struct nouveau_oclass nvc0_fifo_oclass;
+extern struct nouveau_oclass nve0_fifo_oclass;
+
+void nv04_fifo_intr(struct nouveau_subdev *);
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
new file mode 100644
index 0000000..388cfcf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
@@ -0,0 +1,72 @@
+#ifndef __NOUVEAU_GRAPH_H__
+#define __NOUVEAU_GRAPH_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+struct nouveau_graph_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_graph_context_create(p,e,c,g,s,a,f,d)                          \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_graph_context_destroy(d)                                       \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_graph_context_init(d)                                          \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_graph_context_fini(d,s)                                        \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_graph_context_dtor _nouveau_engctx_dtor
+#define _nouveau_graph_context_init _nouveau_engctx_init
+#define _nouveau_graph_context_fini _nouveau_engctx_fini
+#define _nouveau_graph_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_graph_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_graph {
+	struct nouveau_engine base;
+};
+
+static inline struct nouveau_graph *
+nouveau_graph(void *obj)
+{
+	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_GR];
+}
+
+#define nouveau_graph_create(p,e,c,y,d)                                        \
+	nouveau_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d))
+#define nouveau_graph_destroy(d)                                               \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_graph_init(d)                                                  \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_graph_fini(d,s)                                                \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_graph_dtor _nouveau_engine_dtor
+#define _nouveau_graph_init _nouveau_engine_init
+#define _nouveau_graph_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv04_graph_oclass;
+extern struct nouveau_oclass nv10_graph_oclass;
+extern struct nouveau_oclass nv20_graph_oclass;
+extern struct nouveau_oclass nv25_graph_oclass;
+extern struct nouveau_oclass nv2a_graph_oclass;
+extern struct nouveau_oclass nv30_graph_oclass;
+extern struct nouveau_oclass nv34_graph_oclass;
+extern struct nouveau_oclass nv35_graph_oclass;
+extern struct nouveau_oclass nv40_graph_oclass;
+extern struct nouveau_oclass nv50_graph_oclass;
+extern struct nouveau_oclass nvc0_graph_oclass;
+extern struct nouveau_oclass nve0_graph_oclass;
+
+extern struct nouveau_bitfield nv04_graph_nsource[];
+extern struct nouveau_ofuncs nv04_graph_ofuncs;
+bool nv04_graph_idle(void *obj);
+
+extern struct nouveau_bitfield nv10_graph_intr_name[];
+extern struct nouveau_bitfield nv10_graph_nstatus[];
+
+extern struct nouveau_enum nv50_data_error_names[];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
new file mode 100644
index 0000000..bbf0d4a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
@@ -0,0 +1,61 @@
+#ifndef __NOUVEAU_MPEG_H__
+#define __NOUVEAU_MPEG_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_mpeg_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_mpeg_context_create(p,e,c,g,s,a,f,d)                           \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_mpeg_context_destroy(d)                                        \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_mpeg_context_init(d)                                           \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_mpeg_context_fini(d,s)                                         \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_mpeg_context_dtor _nouveau_engctx_dtor
+#define _nouveau_mpeg_context_init _nouveau_engctx_init
+#define _nouveau_mpeg_context_fini _nouveau_engctx_fini
+#define _nouveau_mpeg_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_mpeg_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_mpeg {
+	struct nouveau_engine base;
+};
+
+#define nouveau_mpeg_create(p,e,c,d)                                           \
+	nouveau_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
+#define nouveau_mpeg_destroy(d)                                                \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_mpeg_init(d)                                                   \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_mpeg_fini(d,s)                                                 \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_mpeg_dtor _nouveau_engine_dtor
+#define _nouveau_mpeg_init _nouveau_engine_init
+#define _nouveau_mpeg_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv31_mpeg_oclass;
+extern struct nouveau_oclass nv40_mpeg_oclass;
+extern struct nouveau_oclass nv50_mpeg_oclass;
+extern struct nouveau_oclass nv84_mpeg_oclass;
+
+extern struct nouveau_oclass nv31_mpeg_sclass[];
+void nv31_mpeg_intr(struct nouveau_subdev *);
+void nv31_mpeg_tile_prog(struct nouveau_engine *, int);
+int  nv31_mpeg_init(struct nouveau_object *);
+
+extern struct nouveau_ofuncs nv50_mpeg_ofuncs;
+int  nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
+			    struct nouveau_oclass *, void *, u32,
+			    struct nouveau_object **);
+int  nv50_mpeg_tlb_flush(struct nouveau_engine *);
+void nv50_mpeg_intr(struct nouveau_subdev *);
+int  nv50_mpeg_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
new file mode 100644
index 0000000..74d554f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
@@ -0,0 +1,45 @@
+#ifndef __NOUVEAU_PPP_H__
+#define __NOUVEAU_PPP_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_ppp_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_ppp_context_create(p,e,c,g,s,a,f,d)                            \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_ppp_context_destroy(d)                                         \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_ppp_context_init(d)                                            \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_ppp_context_fini(d,s)                                          \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_ppp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_ppp_context_init _nouveau_engctx_init
+#define _nouveau_ppp_context_fini _nouveau_engctx_fini
+#define _nouveau_ppp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_ppp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_ppp {
+	struct nouveau_engine base;
+};
+
+#define nouveau_ppp_create(p,e,c,d)                                            \
+	nouveau_engine_create((p), (e), (c), true, "PPPP", "ppp", (d))
+#define nouveau_ppp_destroy(d)                                                 \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_ppp_init(d)                                                    \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_ppp_fini(d,s)                                                  \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_ppp_dtor _nouveau_engine_dtor
+#define _nouveau_ppp_init _nouveau_engine_init
+#define _nouveau_ppp_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv98_ppp_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h
new file mode 100644
index 0000000..8d74079
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/software.h
@@ -0,0 +1,58 @@
+#ifndef __NOUVEAU_SOFTWARE_H__
+#define __NOUVEAU_SOFTWARE_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_software_chan {
+	struct nouveau_engctx base;
+
+	struct {
+		struct list_head head;
+		u32 channel;
+		u32 ctxdma;
+		u64 offset;
+		u32 value;
+		u32 crtc;
+	} vblank;
+
+	int (*flip)(void *);
+	void *flip_data;
+};
+
+#define nouveau_software_context_create(p,e,c,d)                               \
+	nouveau_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
+#define nouveau_software_context_destroy(d)                                    \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_software_context_init(d)                                       \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_software_context_fini(d,s)                                     \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_software_context_dtor _nouveau_engctx_dtor
+#define _nouveau_software_context_init _nouveau_engctx_init
+#define _nouveau_software_context_fini _nouveau_engctx_fini
+
+struct nouveau_software {
+	struct nouveau_engine base;
+};
+
+#define nouveau_software_create(p,e,c,d)                                       \
+	nouveau_engine_create((p), (e), (c), true, "SW", "software", (d))
+#define nouveau_software_destroy(d)                                            \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_software_init(d)                                               \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_software_fini(d,s)                                             \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_software_dtor _nouveau_engine_dtor
+#define _nouveau_software_init _nouveau_engine_init
+#define _nouveau_software_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv04_software_oclass;
+extern struct nouveau_oclass nv10_software_oclass;
+extern struct nouveau_oclass nv50_software_oclass;
+extern struct nouveau_oclass nvc0_software_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
new file mode 100644
index 0000000..05cd08f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
@@ -0,0 +1,45 @@
+#ifndef __NOUVEAU_VP_H__
+#define __NOUVEAU_VP_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+
+struct nouveau_vp_chan {
+	struct nouveau_engctx base;
+};
+
+#define nouveau_vp_context_create(p,e,c,g,s,a,f,d)                             \
+	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nouveau_vp_context_destroy(d)                                          \
+	nouveau_engctx_destroy(&(d)->base)
+#define nouveau_vp_context_init(d)                                             \
+	nouveau_engctx_init(&(d)->base)
+#define nouveau_vp_context_fini(d,s)                                           \
+	nouveau_engctx_fini(&(d)->base, (s))
+
+#define _nouveau_vp_context_dtor _nouveau_engctx_dtor
+#define _nouveau_vp_context_init _nouveau_engctx_init
+#define _nouveau_vp_context_fini _nouveau_engctx_fini
+#define _nouveau_vp_context_rd32 _nouveau_engctx_rd32
+#define _nouveau_vp_context_wr32 _nouveau_engctx_wr32
+
+struct nouveau_vp {
+	struct nouveau_engine base;
+};
+
+#define nouveau_vp_create(p,e,c,d)                                             \
+	nouveau_engine_create((p), (e), (c), true, "PVP", "vp", (d))
+#define nouveau_vp_destroy(d)                                                  \
+	nouveau_engine_destroy(&(d)->base)
+#define nouveau_vp_init(d)                                                     \
+	nouveau_engine_init(&(d)->base)
+#define nouveau_vp_fini(d,s)                                                   \
+	nouveau_engine_fini(&(d)->base, (s))
+
+#define _nouveau_vp_dtor _nouveau_engine_dtor
+#define _nouveau_vp_init _nouveau_engine_init
+#define _nouveau_vp_fini _nouveau_engine_fini
+
+extern struct nouveau_oclass nv84_vp_oclass;
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/device.h b/drivers/gpu/drm/nouveau/core/include/subdev/device.h
index 5eec03a..c9e4c4a 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/device.h
@@ -8,7 +8,6 @@
 
 int  nouveau_device_create_(struct pci_dev *, u64 name, const char *sname,
 			    const char *cfg, const char *dbg, int, void **);
-void nouveau_device_destroy(struct nouveau_device **);
 
 int nv04_identify(struct nouveau_device *);
 int nv10_identify(struct nouveau_device *);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
index 2adfcaf..ec7a54e 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
@@ -8,7 +8,6 @@
 struct nouveau_instobj {
 	struct nouveau_object base;
 	struct list_head head;
-	struct nouveau_mm heap;
 	u32 *suspend;
 	u64 addr;
 	u32 size;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
index 81577bb..747781c 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
@@ -73,6 +73,7 @@
 struct nouveau_vmmgr {
 	struct nouveau_subdev base;
 
+	u64 limit;
 	u32 pgt_bits;
 	u8  spg_shift;
 	u8  lpg_shift;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
index 40456b9..d8d1016 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
@@ -241,6 +241,8 @@
 		if (!device->subdev[i]) {
 			ret = nouveau_object_ctor(nv_object(device), NULL,
 						  oclass, NULL, i, &subdev);
+			if (ret == -ENODEV)
+				continue;
 			if (ret)
 				return ret;
 
@@ -404,10 +406,26 @@
 	{}
 };
 
+static void
+nouveau_device_dtor(struct nouveau_object *object)
+{
+	struct nouveau_device *device = (void *)object;
+
+	mutex_lock(&nv_devices_mutex);
+	list_del(&device->head);
+	mutex_unlock(&nv_devices_mutex);
+
+	if (device->base.mmio)
+		iounmap(device->base.mmio);
+
+	nouveau_subdev_destroy(&device->base);
+}
+
 static struct nouveau_oclass
 nouveau_device_oclass = {
 	.handle = NV_SUBDEV(DEVICE, 0x00),
 	.ofuncs = &(struct nouveau_ofuncs) {
+		.dtor = nouveau_device_dtor,
 	},
 };
 
@@ -444,18 +462,3 @@
 	mutex_unlock(&nv_devices_mutex);
 	return ret;
 }
-
-void
-nouveau_device_destroy(struct nouveau_device **pdevice)
-{
-	struct nouveau_device *device = *pdevice;
-	if (device) {
-		mutex_lock(&nv_devices_mutex);
-		list_del(&device->head);
-		mutex_unlock(&nv_devices_mutex);
-		if (device->base.mmio)
-			iounmap(device->base.mmio);
-		nouveau_subdev_destroy(&device->base);
-	}
-	*pdevice = NULL;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c
index 5173c78..693d200 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv04.c
@@ -33,6 +33,12 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/disp.h>
+
 int
 nv04_identify(struct nouveau_device *device)
 {
@@ -47,6 +53,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv04_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv04_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv04_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x05:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -58,6 +69,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv04_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv04_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv04_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown RIVA chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
index c4f2c2d..de6ce89 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
@@ -34,6 +34,12 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/disp.h>
+
 int
 nv10_identify(struct nouveau_device *device)
 {
@@ -49,6 +55,9 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x15:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -61,6 +70,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x16:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -73,6 +87,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x1a:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -85,6 +104,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x11:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -97,6 +121,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x17:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -109,6 +138,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x1f:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -121,6 +155,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x18:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -133,6 +172,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv10_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Celsius chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
index 719b72a..0b30143 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
@@ -34,6 +34,12 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/disp.h>
+
 int
 nv20_identify(struct nouveau_device *device)
 {
@@ -49,6 +55,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv20_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv20_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x25:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -61,6 +72,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv20_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x28:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -73,6 +89,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv20_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x2a:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -85,6 +106,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv20_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Kelvin chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
index 0a1a728..1d5c697 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
@@ -34,6 +34,13 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+
 int
 nv30_identify(struct nouveau_device *device)
 {
@@ -49,6 +56,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x35:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -61,6 +73,11 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x31:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -73,6 +90,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x36:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -85,6 +108,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x34:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -97,6 +126,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv30_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv34_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Rankine chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
index 5e1ef5e..2e071fa 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
@@ -34,6 +34,13 @@
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+
 int
 nv40_identify(struct nouveau_device *device)
 {
@@ -49,6 +56,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x41:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -61,6 +74,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x42:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -73,6 +92,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x43:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -85,6 +110,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x45:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -97,6 +128,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x47:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -109,6 +146,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x49:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -121,6 +164,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x4b:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -133,6 +182,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x44:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -145,6 +200,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x46:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -157,6 +218,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x4a:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -169,6 +236,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x4c:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -181,6 +254,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x4e:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -193,6 +272,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x63:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -205,6 +290,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x67:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -217,6 +308,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	case 0x68:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -229,6 +326,12 @@
 		device->oclass[NVDEV_SUBDEV_FB     ] = &nv40_fb_oclass;
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv10_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Curie chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
index 5e86a2f..5d44b2a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
@@ -35,6 +35,18 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/mpeg.h>
+#include <engine/vp.h>
+#include <engine/crypt.h>
+#include <engine/bsp.h>
+#include <engine/ppp.h>
+#include <engine/copy.h>
+#include <engine/disp.h>
+
 int
 nv50_identify(struct nouveau_device *device)
 {
@@ -51,6 +63,12 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv50_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x84:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -64,6 +82,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x86:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -77,6 +104,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x92:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -90,6 +126,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x94:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -103,6 +148,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x96:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -116,6 +170,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0x98:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -129,6 +192,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xa0:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -142,6 +214,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xaa:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -155,6 +236,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xac:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -168,6 +258,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xa3:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -181,6 +280,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xa5:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -194,6 +303,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xa8:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -207,6 +325,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xaf:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -220,6 +347,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Tesla chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
index 87f4e16..81d6ed5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
@@ -36,6 +36,16 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/vp.h>
+#include <engine/bsp.h>
+#include <engine/ppp.h>
+#include <engine/copy.h>
+#include <engine/disp.h>
+
 int
 nvc0_identify(struct nouveau_device *device)
 {
@@ -53,6 +63,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xc4:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -67,6 +87,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xc3:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -81,6 +111,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xce:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -95,6 +135,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xcf:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -109,6 +159,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xc1:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -123,6 +183,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xc8:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -137,6 +207,16 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
 		break;
 	case 0xd9:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -151,6 +231,15 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
+		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Fermi chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
index ab8346b..f4f5a5a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
@@ -36,6 +36,12 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/disp.h>
+
 int
 nve0_identify(struct nouveau_device *device)
 {
@@ -53,6 +59,11 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
 		break;
 	case 0xe7:
 		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
@@ -67,6 +78,11 @@
 		device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
 		break;
 	default:
 		nv_fatal(device, "unknown Kepler chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
index f44f0f0..ba4d28b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
@@ -139,8 +139,7 @@
 		return ret;
 
 	/* 0x10000-0x18000: reserve for RAMHT */
-	ret = nouveau_gpuobj_new(parent, NULL, 0x08000, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ramht);
+	ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht);
 	if (ret)
 		return ret;
 
@@ -165,7 +164,7 @@
 	struct nv04_instmem_priv *priv = (void *)object;
 	nouveau_gpuobj_ref(NULL, &priv->ramfc);
 	nouveau_gpuobj_ref(NULL, &priv->ramro);
-	nouveau_gpuobj_ref(NULL, &priv->ramht);
+	nouveau_ramht_ref(NULL, &priv->ramht);
 	nouveau_gpuobj_ref(NULL, &priv->vbios);
 	nouveau_mm_fini(&priv->heap);
 	if (priv->iomem)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
index b2f82f9..7983d8d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
@@ -2,6 +2,7 @@
 #define __NV04_INSTMEM_H__
 
 #include <core/gpuobj.h>
+#include <core/ramht.h>
 #include <core/mm.h>
 
 #include <subdev/instmem.h>
@@ -14,11 +15,17 @@
 	struct nouveau_mm heap;
 
 	struct nouveau_gpuobj *vbios;
-	struct nouveau_gpuobj *ramht;
+	struct nouveau_ramht  *ramht;
 	struct nouveau_gpuobj *ramro;
 	struct nouveau_gpuobj *ramfc;
 };
 
+static inline struct nv04_instmem_priv *
+nv04_instmem(void *obj)
+{
+	return (void *)nouveau_instmem(obj);
+}
+
 struct nv04_instobj_priv {
 	struct nouveau_instobj base;
 	struct nouveau_mm_node *mem;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
index 6a22160..73c52eb 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
@@ -87,8 +87,7 @@
 		return ret;
 
 	/* 0x10000-0x18000: reserve for RAMHT */
-	ret = nouveau_gpuobj_new(parent, NULL, 0x08000, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ramht);
+	ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
index b92b3d4..082c11b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
@@ -299,6 +299,7 @@
 
 	fpde = (vma->node->offset >> vmm->pgt_bits);
 	lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
+
 	for (pde = fpde; pde <= lpde; pde++) {
 		struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
 		int big = (vma->node->type != vmm->spg_shift);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
index 6475c02..bfe6766 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
@@ -96,6 +96,7 @@
 		return ret;
 
 	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV04_PDMA_SIZE;
 	priv->base.pgt_bits = 32 - 12;
 	priv->base.spg_shift = 12;
 	priv->base.lpg_shift = 12;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
index 5309303..e21369c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
@@ -10,4 +10,10 @@
 	dma_addr_t null;
 };
 
+static inline struct nv04_vmmgr_priv *
+nv04_vmmgr(void *obj)
+{
+	return (void *)nouveau_vmmgr(obj);
+}
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
index f036770..bbeac8d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
@@ -97,6 +97,7 @@
 		return ret;
 
 	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV41_GART_SIZE;
 	priv->base.pgt_bits = 32 - 12;
 	priv->base.spg_shift = 12;
 	priv->base.lpg_shift = 12;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
index d17f761..d099cde 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
@@ -178,6 +178,7 @@
 		return ret;
 
 	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV44_GART_SIZE;
 	priv->base.pgt_bits = 32 - 12;
 	priv->base.spg_shift = 12;
 	priv->base.lpg_shift = 12;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
index 6e9bcd2..0f0d3a5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
@@ -154,7 +154,6 @@
 	struct nouveau_engine *engine;
 	int i;
 
-#if 0
 	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
 		if (atomic_read(&vm->engref[i])) {
 			engine = nouveau_engine(vm->vmm, i);
@@ -162,11 +161,6 @@
 				engine->tlb_flush(engine);
 		}
 	}
-#else
-	nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x06); /* bar */
-	nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x05); /* fifo */
-	nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x00); /* gr */
-#endif
 }
 
 void
@@ -206,6 +200,7 @@
 	if (ret)
 		return ret;
 
+	priv->base.limit = 1ULL << 40;
 	priv->base.pgt_bits  = 29 - 12;
 	priv->base.spg_shift = 12;
 	priv->base.lpg_shift = 16;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
index a0bc0f6..e48ece2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
@@ -162,6 +162,7 @@
 	if (ret)
 		return ret;
 
+	priv->base.limit = 1ULL << 40;
 	priv->base.pgt_bits  = 27 - 12;
 	priv->base.spg_shift = 12;
 	priv->base.lpg_shift = 17;
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 9b3a461..9e6ced3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -21,23 +21,153 @@
  *
  */
 
-#include "drmP.h"
+#include <core/object.h>
+#include <core/client.h>
+#include <core/device.h>
+#include <core/class.h>
+#include <core/mm.h>
 
-#include "nouveau_drv.h"
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <subdev/instmem.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
+#include "nouveau_gem.h"
+#include "nouveau_chan.h"
 #include "nouveau_abi16.h"
-#include <core/ramht.h>
-#include "nouveau_software.h"
+
+struct nouveau_abi16 *
+nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev)
+{
+	struct nouveau_cli *cli = nouveau_cli(file_priv);
+	mutex_lock(&cli->mutex);
+	if (!cli->abi16) {
+		struct nouveau_abi16 *abi16;
+		cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
+		if (cli->abi16) {
+			INIT_LIST_HEAD(&abi16->channels);
+			abi16->client = nv_object(cli);
+
+			/* allocate device object targeting client's default
+			 * device (ie. the one that belongs to the fd it
+			 * opened)
+			 */
+			if (nouveau_object_new(abi16->client, NVDRM_CLIENT,
+					       NVDRM_DEVICE, 0x0080,
+					       &(struct nv_device_class) {
+						.device = ~0ULL,
+					       },
+					       sizeof(struct nv_device_class),
+					       &abi16->device) == 0)
+				return cli->abi16;
+
+			kfree(cli->abi16);
+			cli->abi16 = NULL;
+		}
+
+		mutex_unlock(&cli->mutex);
+	}
+	return cli->abi16;
+}
+
+int
+nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
+{
+	struct nouveau_cli *cli = (void *)abi16->client;
+	mutex_unlock(&cli->mutex);
+	return ret;
+}
+
+u16
+nouveau_abi16_swclass(struct nouveau_drm *drm)
+{
+	switch (nv_device(drm->device)->card_type) {
+	case NV_04:
+		return 0x006e;
+	case NV_10:
+	case NV_20:
+	case NV_30:
+	case NV_40:
+		return 0x016e;
+	case NV_50:
+		return 0x506e;
+	case NV_C0:
+	case NV_D0:
+	case NV_E0:
+		return 0x906e;
+	}
+
+	return 0x0000;
+}
+
+static void
+nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
+			struct nouveau_abi16_ntfy *ntfy)
+{
+	nouveau_mm_free(&chan->heap, &ntfy->node);
+	list_del(&ntfy->head);
+	kfree(ntfy);
+}
+
+static void
+nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
+			struct nouveau_abi16_chan *chan)
+{
+	struct nouveau_abi16_ntfy *ntfy, *temp;
+
+	/* cleanup notifier state */
+	list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
+		nouveau_abi16_ntfy_fini(chan, ntfy);
+	}
+
+	if (chan->ntfy) {
+		nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
+		drm_gem_object_unreference_unlocked(chan->ntfy->gem);
+	}
+
+	if (chan->heap.block_size)
+		nouveau_mm_fini(&chan->heap);
+
+	/* destroy channel object, all children will be killed too */
+	if (chan->chan) {
+		abi16->handles &= ~(1 << (chan->chan->handle & 0xffff));
+		nouveau_channel_del(&chan->chan);
+	}
+
+	list_del(&chan->head);
+	kfree(chan);
+}
+
+void
+nouveau_abi16_fini(struct nouveau_abi16 *abi16)
+{
+	struct nouveau_cli *cli = (void *)abi16->client;
+	struct nouveau_abi16_chan *chan, *temp;
+
+	/* cleanup channels */
+	list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
+		nouveau_abi16_chan_fini(abi16, chan);
+	}
+
+	/* destroy the device object */
+	nouveau_object_del(abi16->client, NVDRM_CLIENT, NVDRM_DEVICE);
+
+	kfree(cli->abi16);
+	cli->abi16 = NULL;
+}
 
 int
 nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_device *device = nv_device(drm->device);
+	struct nouveau_timer *ptimer = nouveau_timer(device);
 	struct drm_nouveau_getparam *getparam = data;
 
 	switch (getparam->param) {
 	case NOUVEAU_GETPARAM_CHIPSET_ID:
-		getparam->value = dev_priv->chipset;
+		getparam->value = device->chipset;
 		break;
 	case NOUVEAU_GETPARAM_PCI_VENDOR:
 		getparam->value = dev->pci_vendor;
@@ -55,16 +185,16 @@
 			getparam->value = 2;
 		break;
 	case NOUVEAU_GETPARAM_FB_SIZE:
-		getparam->value = dev_priv->fb_available_size;
+		getparam->value = drm->gem.vram_available;
 		break;
 	case NOUVEAU_GETPARAM_AGP_SIZE:
-		getparam->value = dev_priv->gart_info.aper_size;
+		getparam->value = drm->gem.gart_available;
 		break;
 	case NOUVEAU_GETPARAM_VM_VRAM_BASE:
 		getparam->value = 0; /* deprecated */
 		break;
 	case NOUVEAU_GETPARAM_PTIMER_TIME:
-		getparam->value = nv_timer_read(dev);
+		getparam->value = ptimer->read(ptimer);
 		break;
 	case NOUVEAU_GETPARAM_HAS_BO_USAGE:
 		getparam->value = 1;
@@ -76,13 +206,13 @@
 		/* NV40 and NV50 versions are quite different, but register
 		 * address is the same. User is supposed to know the card
 		 * family anyway... */
-		if (dev_priv->chipset >= 0x40) {
-			getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS);
+		if (device->chipset >= 0x40) {
+			getparam->value = nv_rd32(device, 0x001540);
 			break;
 		}
 		/* FALLTHRU */
 	default:
-		NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
+		nv_debug(device, "unknown parameter %lld\n", getparam->param);
 		return -EINVAL;
 	}
 
@@ -98,148 +228,247 @@
 int
 nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct drm_nouveau_channel_alloc *init = data;
-	struct nouveau_channel *chan;
+	struct nouveau_cli *cli = nouveau_cli(file_priv);
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_abi16_chan *chan;
+	struct nouveau_client *client;
+	struct nouveau_device *device;
+	struct nouveau_instmem *imem;
+	struct nouveau_fb *pfb;
 	int ret;
 
-	if (!dev_priv->eng[NVOBJ_ENGINE_GR])
-		return -ENODEV;
+	if (unlikely(!abi16))
+		return -ENOMEM;
+	client = nv_client(abi16->client);
 
 	if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
-		return -EINVAL;
+		return nouveau_abi16_put(abi16, -EINVAL);
 
-	ret = nouveau_channel_alloc(dev, &chan, file_priv,
-				    init->fb_ctxdma_handle,
-				    init->tt_ctxdma_handle);
+	device = nv_device(abi16->device);
+	imem   = nouveau_instmem(device);
+	pfb    = nouveau_fb(device);
+
+	/* allocate "abi16 channel" data and make up a handle for it */
+	init->channel = ffsll(~abi16->handles);
+	if (!init->channel--)
+		return nouveau_abi16_put(abi16, -ENOSPC);
+
+	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+	if (!chan)
+		return nouveau_abi16_put(abi16, -ENOMEM);
+
+	INIT_LIST_HEAD(&chan->notifiers);
+	list_add(&chan->head, &abi16->channels);
+	abi16->handles |= (1 << init->channel);
+
+	/* create channel object and initialise dma and fence management */
+	ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN |
+				  init->channel, init->fb_ctxdma_handle,
+				  init->tt_ctxdma_handle, &chan->chan);
 	if (ret)
-		return ret;
-	init->channel  = chan->id;
+		goto done;
 
-	if (nouveau_vram_pushbuf == 0) {
-		if (chan->dma.ib_max)
-			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
-						NOUVEAU_GEM_DOMAIN_GART;
-		else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
-			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
-		else
-			init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
-	} else {
+	if (device->card_type >= NV_50)
+		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
+					NOUVEAU_GEM_DOMAIN_GART;
+	else
+	if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
 		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
-	}
+	else
+		init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
 
-	if (dev_priv->card_type < NV_C0) {
+	if (device->card_type < NV_C0) {
 		init->subchan[0].handle = 0x00000000;
 		init->subchan[0].grclass = 0x0000;
 		init->subchan[1].handle = NvSw;
-		init->subchan[1].grclass = NV_SW;
+		init->subchan[1].grclass = 0x506e;
 		init->nr_subchan = 2;
 	}
 
 	/* Named memory object area */
-	ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem,
-				    &init->notifier_handle);
-
+	ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
+			      0, 0, &chan->ntfy);
 	if (ret == 0)
-		atomic_inc(&chan->users); /* userspace reference */
-	nouveau_channel_put(&chan);
-	return ret;
+		ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT);
+	if (ret)
+		goto done;
+
+	if (device->card_type >= NV_50) {
+		ret = nouveau_bo_vma_add(chan->ntfy, client->vm,
+					&chan->ntfy_vma);
+		if (ret)
+			goto done;
+	}
+
+	ret = drm_gem_handle_create(file_priv, chan->ntfy->gem,
+				    &init->notifier_handle);
+	if (ret)
+		goto done;
+
+	ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
+done:
+	if (ret)
+		nouveau_abi16_chan_fini(abi16, chan);
+	return nouveau_abi16_put(abi16, ret);
 }
 
+
 int
 nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
 {
 	struct drm_nouveau_channel_free *req = data;
-	struct nouveau_channel *chan;
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_abi16_chan *chan;
+	int ret = -ENOENT;
 
-	chan = nouveau_channel_get(file_priv, req->channel);
-	if (IS_ERR(chan))
-		return PTR_ERR(chan);
+	if (unlikely(!abi16))
+		return -ENOMEM;
 
-	list_del(&chan->list);
-	atomic_dec(&chan->users);
-	nouveau_channel_put(&chan);
-	return 0;
+	list_for_each_entry(chan, &abi16->channels, head) {
+		if (chan->chan->handle == (NVDRM_CHAN | req->channel)) {
+			nouveau_abi16_chan_fini(abi16, chan);
+			return nouveau_abi16_put(abi16, 0);
+		}
+	}
+
+	return nouveau_abi16_put(abi16, ret);
 }
 
 int
 nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
 {
 	struct drm_nouveau_grobj_alloc *init = data;
-	struct nouveau_channel *chan;
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_object *object;
 	int ret;
 
+	if (unlikely(!abi16))
+		return -ENOMEM;
+
 	if (init->handle == ~0)
-		return -EINVAL;
+		return nouveau_abi16_put(abi16, -EINVAL);
 
 	/* compatibility with userspace that assumes 506e for all chipsets */
 	if (init->class == 0x506e) {
-		init->class = nouveau_software_class(dev);
+		init->class = nouveau_abi16_swclass(drm);
 		if (init->class == 0x906e)
-			return 0;
-	} else
-	if (init->class == 0x906e) {
-		NV_DEBUG(dev, "906e not supported yet\n");
-		return -EINVAL;
+			return nouveau_abi16_put(abi16, 0);
 	}
 
-	chan = nouveau_channel_get(file_priv, init->channel);
-	if (IS_ERR(chan))
-		return PTR_ERR(chan);
-
-	if (nouveau_ramht_find(chan, init->handle)) {
-		ret = -EEXIST;
-		goto out;
-	}
-
-	ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class);
-	if (ret) {
-		NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
-			 ret, init->channel, init->handle);
-	}
-
-out:
-	nouveau_channel_put(&chan);
-	return ret;
+	ret = nouveau_object_new(abi16->client, NVDRM_CHAN | init->channel,
+				  init->handle, init->class, NULL, 0, &object);
+	return nouveau_abi16_put(abi16, ret);
 }
 
 int
 nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct drm_nouveau_notifierobj_alloc *na = data;
-	struct nouveau_channel *chan;
+	struct drm_nouveau_notifierobj_alloc *info = data;
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_device *device = nv_device(drm->device);
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_abi16_chan *chan, *temp;
+	struct nouveau_abi16_ntfy *ntfy;
+	struct nouveau_object *object;
+	struct nv_dma_class args;
 	int ret;
 
+	if (unlikely(!abi16))
+		return -ENOMEM;
+
 	/* completely unnecessary for these chipsets... */
-	if (unlikely(dev_priv->card_type >= NV_C0))
-		return -EINVAL;
+	if (unlikely(nv_device(abi16->device)->card_type >= NV_C0))
+		return nouveau_abi16_put(abi16, -EINVAL);
 
-	chan = nouveau_channel_get(file_priv, na->channel);
-	if (IS_ERR(chan))
-		return PTR_ERR(chan);
+	list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
+		if (chan->chan->handle == (NVDRM_CHAN | info->channel))
+			break;
+		chan = NULL;
+	}
 
-	ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,
-				     &na->offset);
-	nouveau_channel_put(&chan);
-	return ret;
+	if (!chan)
+		return nouveau_abi16_put(abi16, -ENOENT);
+
+	ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
+	if (!ntfy)
+		return nouveau_abi16_put(abi16, -ENOMEM);
+
+	list_add(&ntfy->head, &chan->notifiers);
+	ntfy->handle = info->handle;
+
+	ret = nouveau_mm_head(&chan->heap, 1, info->size, info->size, 1,
+			      &ntfy->node);
+	if (ret)
+		goto done;
+
+	args.start = ntfy->node->offset;
+	args.limit = ntfy->node->offset + ntfy->node->length - 1;
+	if (device->card_type >= NV_50) {
+		args.flags  = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
+		args.start += chan->ntfy_vma.offset;
+		args.limit += chan->ntfy_vma.offset;
+	} else
+	if (drm->agp.stat == ENABLED) {
+		args.flags  = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
+		args.start += drm->agp.base + chan->ntfy->bo.offset;
+		args.limit += drm->agp.base + chan->ntfy->bo.offset;
+	} else {
+		args.flags  = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
+		args.start += chan->ntfy->bo.offset;
+		args.limit += chan->ntfy->bo.offset;
+	}
+
+	ret = nouveau_object_new(abi16->client, chan->chan->handle,
+				 ntfy->handle, 0x003d, &args,
+				 sizeof(args), &object);
+	if (ret)
+		goto done;
+
+done:
+	if (ret)
+		nouveau_abi16_ntfy_fini(chan, ntfy);
+	return nouveau_abi16_put(abi16, ret);
 }
 
 int
 nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
 {
-	struct drm_nouveau_gpuobj_free *objfree = data;
-	struct nouveau_channel *chan;
+	struct drm_nouveau_gpuobj_free *fini = data;
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_abi16_chan *chan, *temp;
+	struct nouveau_abi16_ntfy *ntfy;
 	int ret;
 
-	chan = nouveau_channel_get(file_priv, objfree->channel);
-	if (IS_ERR(chan))
-		return PTR_ERR(chan);
+	if (unlikely(!abi16))
+		return -ENOMEM;
 
-	/* Synchronize with the user channel */
-	nouveau_channel_idle(chan);
+	list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
+		if (chan->chan->handle == (NVDRM_CHAN | fini->channel))
+			break;
+		chan = NULL;
+	}
 
-	ret = nouveau_ramht_remove(chan, objfree->handle);
-	nouveau_channel_put(&chan);
-	return ret;
+	if (!chan)
+		return nouveau_abi16_put(abi16, -ENOENT);
+
+	/* synchronize with the user channel and destroy the gpu object */
+	nouveau_channel_idle(chan->chan);
+
+	ret = nouveau_object_del(abi16->client, chan->chan->handle, fini->handle);
+	if (ret)
+		return nouveau_abi16_put(abi16, ret);
+
+	/* cleanup extra state if this object was a notifier */
+	list_for_each_entry(ntfy, &chan->notifiers, head) {
+		if (ntfy->handle == fini->handle) {
+			nouveau_mm_free(&chan->heap, &ntfy->node);
+			list_del(&ntfy->head);
+			break;
+		}
+	}
+
+	return nouveau_abi16_put(abi16, 0);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h
index e6328b0..9000408 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.h
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h
@@ -3,6 +3,7 @@
 
 #define ABI16_IOCTL_ARGS                                                       \
 	struct drm_device *dev, void *data, struct drm_file *file_priv
+
 int nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS);
 int nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS);
 int nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS);
@@ -11,6 +12,37 @@
 int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS);
 int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS);
 
+struct nouveau_abi16_ntfy {
+	struct list_head head;
+	struct nouveau_mm_node *node;
+	u32 handle;
+};
+
+struct nouveau_abi16_chan {
+	struct list_head head;
+	struct nouveau_channel *chan;
+	struct list_head notifiers;
+	struct nouveau_bo *ntfy;
+	struct nouveau_vma ntfy_vma;
+	struct nouveau_mm  heap;
+};
+
+struct nouveau_abi16 {
+	struct nouveau_object *client;
+	struct nouveau_object *device;
+	struct list_head channels;
+	u64 handles;
+};
+
+struct nouveau_drm;
+struct nouveau_abi16 *nouveau_abi16_get(struct drm_file *, struct drm_device *);
+int  nouveau_abi16_put(struct nouveau_abi16 *, int);
+void nouveau_abi16_fini(struct nouveau_abi16 *);
+u16  nouveau_abi16_swclass(struct nouveau_drm *);
+
+#define NOUVEAU_GEM_DOMAIN_VRAM      (1 << 1)
+#define NOUVEAU_GEM_DOMAIN_GART      (1 << 2)
+
 struct drm_nouveau_channel_alloc {
 	uint32_t     fb_ctxdma_handle;
 	uint32_t     tt_ctxdma_handle;
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 778cd14..83686ef 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -13,7 +13,6 @@
 #include "drm_crtc_helper.h"
 #include "nouveau_drv.h"
 #include <nouveau_drm.h>
-#include "nv50_display.h"
 #include "nouveau_connector.h"
 
 #include <linux/vga_switcheroo.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index c3e66ae0..3465df3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -27,66 +27,57 @@
  *	    Jeremy Kolb  <jkolb@brandeis.edu>
  */
 
-#include "drmP.h"
-#include "ttm/ttm_page_alloc.h"
+#include <core/engine.h>
 
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/mm.h>
 #include "nouveau_fence.h"
-#include <core/ramht.h>
-#include <engine/fifo.h>
 
-#include <linux/log2.h>
-#include <linux/slab.h>
+#include "nouveau_bo.h"
+#include "nouveau_ttm.h"
+#include "nouveau_gem.h"
 
 /*
  * NV10-NV40 tiling helpers
  */
 
 static void
-nv10_bo_update_tile_region(struct drm_device *dev,
-			    struct nouveau_tile_reg *tilereg, uint32_t addr,
-			    uint32_t size, uint32_t pitch, uint32_t flags)
+nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
+			   u32 addr, u32 size, u32 pitch, u32 flags)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i = tilereg - dev_priv->tile.reg, j;
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-	unsigned long save;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	int i = reg - drm->tile.reg;
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
+	struct nouveau_fb_tile *tile = &pfb->tile.region[i];
+	struct nouveau_engine *engine;
 
-	nouveau_fence_unref(&tilereg->fence);
+	nouveau_fence_unref(&reg->fence);
 
 	if (tile->pitch)
-		nvfb_tile_fini(dev, i);
+		pfb->tile.fini(pfb, i, tile);
 
 	if (pitch)
-		nvfb_tile_init(dev, i, addr, size, pitch, flags);
+		pfb->tile.init(pfb, i, addr, size, pitch, flags, tile);
 
-	spin_lock_irqsave(&dev_priv->context_switch_lock, save);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 0);
-	nv04_fifo_cache_pull(dev, false);
+	pfb->tile.prog(pfb, i, tile);
 
-	nouveau_wait_for_idle(dev);
-
-	nvfb_tile_prog(dev, i);
-	for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
-		if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
-			dev_priv->eng[j]->set_tile_region(dev, i);
-	}
-
-	nv04_fifo_cache_pull(dev, true);
-	nv_wr32(dev, NV03_PFIFO_CACHES, 1);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, save);
+	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_GR)))
+		engine->tile_prog(engine, i);
+	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_MPEG)))
+		engine->tile_prog(engine, i);
 }
 
-static struct nouveau_tile_reg *
+static struct nouveau_drm_tile *
 nv10_bo_get_tile_region(struct drm_device *dev, int i)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_drm_tile *tile = &drm->tile.reg[i];
 
-	spin_lock(&dev_priv->tile.lock);
+	spin_lock(&drm->tile.lock);
 
 	if (!tile->used &&
 	    (!tile->fence || nouveau_fence_done(tile->fence)))
@@ -94,18 +85,18 @@
 	else
 		tile = NULL;
 
-	spin_unlock(&dev_priv->tile.lock);
+	spin_unlock(&drm->tile.lock);
 	return tile;
 }
 
 static void
-nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile,
-			 struct nouveau_fence *fence)
+nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
+			struct nouveau_fence *fence)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 
 	if (tile) {
-		spin_lock(&dev_priv->tile.lock);
+		spin_lock(&drm->tile.lock);
 		if (fence) {
 			/* Mark it as pending. */
 			tile->fence = fence;
@@ -113,25 +104,27 @@
 		}
 
 		tile->used = false;
-		spin_unlock(&dev_priv->tile.lock);
+		spin_unlock(&drm->tile.lock);
 	}
 }
 
-static struct nouveau_tile_reg *
-nv10_bo_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
-		    uint32_t pitch, uint32_t flags)
+static struct nouveau_drm_tile *
+nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
+		   u32 size, u32 pitch, u32 flags)
 {
-	struct nouveau_tile_reg *tile, *found = NULL;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
+	struct nouveau_drm_tile *tile, *found = NULL;
 	int i;
 
-	for (i = 0; i < nvfb_tile_nr(dev); i++) {
+	for (i = 0; i < pfb->tile.regions; i++) {
 		tile = nv10_bo_get_tile_region(dev, i);
 
 		if (pitch && !found) {
 			found = tile;
 			continue;
 
-		} else if (tile && nvfb_tile(dev, i)->pitch) {
+		} else if (tile && pfb->tile.region[i].pitch) {
 			/* Kill an unused tile region. */
 			nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0);
 		}
@@ -148,13 +141,12 @@
 static void
 nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+	struct drm_device *dev = drm->dev;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 
 	if (unlikely(nvbo->gem))
 		DRM_ERROR("bo %p still attached to GEM object\n", bo);
-
 	nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
 	kfree(nvbo);
 }
@@ -163,23 +155,24 @@
 nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
 		       int *align, int *size)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+	struct nouveau_device *device = nv_device(drm->device);
 
-	if (dev_priv->card_type < NV_50) {
+	if (device->card_type < NV_50) {
 		if (nvbo->tile_mode) {
-			if (dev_priv->chipset >= 0x40) {
+			if (device->chipset >= 0x40) {
 				*align = 65536;
 				*size = roundup(*size, 64 * nvbo->tile_mode);
 
-			} else if (dev_priv->chipset >= 0x30) {
+			} else if (device->chipset >= 0x30) {
 				*align = 32768;
 				*size = roundup(*size, 64 * nvbo->tile_mode);
 
-			} else if (dev_priv->chipset >= 0x20) {
+			} else if (device->chipset >= 0x20) {
 				*align = 16384;
 				*size = roundup(*size, 64 * nvbo->tile_mode);
 
-			} else if (dev_priv->chipset >= 0x10) {
+			} else if (device->chipset >= 0x10) {
 				*align = 16384;
 				*size = roundup(*size, 32 * nvbo->tile_mode);
 			}
@@ -198,7 +191,7 @@
 	       struct sg_table *sg,
 	       struct nouveau_bo **pnvbo)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 	struct nouveau_bo *nvbo;
 	size_t acc_size;
 	int ret;
@@ -215,22 +208,22 @@
 	INIT_LIST_HEAD(&nvbo->vma_list);
 	nvbo->tile_mode = tile_mode;
 	nvbo->tile_flags = tile_flags;
-	nvbo->bo.bdev = &dev_priv->ttm.bdev;
+	nvbo->bo.bdev = &drm->ttm.bdev;
 
 	nvbo->page_shift = 12;
-	if (dev_priv->chan_vm) {
+	if (drm->client.base.vm) {
 		if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
-			nvbo->page_shift = nvvm_lpg_shift(dev_priv->chan_vm);
+			nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift;
 	}
 
 	nouveau_bo_fixup_align(nvbo, flags, &align, &size);
 	nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
 	nouveau_bo_placement_set(nvbo, flags, 0);
 
-	acc_size = ttm_bo_dma_acc_size(&dev_priv->ttm.bdev, size,
+	acc_size = ttm_bo_dma_acc_size(&drm->ttm.bdev, size,
 				       sizeof(struct nouveau_bo));
 
-	ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
+	ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size,
 			  type, &nvbo->placement,
 			  align >> PAGE_SHIFT, 0, false, NULL, acc_size, sg,
 			  nouveau_bo_del_ttm);
@@ -259,10 +252,11 @@
 static void
 set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
-	int vram_pages = nvfb_vram_size(dev_priv->dev) >> PAGE_SHIFT;
+	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
+	u32 vram_pages = pfb->ram.size >> PAGE_SHIFT;
 
-	if (dev_priv->card_type == NV_10 &&
+	if (nv_device(drm->device)->card_type == NV_10 &&
 	    nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
 	    nvbo->bo.mem.num_pages < vram_pages / 4) {
 		/*
@@ -302,13 +296,12 @@
 int
 nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct ttm_buffer_object *bo = &nvbo->bo;
 	int ret;
 
 	if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
-		NV_ERROR(nouveau_bdev(bo->bdev)->dev,
-			 "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
+		NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
 			 1 << bo->mem.mem_type, memtype);
 		return -EINVAL;
 	}
@@ -326,10 +319,10 @@
 	if (ret == 0) {
 		switch (bo->mem.mem_type) {
 		case TTM_PL_VRAM:
-			dev_priv->fb_aper_free -= bo->mem.size;
+			drm->gem.vram_available -= bo->mem.size;
 			break;
 		case TTM_PL_TT:
-			dev_priv->gart_info.aper_free -= bo->mem.size;
+			drm->gem.gart_available -= bo->mem.size;
 			break;
 		default:
 			break;
@@ -345,7 +338,7 @@
 int
 nouveau_bo_unpin(struct nouveau_bo *nvbo)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct ttm_buffer_object *bo = &nvbo->bo;
 	int ret;
 
@@ -362,10 +355,10 @@
 	if (ret == 0) {
 		switch (bo->mem.mem_type) {
 		case TTM_PL_VRAM:
-			dev_priv->fb_aper_free += bo->mem.size;
+			drm->gem.vram_available += bo->mem.size;
 			break;
 		case TTM_PL_TT:
-			dev_priv->gart_info.aper_free += bo->mem.size;
+			drm->gem.gart_available += bo->mem.size;
 			break;
 		default:
 			break;
@@ -460,30 +453,18 @@
 }
 
 static struct ttm_tt *
-nouveau_ttm_tt_create(struct ttm_bo_device *bdev,
-		      unsigned long size, uint32_t page_flags,
-		      struct page *dummy_read_page)
+nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
+		      uint32_t page_flags, struct page *dummy_read)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bdev);
+	struct drm_device *dev = drm->dev;
 
-	switch (dev_priv->gart_info.type) {
-#if __OS_HAS_AGP
-	case NOUVEAU_GART_AGP:
-		return ttm_agp_tt_create(bdev, dev->agp->bridge,
-					 size, page_flags, dummy_read_page);
-#endif
-	case NOUVEAU_GART_PDMA:
-	case NOUVEAU_GART_HW:
-		return nouveau_sgdma_create_ttm(bdev, size, page_flags,
-						dummy_read_page);
-	default:
-		NV_ERROR(dev, "Unknown GART type %d\n",
-			 dev_priv->gart_info.type);
-		break;
+	if (drm->agp.stat == ENABLED) {
+		return ttm_agp_tt_create(bdev, dev->agp->bridge, size,
+					 page_flags, dummy_read);
 	}
 
-	return NULL;
+	return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read);
 }
 
 static int
@@ -497,8 +478,7 @@
 nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
 			 struct ttm_mem_type_manager *man)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bdev);
 
 	switch (type) {
 	case TTM_PL_SYSTEM:
@@ -507,7 +487,7 @@
 		man->default_caching = TTM_PL_FLAG_CACHED;
 		break;
 	case TTM_PL_VRAM:
-		if (dev_priv->card_type >= NV_50) {
+		if (nv_device(drm->device)->card_type >= NV_50) {
 			man->func = &nouveau_vram_manager;
 			man->io_reserve_fastpath = false;
 			man->use_io_reserve_lru = true;
@@ -521,35 +501,28 @@
 		man->default_caching = TTM_PL_FLAG_WC;
 		break;
 	case TTM_PL_TT:
-		if (dev_priv->card_type >= NV_50)
+		if (nv_device(drm->device)->card_type >= NV_50)
 			man->func = &nouveau_gart_manager;
 		else
-		if (dev_priv->gart_info.type != NOUVEAU_GART_AGP)
+		if (drm->agp.stat != ENABLED)
 			man->func = &nv04_gart_manager;
 		else
 			man->func = &ttm_bo_manager_func;
-		switch (dev_priv->gart_info.type) {
-		case NOUVEAU_GART_AGP:
+
+		if (drm->agp.stat == ENABLED) {
 			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
 			man->available_caching = TTM_PL_FLAG_UNCACHED |
 				TTM_PL_FLAG_WC;
 			man->default_caching = TTM_PL_FLAG_WC;
-			break;
-		case NOUVEAU_GART_PDMA:
-		case NOUVEAU_GART_HW:
+		} else {
 			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
 				     TTM_MEMTYPE_FLAG_CMA;
 			man->available_caching = TTM_PL_MASK_CACHING;
 			man->default_caching = TTM_PL_FLAG_CACHED;
-			break;
-		default:
-			NV_ERROR(dev, "Unknown GART type: %d\n",
-				 dev_priv->gart_info.type);
-			return -EINVAL;
 		}
+
 		break;
 	default:
-		NV_ERROR(dev, "Unsupported memory type %u\n", (unsigned)type);
 		return -EINVAL;
 	}
 	return 0;
@@ -783,20 +756,14 @@
 static int
 nv50_bo_move_init(struct nouveau_channel *chan, u32 handle)
 {
-	int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
-					 &chan->m2mf_ntfy);
+	int ret = RING_SPACE(chan, 6);
 	if (ret == 0) {
-		ret = RING_SPACE(chan, 6);
-		if (ret == 0) {
-			BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
-			OUT_RING  (chan, handle);
-			BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
-			OUT_RING  (chan, NvNotify0);
-			OUT_RING  (chan, NvDmaFB);
-			OUT_RING  (chan, NvDmaFB);
-		} else {
-			nouveau_ramht_remove(chan, NvNotify0);
-		}
+		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
+		OUT_RING  (chan, handle);
+		BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
+		OUT_RING  (chan, NvNotify0);
+		OUT_RING  (chan, NvDmaFB);
+		OUT_RING  (chan, NvDmaFB);
 	}
 
 	return ret;
@@ -895,16 +862,12 @@
 static int
 nv04_bo_move_init(struct nouveau_channel *chan, u32 handle)
 {
-	int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
-					 &chan->m2mf_ntfy);
+	int ret = RING_SPACE(chan, 4);
 	if (ret == 0) {
-		ret = RING_SPACE(chan, 4);
-		if (ret == 0) {
-			BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
-			OUT_RING  (chan, handle);
-			BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
-			OUT_RING  (chan, NvNotify0);
-		}
+		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
+		OUT_RING  (chan, handle);
+		BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
+		OUT_RING  (chan, NvNotify0);
 	}
 
 	return ret;
@@ -915,8 +878,8 @@
 		      struct nouveau_channel *chan, struct ttm_mem_reg *mem)
 {
 	if (mem->mem_type == TTM_PL_TT)
-		return chan->gart_handle;
-	return chan->vram_handle;
+		return NvDmaTT;
+	return NvDmaFB;
 }
 
 static int
@@ -972,8 +935,9 @@
 	struct nouveau_mem *node = mem->mm_node;
 	int ret;
 
-	ret = nouveau_vm_get(chan->vm, mem->num_pages << PAGE_SHIFT,
-			     node->page_shift, NV_MEM_ACCESS_RO, vma);
+	ret = nouveau_vm_get(nv_client(chan->cli)->vm, mem->num_pages <<
+			     PAGE_SHIFT, node->page_shift,
+			     NV_MEM_ACCESS_RW, vma);
 	if (ret)
 		return ret;
 
@@ -990,19 +954,19 @@
 		     bool no_wait_reserve, bool no_wait_gpu,
 		     struct ttm_mem_reg *new_mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-	struct nouveau_channel *chan = chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+	struct nouveau_channel *chan = chan = drm->channel;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct ttm_mem_reg *old_mem = &bo->mem;
 	int ret;
 
-	mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX);
+	mutex_lock(&chan->cli->mutex);
 
 	/* create temporary vmas for the transfer and attach them to the
 	 * old nouveau_mem node, these will get cleaned up after ttm has
 	 * destroyed the ttm_mem_reg
 	 */
-	if (dev_priv->card_type >= NV_50) {
+	if (nv_device(drm->device)->card_type >= NV_50) {
 		struct nouveau_mem *node = old_mem->mm_node;
 
 		ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]);
@@ -1014,7 +978,7 @@
 			goto out;
 	}
 
-	ret = dev_priv->ttm.move(chan, bo, &bo->mem, new_mem);
+	ret = drm->ttm.move(chan, bo, &bo->mem, new_mem);
 	if (ret == 0) {
 		ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
 						    no_wait_reserve,
@@ -1022,14 +986,15 @@
 	}
 
 out:
-	mutex_unlock(&chan->mutex);
+	mutex_unlock(&chan->cli->mutex);
 	return ret;
 }
 
 void
 nouveau_bo_move_init(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+	struct nouveau_cli *cli = chan->cli;
+	struct nouveau_drm *drm = chan->drm;
 	static const struct {
 		const char *name;
 		int engine;
@@ -1054,19 +1019,26 @@
 	int ret;
 
 	do {
+		struct nouveau_object *object;
 		u32 handle = (mthd->engine << 16) | mthd->oclass;
-		ret = nouveau_gpuobj_gr_new(chan, handle, mthd->oclass);
+
+		ret = nouveau_object_new(nv_object(cli), chan->handle, handle,
+					 mthd->oclass, NULL, 0, &object);
 		if (ret == 0) {
 			ret = mthd->init(chan, handle);
-			if (ret == 0) {
-				dev_priv->ttm.move = mthd->exec;
-				name = mthd->name;
-				break;
+			if (ret) {
+				nouveau_object_del(nv_object(cli),
+						   chan->handle, handle);
+				continue;
 			}
+
+			drm->ttm.move = mthd->exec;
+			name = mthd->name;
+			break;
 		}
 	} while ((++mthd)->exec);
 
-	NV_INFO(chan->dev, "MM: using %s for buffer copies\n", name);
+	NV_INFO(drm, "MM: using %s for buffer copies\n", name);
 }
 
 static int
@@ -1151,7 +1123,7 @@
 			nouveau_vm_map(vma, new_mem->mm_node);
 		} else
 		if (new_mem && new_mem->mem_type == TTM_PL_TT &&
-		    nvbo->page_shift == nvvm_spg_shift(vma->vm)) {
+		    nvbo->page_shift == vma->vm->vmm->spg_shift) {
 			if (((struct nouveau_mem *)new_mem->mm_node)->sg)
 				nouveau_vm_map_sg_table(vma, 0, new_mem->
 						  num_pages << PAGE_SHIFT,
@@ -1168,10 +1140,10 @@
 
 static int
 nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
-		   struct nouveau_tile_reg **new_tile)
+		   struct nouveau_drm_tile **new_tile)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+	struct drm_device *dev = drm->dev;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	u64 offset = new_mem->start << PAGE_SHIFT;
 
@@ -1179,7 +1151,7 @@
 	if (new_mem->mem_type != TTM_PL_VRAM)
 		return 0;
 
-	if (dev_priv->card_type >= NV_10) {
+	if (nv_device(drm->device)->card_type >= NV_10) {
 		*new_tile = nv10_bo_set_tiling(dev, offset, new_mem->size,
 						nvbo->tile_mode,
 						nvbo->tile_flags);
@@ -1190,11 +1162,11 @@
 
 static void
 nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
-		      struct nouveau_tile_reg *new_tile,
-		      struct nouveau_tile_reg **old_tile)
+		      struct nouveau_drm_tile *new_tile,
+		      struct nouveau_drm_tile **old_tile)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
+	struct drm_device *dev = drm->dev;
 
 	nv10_bo_put_tile_region(dev, *old_tile, bo->sync_obj);
 	*old_tile = new_tile;
@@ -1205,13 +1177,13 @@
 		bool no_wait_reserve, bool no_wait_gpu,
 		struct ttm_mem_reg *new_mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct ttm_mem_reg *old_mem = &bo->mem;
-	struct nouveau_tile_reg *new_tile = NULL;
+	struct nouveau_drm_tile *new_tile = NULL;
 	int ret = 0;
 
-	if (dev_priv->card_type < NV_50) {
+	if (nv_device(drm->device)->card_type < NV_50) {
 		ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile);
 		if (ret)
 			return ret;
@@ -1226,7 +1198,7 @@
 	}
 
 	/* CPU copy if we have no accelerated method available */
-	if (!dev_priv->ttm.move) {
+	if (!drm->ttm.move) {
 		ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 		goto out;
 	}
@@ -1246,7 +1218,7 @@
 	ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 
 out:
-	if (dev_priv->card_type < NV_50) {
+	if (nv_device(drm->device)->card_type < NV_50) {
 		if (ret)
 			nouveau_bo_vm_cleanup(bo, NULL, &new_tile);
 		else
@@ -1266,8 +1238,8 @@
 nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bdev);
+	struct drm_device *dev = drm->dev;
 	int ret;
 
 	mem->bus.addr = NULL;
@@ -1283,9 +1255,9 @@
 		return 0;
 	case TTM_PL_TT:
 #if __OS_HAS_AGP
-		if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
+		if (drm->agp.stat == ENABLED) {
 			mem->bus.offset = mem->start << PAGE_SHIFT;
-			mem->bus.base = dev_priv->gart_info.aper_base;
+			mem->bus.base = drm->agp.base;
 			mem->bus.is_iomem = true;
 		}
 #endif
@@ -1294,10 +1266,11 @@
 		mem->bus.offset = mem->start << PAGE_SHIFT;
 		mem->bus.base = pci_resource_start(dev->pdev, 1);
 		mem->bus.is_iomem = true;
-		if (dev_priv->card_type >= NV_50) {
+		if (nv_device(drm->device)->card_type >= NV_50) {
+			struct nouveau_bar *bar = nouveau_bar(drm->device);
 			struct nouveau_mem *node = mem->mm_node;
 
-			ret = nvbar_map(dev, node, NV_MEM_ACCESS_RW,
+			ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
 					&node->bar_vma);
 			if (ret)
 				return ret;
@@ -1314,40 +1287,40 @@
 static void
 nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
+	struct nouveau_drm *drm = nouveau_bdev(bdev);
+	struct nouveau_bar *bar = nouveau_bar(drm->device);
 	struct nouveau_mem *node = mem->mm_node;
 
-	if (mem->mem_type != TTM_PL_VRAM)
-		return;
-
 	if (!node->bar_vma.node)
 		return;
 
-	nvbar_unmap(dev_priv->dev, &node->bar_vma);
+	bar->unmap(bar, &node->bar_vma);
 }
 
 static int
 nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
+	struct nouveau_device *device = nv_device(drm->device);
+	u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
 
 	/* as long as the bo isn't in vram, and isn't tiled, we've got
 	 * nothing to do here.
 	 */
 	if (bo->mem.mem_type != TTM_PL_VRAM) {
-		if (dev_priv->card_type < NV_50 ||
+		if (nv_device(drm->device)->card_type < NV_50 ||
 		    !nouveau_bo_tile_layout(nvbo))
 			return 0;
 	}
 
 	/* make sure bo is in mappable vram */
-	if (bo->mem.start + bo->mem.num_pages < dev_priv->fb_mappable_pages)
+	if (bo->mem.start + bo->mem.num_pages < mappable)
 		return 0;
 
 
 	nvbo->placement.fpfn = 0;
-	nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
+	nvbo->placement.lpfn = mappable;
 	nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
 	return nouveau_bo_validate(nvbo, false, true, false);
 }
@@ -1356,7 +1329,7 @@
 nouveau_ttm_tt_populate(struct ttm_tt *ttm)
 {
 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
-	struct drm_nouveau_private *dev_priv;
+	struct nouveau_drm *drm;
 	struct drm_device *dev;
 	unsigned i;
 	int r;
@@ -1373,11 +1346,11 @@
 		return 0;
 	}
 
-	dev_priv = nouveau_bdev(ttm->bdev);
-	dev = dev_priv->dev;
+	drm = nouveau_bdev(ttm->bdev);
+	dev = drm->dev;
 
 #if __OS_HAS_AGP
-	if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
+	if (drm->agp.stat == ENABLED) {
 		return ttm_agp_tt_populate(ttm);
 	}
 #endif
@@ -1414,7 +1387,7 @@
 nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 {
 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
-	struct drm_nouveau_private *dev_priv;
+	struct nouveau_drm *drm;
 	struct drm_device *dev;
 	unsigned i;
 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@@ -1422,11 +1395,11 @@
 	if (slave)
 		return;
 
-	dev_priv = nouveau_bdev(ttm->bdev);
-	dev = dev_priv->dev;
+	drm = nouveau_bdev(ttm->bdev);
+	dev = drm->dev;
 
 #if __OS_HAS_AGP
-	if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
+	if (drm->agp.stat == ENABLED) {
 		ttm_agp_tt_unpopulate(ttm);
 		return;
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index a0a889c..c42aea9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -2,13 +2,9 @@
 #define __NOUVEAU_BO_H__
 
 struct nouveau_channel;
+struct nouveau_fence;
 struct nouveau_vma;
 
-struct nouveau_tile_reg {
-	bool used;
-	struct nouveau_fence *fence;
-};
-
 struct nouveau_bo {
 	struct ttm_buffer_object bo;
 	struct ttm_placement placement;
@@ -29,7 +25,7 @@
 
 	u32 tile_mode;
 	u32 tile_flags;
-	struct nouveau_tile_reg *tile;
+	struct nouveau_drm_tile *tile;
 
 	struct drm_gem_object *gem;
 	int pin_refcnt;
@@ -89,4 +85,15 @@
 			struct nouveau_vma *);
 void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
 
+/* TODO: submit equivalent to TTM generic API upstream? */
+static inline void __iomem *
+nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
+{
+	bool is_iomem;
+	void __iomem *ioptr = (void __force __iomem *)ttm_kmap_obj_virtual(
+						&nvbo->kmap, &is_iomem);
+	WARN_ON_ONCE(ioptr && !is_iomem);
+	return ioptr;
+}
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
new file mode 100644
index 0000000..3dd5f71
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2012 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 <core/object.h>
+#include <core/client.h>
+#include <core/device.h>
+#include <core/class.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/instmem.h>
+
+#include <engine/software.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+#include "nouveau_bo.h"
+#include "nouveau_chan.h"
+#include "nouveau_fence.h"
+#include "nouveau_abi16.h"
+
+MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
+static int nouveau_vram_pushbuf;
+module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
+
+int
+nouveau_channel_idle(struct nouveau_channel *chan)
+{
+	struct nouveau_drm *drm = chan->drm;
+	struct nouveau_fence *fence = NULL;
+	int ret;
+
+	ret = nouveau_fence_new(chan, &fence);
+	if (!ret) {
+		ret = nouveau_fence_wait(fence, false, false);
+		nouveau_fence_unref(&fence);
+	}
+
+	if (ret)
+		NV_ERROR(drm, "failed to idle channel 0x%08x\n", chan->handle);
+	return ret;
+}
+
+void
+nouveau_channel_del(struct nouveau_channel **pchan)
+{
+	struct nouveau_channel *chan = *pchan;
+	if (chan) {
+		struct nouveau_object *client = nv_object(chan->cli);
+		if (chan->fence) {
+			nouveau_channel_idle(chan);
+			nouveau_fence(chan->drm)->context_del(chan);
+		}
+		nouveau_object_del(client, NVDRM_DEVICE, chan->handle);
+		nouveau_object_del(client, NVDRM_DEVICE, chan->push.handle);
+		nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma);
+		nouveau_bo_unmap(chan->push.buffer);
+		nouveau_bo_ref(NULL, &chan->push.buffer);
+		kfree(chan);
+	}
+	*pchan = NULL;
+}
+
+static int
+nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli,
+		     u32 parent, u32 handle, u32 size,
+		     struct nouveau_channel **pchan)
+{
+	struct nouveau_device *device = nv_device(drm->device);
+	struct nouveau_instmem *imem = nouveau_instmem(device);
+	struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
+	struct nouveau_fb *pfb = nouveau_fb(device);
+	struct nouveau_client *client = &cli->base;
+	struct nv_dma_class args = {};
+	struct nouveau_channel *chan;
+	struct nouveau_object *push;
+	u32 target;
+	int ret;
+
+	chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL);
+	if (!chan)
+		return -ENOMEM;
+
+	chan->cli = cli;
+	chan->drm = drm;
+	chan->handle = handle;
+
+	/* allocate memory for dma push buffer */
+	target = TTM_PL_FLAG_TT;
+	if (nouveau_vram_pushbuf)
+		target = TTM_PL_FLAG_VRAM;
+
+	ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL,
+			    &chan->push.buffer);
+	if (ret == 0) {
+		ret = nouveau_bo_pin(chan->push.buffer, target);
+		if (ret == 0)
+			ret = nouveau_bo_map(chan->push.buffer);
+	}
+
+	if (ret) {
+		nouveau_channel_del(pchan);
+		return ret;
+	}
+
+	/* create dma object covering the *entire* memory space that the
+	 * pushbuf lives in, this is because the GEM code requires that
+	 * we be able to call out to other (indirect) push buffers
+	 */
+	chan->push.vma.offset = chan->push.buffer->bo.offset;
+	chan->push.handle = NVDRM_PUSH | (handle & 0xffff);
+
+	if (device->card_type >= NV_50) {
+		ret = nouveau_bo_vma_add(chan->push.buffer, client->vm,
+					&chan->push.vma);
+		if (ret) {
+			nouveau_channel_del(pchan);
+			return ret;
+		}
+
+		args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
+		args.start = 0;
+		args.limit = client->vm->vmm->limit - 1;
+	} else
+	if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
+		u64 limit = pfb->ram.size - imem->reserved - 1;
+		if (device->card_type == NV_04) {
+			/* nv04 vram pushbuf hack, retarget to its location in
+			 * the framebuffer bar rather than direct vram access..
+			 * nfi why this exists, it came from the -nv ddx.
+			 */
+			args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR;
+			args.start = pci_resource_start(device->pdev, 1);
+			args.limit = args.start + limit;
+		} else {
+			args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
+			args.start = 0;
+			args.limit = limit;
+		}
+	} else {
+		if (chan->drm->agp.stat == ENABLED) {
+			args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
+			args.start = chan->drm->agp.base;
+			args.limit = chan->drm->agp.base +
+				     chan->drm->agp.size - 1;
+		} else {
+			args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
+			args.start = 0;
+			args.limit = vmm->limit - 1;
+		}
+	}
+
+	ret = nouveau_object_new(nv_object(chan->cli), parent,
+				 chan->push.handle, 0x0002,
+				 &args, sizeof(args), &push);
+	if (ret) {
+		nouveau_channel_del(pchan);
+		return ret;
+	}
+
+	return 0;
+}
+
+int
+nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli,
+		    u32 parent, u32 handle, struct nouveau_channel **pchan)
+{
+	static const u16 oclasses[] = { 0xa06f, 0x906f, 0x826f, 0x506f, 0 };
+	const u16 *oclass = oclasses;
+	struct nv_channel_ind_class args;
+	struct nouveau_channel *chan;
+	int ret;
+
+	/* allocate dma push buffer */
+	ret = nouveau_channel_prep(drm, cli, parent, handle, 0x12000, &chan);
+	*pchan = chan;
+	if (ret)
+		return ret;
+
+	/* create channel object */
+	args.pushbuf = chan->push.handle;
+	args.ioffset = 0x10000 + chan->push.vma.offset;
+	args.ilength = 0x02000;
+
+	do {
+		ret = nouveau_object_new(nv_object(cli), parent, handle,
+					 *oclass++, &args, sizeof(args),
+					 &chan->object);
+		if (ret == 0)
+			return ret;
+	} while (*oclass);
+
+	nouveau_channel_del(pchan);
+	return ret;
+}
+
+static int
+nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli,
+		    u32 parent, u32 handle, struct nouveau_channel **pchan)
+{
+	static const u16 oclasses[] = { 0x006e, 0 };
+	const u16 *oclass = oclasses;
+	struct nv_channel_dma_class args;
+	struct nouveau_channel *chan;
+	int ret;
+
+	/* allocate dma push buffer */
+	ret = nouveau_channel_prep(drm, cli, parent, handle, 0x10000, &chan);
+	*pchan = chan;
+	if (ret)
+		return ret;
+
+	/* create channel object */
+	args.pushbuf = chan->push.handle;
+	args.offset = chan->push.vma.offset;
+
+	do {
+		ret = nouveau_object_new(nv_object(cli), parent, handle,
+					 *oclass++, &args, sizeof(args),
+					 &chan->object);
+		if (ret == 0)
+			return ret;
+	} while (ret && *oclass);
+
+	nouveau_channel_del(pchan);
+	return ret;
+}
+
+static int
+nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
+{
+	struct nouveau_client *client = nv_client(chan->cli);
+	struct nouveau_device *device = nv_device(chan->drm->device);
+	struct nouveau_instmem *imem = nouveau_instmem(device);
+	struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
+	struct nouveau_fb *pfb = nouveau_fb(device);
+	struct nouveau_software_chan *swch;
+	struct nouveau_object *object;
+	struct nv_dma_class args;
+	int ret, i;
+
+	chan->vram = vram;
+	chan->gart = gart;
+
+	/* allocate dma objects to cover all allowed vram, and gart */
+	if (device->card_type < NV_C0) {
+		if (device->card_type >= NV_50) {
+			args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
+			args.start = 0;
+			args.limit = client->vm->vmm->limit - 1;
+		} else {
+			args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
+			args.start = 0;
+			args.limit = pfb->ram.size - imem->reserved - 1;
+		}
+
+		ret = nouveau_object_new(nv_object(client), chan->handle, vram,
+					 0x003d, &args, sizeof(args), &object);
+		if (ret)
+			return ret;
+
+		if (device->card_type >= NV_50) {
+			args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
+			args.start = 0;
+			args.limit = client->vm->vmm->limit - 1;
+		} else
+		if (chan->drm->agp.stat == ENABLED) {
+			args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
+			args.start = chan->drm->agp.base;
+			args.limit = chan->drm->agp.base +
+				     chan->drm->agp.size - 1;
+		} else {
+			args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
+			args.start = 0;
+			args.limit = vmm->limit - 1;
+		}
+
+		ret = nouveau_object_new(nv_object(client), chan->handle, gart,
+					 0x003d, &args, sizeof(args), &object);
+		if (ret)
+			return ret;
+	}
+
+	/* initialise dma tracking parameters */
+	switch (nv_hclass(chan->object) & 0xffff) {
+	case 0x006e:
+		chan->user_put = 0x40;
+		chan->user_get = 0x44;
+		chan->dma.max = (0x10000 / 4) - 2;
+		break;
+	default:
+		chan->user_put = 0x40;
+		chan->user_get = 0x44;
+		chan->user_get_hi = 0x60;
+		chan->dma.ib_base =  0x10000 / 4;
+		chan->dma.ib_max  = (0x02000 / 8) - 1;
+		chan->dma.ib_put  = 0;
+		chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
+		chan->dma.max = chan->dma.ib_base;
+		break;
+	}
+
+	chan->dma.put = 0;
+	chan->dma.cur = chan->dma.put;
+	chan->dma.free = chan->dma.max - chan->dma.cur;
+
+	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
+		OUT_RING(chan, 0x00000000);
+
+	/* allocate software object class (used for fences on <= nv05, and
+	 * to signal flip completion), bind it to a subchannel.
+	 */
+	ret = nouveau_object_new(nv_object(client), chan->handle,
+				 NvSw, nouveau_abi16_swclass(chan->drm),
+				 NULL, 0, &object);
+	if (ret)
+		return ret;
+
+	swch = (void *)object->parent;
+	swch->flip = nouveau_flip_complete;
+	swch->flip_data = chan;
+
+	if (device->card_type < NV_C0) {
+		ret = RING_SPACE(chan, 2);
+		if (ret)
+			return ret;
+
+		BEGIN_NV04(chan, NvSubSw, 0x0000, 1);
+		OUT_RING  (chan, NvSw);
+		FIRE_RING (chan);
+	}
+
+	/* initialise synchronisation */
+	return nouveau_fence(chan->drm)->context_new(chan);
+}
+
+int
+nouveau_channel_new(struct nouveau_drm *drm, struct nouveau_cli *cli,
+		    u32 parent, u32 handle, u32 vram, u32 gart,
+		    struct nouveau_channel **pchan)
+{
+	int ret;
+
+	ret = nouveau_channel_ind(drm, cli, parent, handle, pchan);
+	if (ret) {
+		NV_DEBUG(drm, "ib channel create, %d\n", ret);
+		ret = nouveau_channel_dma(drm, cli, parent, handle, pchan);
+		if (ret) {
+			NV_DEBUG(drm, "dma channel create, %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = nouveau_channel_init(*pchan, vram, gart);
+	if (ret) {
+		NV_ERROR(drm, "channel failed to initialise, %d\n", ret);
+		nouveau_channel_del(pchan);
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h
new file mode 100644
index 0000000..0fa9424
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.h
@@ -0,0 +1,47 @@
+#ifndef __NOUVEAU_CHAN_H__
+#define __NOUVEAU_CHAN_H__
+
+struct nouveau_cli;
+
+struct nouveau_channel {
+	struct nouveau_cli *cli;
+	struct nouveau_drm *drm;
+
+	u32 handle;
+	u32 vram;
+	u32 gart;
+
+	struct {
+		struct nouveau_bo *buffer;
+		struct nouveau_vma vma;
+		u32 handle;
+	} push;
+
+	/* TODO: this will be reworked in the near future */
+	bool accel_done;
+	void *fence;
+	struct {
+		int max;
+		int free;
+		int cur;
+		int put;
+		int ib_base;
+		int ib_max;
+		int ib_free;
+		int ib_put;
+	} dma;
+	u32 user_get_hi;
+	u32 user_get;
+	u32 user_put;
+
+	struct nouveau_object *object;
+};
+
+
+int  nouveau_channel_new(struct nouveau_drm *, struct nouveau_cli *,
+			 u32 parent, u32 handle, u32 vram, u32 gart,
+			 struct nouveau_channel **);
+void nouveau_channel_del(struct nouveau_channel **);
+int  nouveau_channel_idle(struct nouveau_channel *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
deleted file mode 100644
index 285fde8..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright 2005-2006 Stephane Marchesin
- * All Rights Reserved.
- *
- * 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <nouveau_drm.h>
-#include "nouveau_dma.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
-#include "nouveau_fence.h"
-#include "nouveau_software.h"
-
-MODULE_PARM_DESC(vram_pushbuf, "Force DMA push buffers to be in VRAM");
-int nouveau_vram_pushbuf;
-module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
-
-static int
-nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
-{
-	u32 mem = nouveau_vram_pushbuf ? TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT;
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int ret;
-
-	/* allocate buffer object */
-	ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo);
-	if (ret)
-		goto out;
-
-	ret = nouveau_bo_pin(chan->pushbuf_bo, mem);
-	if (ret)
-		goto out;
-
-	ret = nouveau_bo_map(chan->pushbuf_bo);
-	if (ret)
-		goto out;
-
-	/* create DMA object covering the entire memtype where the push
-	 * buffer resides, userspace can submit its own push buffers from
-	 * anywhere within the same memtype.
-	 */
-	chan->pushbuf_base = chan->pushbuf_bo->bo.offset;
-	if (dev_priv->card_type >= NV_50) {
-		ret = nouveau_bo_vma_add(chan->pushbuf_bo, chan->vm,
-					 &chan->pushbuf_vma);
-		if (ret)
-			goto out;
-
-		if (dev_priv->card_type < NV_C0) {
-			ret = nouveau_gpuobj_dma_new(chan,
-						     NV_CLASS_DMA_IN_MEMORY, 0,
-						     (1ULL << 40),
-						     NV_MEM_ACCESS_RO,
-						     NV_MEM_TARGET_VM,
-						     &chan->pushbuf);
-		}
-		chan->pushbuf_base = chan->pushbuf_vma.offset;
-	} else
-	if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_TT) {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
-					     dev_priv->gart_info.aper_size,
-					     NV_MEM_ACCESS_RO,
-					     NV_MEM_TARGET_GART,
-					     &chan->pushbuf);
-	} else
-	if (dev_priv->card_type != NV_04) {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
-					     dev_priv->fb_available_size,
-					     NV_MEM_ACCESS_RO,
-					     NV_MEM_TARGET_VRAM,
-					     &chan->pushbuf);
-	} else {
-		/* NV04 cmdbuf hack, from original ddx.. not sure of it's
-		 * exact reason for existing :)  PCI access to cmdbuf in
-		 * VRAM.
-		 */
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     pci_resource_start(dev->pdev, 1),
-					     dev_priv->fb_available_size,
-					     NV_MEM_ACCESS_RO,
-					     NV_MEM_TARGET_PCI,
-					     &chan->pushbuf);
-	}
-
-out:
-	if (ret) {
-		NV_ERROR(dev, "error initialising pushbuf: %d\n", ret);
-		nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma);
-		nouveau_gpuobj_ref(NULL, &chan->pushbuf);
-		if (chan->pushbuf_bo) {
-			nouveau_bo_unmap(chan->pushbuf_bo);
-			nouveau_bo_ref(NULL, &chan->pushbuf_bo);
-		}
-	}
-
-	return 0;
-}
-
-/* allocates and initializes a fifo for user space consumption */
-int
-nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
-		      struct drm_file *file_priv,
-		      uint32_t vram_handle, uint32_t gart_handle)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct nouveau_fence_priv *fence = dev_priv->fence.func;
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int ret, i;
-
-	/* allocate and lock channel structure */
-	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
-	if (!chan)
-		return -ENOMEM;
-	chan->dev = dev;
-	chan->file_priv = file_priv;
-	chan->vram_handle = vram_handle;
-	chan->gart_handle = gart_handle;
-
-	kref_init(&chan->ref);
-	atomic_set(&chan->users, 1);
-	mutex_init(&chan->mutex);
-	mutex_lock(&chan->mutex);
-
-	/* allocate hw channel id */
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (chan->id = 0; chan->id < pfifo->channels; chan->id++) {
-		if ( dev_priv->card_type == NV_50 && chan->id == 0)
-			continue;
-
-		if (!dev_priv->channels.ptr[chan->id]) {
-			nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-
-	if (chan->id == pfifo->channels) {
-		mutex_unlock(&chan->mutex);
-		kfree(chan);
-		return -ENODEV;
-	}
-
-	NV_DEBUG(dev, "initialising channel %d\n", chan->id);
-
-	/* setup channel's memory and vm */
-	ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle);
-	if (ret) {
-		NV_ERROR(dev, "gpuobj %d\n", ret);
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	/* Allocate space for per-channel fixed notifier memory */
-	ret = nouveau_notifier_init_channel(chan);
-	if (ret) {
-		NV_ERROR(dev, "ntfy %d\n", ret);
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	/* Allocate DMA push buffer */
-	ret = nouveau_channel_pushbuf_init(chan);
-	if (ret) {
-		NV_ERROR(dev, "pushbuf %d\n", ret);
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	nouveau_dma_init(chan);
-	chan->user_put = 0x40;
-	chan->user_get = 0x44;
-	if (dev_priv->card_type >= NV_50)
-		chan->user_get_hi = 0x60;
-
-	/* create fifo context */
-	ret = pfifo->base.context_new(chan, NVOBJ_ENGINE_FIFO);
-	if (ret) {
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	/* Insert NOPs for NOUVEAU_DMA_SKIPS */
-	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
-	if (ret) {
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
-		OUT_RING  (chan, 0x00000000);
-
-	ret = nouveau_gpuobj_gr_new(chan, NvSw, nouveau_software_class(dev));
-	if (ret) {
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	if (dev_priv->card_type < NV_C0) {
-		ret = RING_SPACE(chan, 2);
-		if (ret) {
-			nouveau_channel_put(&chan);
-			return ret;
-		}
-
-		BEGIN_NV04(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
-		OUT_RING  (chan, NvSw);
-		FIRE_RING (chan);
-	}
-
-	FIRE_RING(chan);
-
-	ret = fence->context_new(chan);
-	if (ret) {
-		nouveau_channel_put(&chan);
-		return ret;
-	}
-
-	nouveau_debugfs_channel_init(chan);
-
-	NV_DEBUG(dev, "channel %d initialised\n", chan->id);
-	if (fpriv) {
-		spin_lock(&fpriv->lock);
-		list_add(&chan->list, &fpriv->channels);
-		spin_unlock(&fpriv->lock);
-	}
-	*chan_ret = chan;
-	return 0;
-}
-
-struct nouveau_channel *
-nouveau_channel_get_unlocked(struct nouveau_channel *ref)
-{
-	struct nouveau_channel *chan = NULL;
-
-	if (likely(ref && atomic_inc_not_zero(&ref->users)))
-		nouveau_channel_ref(ref, &chan);
-
-	return chan;
-}
-
-struct nouveau_channel *
-nouveau_channel_get(struct drm_file *file_priv, int id)
-{
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
-	struct nouveau_channel *chan;
-
-	spin_lock(&fpriv->lock);
-	list_for_each_entry(chan, &fpriv->channels, list) {
-		if (chan->id == id) {
-			chan = nouveau_channel_get_unlocked(chan);
-			spin_unlock(&fpriv->lock);
-			mutex_lock(&chan->mutex);
-			return chan;
-		}
-	}
-	spin_unlock(&fpriv->lock);
-
-	return ERR_PTR(-EINVAL);
-}
-
-void
-nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
-{
-	struct nouveau_channel *chan = *pchan;
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fence_priv *fence = dev_priv->fence.func;
-	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))) {
-		nouveau_channel_ref(NULL, pchan);
-		return;
-	}
-
-	/* no one wants the channel anymore */
-	NV_DEBUG(dev, "freeing channel %d\n", chan->id);
-	nouveau_debugfs_channel_fini(chan);
-
-	/* give it chance to idle */
-	nouveau_channel_idle(chan);
-
-	/* destroy the engine specific contexts */
-	for (i = NVOBJ_ENGINE_NR - 1; i >= 0; i--) {
-		if (chan->engctx[i])
-			dev_priv->eng[i]->context_del(chan, i);
-	}
-
-	if (chan->fence)
-		fence->context_del(chan);
-
-	/* aside from its resources, the channel should now be dead,
-	 * remove it from the channel list
-	 */
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	nouveau_channel_ref(NULL, &dev_priv->channels.ptr[chan->id]);
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-
-	/* destroy any resources the channel owned */
-	nouveau_gpuobj_ref(NULL, &chan->pushbuf);
-	if (chan->pushbuf_bo) {
-		nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma);
-		nouveau_bo_unmap(chan->pushbuf_bo);
-		nouveau_bo_unpin(chan->pushbuf_bo);
-		nouveau_bo_ref(NULL, &chan->pushbuf_bo);
-	}
-	nouveau_ramht_ref(NULL, &chan->ramht, chan);
-	nouveau_notifier_takedown_channel(chan);
-	nouveau_gpuobj_channel_takedown(chan);
-
-	nouveau_channel_ref(NULL, pchan);
-}
-
-void
-nouveau_channel_put(struct nouveau_channel **pchan)
-{
-	mutex_unlock(&(*pchan)->mutex);
-	nouveau_channel_put_unlocked(pchan);
-}
-
-static void
-nouveau_channel_del(struct kref *ref)
-{
-	struct nouveau_channel *chan =
-		container_of(ref, struct nouveau_channel, ref);
-
-	kfree(chan);
-}
-
-void
-nouveau_channel_ref(struct nouveau_channel *chan,
-		    struct nouveau_channel **pchan)
-{
-	if (chan)
-		kref_get(&chan->ref);
-
-	if (*pchan)
-		kref_put(&(*pchan)->ref, nouveau_channel_del);
-
-	*pchan = chan;
-}
-
-int
-nouveau_channel_idle(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_fence *fence = NULL;
-	int ret;
-
-	ret = nouveau_fence_new(chan, &fence);
-	if (!ret) {
-		ret = nouveau_fence_wait(fence, false, false);
-		nouveau_fence_unref(&fence);
-	}
-
-	if (ret)
-		NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
-	return ret;
-}
-
-/* cleans up all the fifos from file_priv */
-void
-nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct nouveau_channel *chan;
-	int i;
-
-	if (!pfifo)
-		return;
-
-	NV_DEBUG(dev, "clearing FIFO enables from file_priv\n");
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = nouveau_channel_get(file_priv, i);
-		if (IS_ERR(chan))
-			continue;
-
-		list_del(&chan->list);
-		atomic_dec(&chan->users);
-		nouveau_channel_put(&chan);
-	}
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_compat.c b/drivers/gpu/drm/nouveau/nouveau_compat.c
index 0403f2b..3db2349 100644
--- a/drivers/gpu/drm/nouveau/nouveau_compat.c
+++ b/drivers/gpu/drm/nouveau/nouveau_compat.c
@@ -1,4 +1,5 @@
 #include "nouveau_drm.h"
+#include "nouveau_chan.h"
 #include "nouveau_compat.h"
 
 #include <subdev/bios.h>
@@ -14,8 +15,6 @@
 #include <subdev/bar.h>
 #include <subdev/vm.h>
 
-void *nouveau_newpriv(struct drm_device *);
-
 int
 nvdrm_gart_init(struct drm_device *dev, u64 *base, u64 *size)
 {
@@ -583,3 +582,28 @@
 {
 	return vm->vmm->lpg_shift;
 }
+
+u64 nvgpuobj_addr(struct nouveau_object *object)
+{
+	return nv_gpuobj(object)->addr;
+}
+
+struct drm_device *
+nouveau_drv(void *ptr)
+{
+	struct nouveau_drm *drm = ptr;
+	return drm->dev;
+}
+
+struct nouveau_channel *
+nvdrm_channel(struct drm_device *dev)
+{
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	return drm->channel;
+}
+
+struct mutex *
+nvchan_mutex(struct nouveau_channel *chan)
+{
+	return &chan->cli->mutex;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_compat.h b/drivers/gpu/drm/nouveau/nouveau_compat.h
index d691b25..9f42d1d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_compat.h
+++ b/drivers/gpu/drm/nouveau/nouveau_compat.h
@@ -124,4 +124,18 @@
 int
 nvvm_lpg_shift(struct nouveau_vm *);
 
+u32
+nv50_display_active_crtcs(struct drm_device *dev);
+
+u64 nvgpuobj_addr(struct nouveau_object *object);
+
+struct drm_device *
+nouveau_drv(void *drm);
+
+struct nouveau_channel *
+nvdrm_channel(struct drm_device *dev);
+
+struct mutex *
+nvchan_mutex(struct nouveau_channel *chan);
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
deleted file mode 100644
index 6564b54..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
- *
- * 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 (including the
- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 <bskeggs@redhat.com>
- */
-
-#include <linux/debugfs.h>
-
-#include "drmP.h"
-#include "nouveau_drv.h"
-
-#include <ttm/ttm_page_alloc.h>
-
-static int
-nouveau_debugfs_channel_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct nouveau_channel *chan = node->info_ent->data;
-
-	seq_printf(m, "channel id    : %d\n", chan->id);
-
-	seq_printf(m, "cpu fifo state:\n");
-	seq_printf(m, "          base: 0x%10llx\n", chan->pushbuf_base);
-	seq_printf(m, "           max: 0x%08x\n", chan->dma.max << 2);
-	seq_printf(m, "           cur: 0x%08x\n", chan->dma.cur << 2);
-	seq_printf(m, "           put: 0x%08x\n", chan->dma.put << 2);
-	seq_printf(m, "          free: 0x%08x\n", chan->dma.free << 2);
-	if (chan->dma.ib_max) {
-		seq_printf(m, "        ib max: 0x%08x\n", chan->dma.ib_max);
-		seq_printf(m, "        ib put: 0x%08x\n", chan->dma.ib_put);
-		seq_printf(m, "       ib free: 0x%08x\n", chan->dma.ib_free);
-	}
-
-	seq_printf(m, "gpu fifo state:\n");
-	seq_printf(m, "           get: 0x%08x\n",
-					nvchan_rd32(chan, chan->user_get));
-	seq_printf(m, "           put: 0x%08x\n",
-					nvchan_rd32(chan, chan->user_put));
-	if (chan->dma.ib_max) {
-		seq_printf(m, "        ib get: 0x%08x\n",
-			   nvchan_rd32(chan, 0x88));
-		seq_printf(m, "        ib put: 0x%08x\n",
-			   nvchan_rd32(chan, 0x8c));
-	}
-
-	return 0;
-}
-
-int
-nouveau_debugfs_channel_init(struct nouveau_channel *chan)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct drm_minor *minor = chan->dev->primary;
-	int ret;
-
-	if (!dev_priv->debugfs.channel_root) {
-		dev_priv->debugfs.channel_root =
-			debugfs_create_dir("channel", minor->debugfs_root);
-		if (!dev_priv->debugfs.channel_root)
-			return -ENOENT;
-	}
-
-	snprintf(chan->debugfs.name, 32, "%d", chan->id);
-	chan->debugfs.info.name = chan->debugfs.name;
-	chan->debugfs.info.show = nouveau_debugfs_channel_info;
-	chan->debugfs.info.driver_features = 0;
-	chan->debugfs.info.data = chan;
-
-	ret = drm_debugfs_create_files(&chan->debugfs.info, 1,
-				       dev_priv->debugfs.channel_root,
-				       chan->dev->primary);
-	if (ret == 0)
-		chan->debugfs.active = true;
-	return ret;
-}
-
-void
-nouveau_debugfs_channel_fini(struct nouveau_channel *chan)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-
-	if (!chan->debugfs.active)
-		return;
-
-	drm_debugfs_remove_files(&chan->debugfs.info, 1, chan->dev->primary);
-	chan->debugfs.active = false;
-
-	if (chan == dev_priv->channel) {
-		debugfs_remove(dev_priv->debugfs.channel_root);
-		dev_priv->debugfs.channel_root = NULL;
-	}
-}
-
-static int
-nouveau_debugfs_chipset_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_minor *minor = node->minor;
-	struct drm_device *dev = minor->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t ppci_0;
-
-	ppci_0 = nv_rd32(dev, dev_priv->chipset >= 0x40 ? 0x88000 : 0x1800);
-
-	seq_printf(m, "PMC_BOOT_0: 0x%08x\n", nv_rd32(dev, NV03_PMC_BOOT_0));
-	seq_printf(m, "PCI ID    : 0x%04x:0x%04x\n",
-		   ppci_0 & 0xffff, ppci_0 >> 16);
-	return 0;
-}
-
-static int
-nouveau_debugfs_memory_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_minor *minor = node->minor;
-
-	seq_printf(m, "VRAM total: %dKiB\n", (int)(nvfb_vram_size(minor->dev) >> 10));
-	return 0;
-}
-
-static int
-nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
-	int i;
-
-	for (i = 0; i < dev_priv->vbios.length; i++)
-		seq_printf(m, "%c", dev_priv->vbios.data[i]);
-	return 0;
-}
-
-static int
-nouveau_debugfs_evict_vram(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
-	int ret;
-
-	ret = ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
-	if (ret)
-		seq_printf(m, "failed: %d", ret);
-	else
-		seq_printf(m, "succeeded\n");
-	return 0;
-}
-
-static struct drm_info_list nouveau_debugfs_list[] = {
-	{ "evict_vram", nouveau_debugfs_evict_vram, 0, NULL },
-	{ "chipset", nouveau_debugfs_chipset_info, 0, NULL },
-	{ "memory", nouveau_debugfs_memory_info, 0, NULL },
-	{ "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
-	{ "ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL },
-	{ "ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL },
-};
-#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
-
-int
-nouveau_debugfs_init(struct drm_minor *minor)
-{
-	drm_debugfs_create_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
-				 minor->debugfs_root, minor);
-	return 0;
-}
-
-void
-nouveau_debugfs_takedown(struct drm_minor *minor)
-{
-	drm_debugfs_remove_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
-				 minor);
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index e0a56b2..a60a9f5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -33,10 +33,10 @@
 #include "nouveau_crtc.h"
 #include "nouveau_dma.h"
 #include "nouveau_connector.h"
-#include "nouveau_software.h"
-#include "nouveau_fence.h"
 #include "nv50_display.h"
 
+#include "nouveau_fence.h"
+
 #include <subdev/bios/gpio.h>
 
 static void
@@ -260,6 +260,24 @@
 	disp->fini(dev);
 }
 
+static void
+nouveau_display_vblank_notify(void *data, int crtc)
+{
+	drm_handle_vblank(data, crtc);
+}
+
+static void
+nouveau_display_vblank_get(void *data, int crtc)
+{
+	drm_vblank_get(data, crtc);
+}
+
+static void
+nouveau_display_vblank_put(void *data, int crtc)
+{
+	drm_vblank_put(data, crtc);
+}
+
 int
 nouveau_display_create(struct drm_device *dev)
 {
@@ -365,6 +383,10 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
+	if (dev_priv->card_type >= NV_D0)
+		nv_mask(dev, 0x6100c0 + (crtc * 0x800), 1, 1);
+	else
+
 	if (dev_priv->card_type >= NV_50)
 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
@@ -380,6 +402,9 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
+	if (dev_priv->card_type >= NV_D0)
+		nv_mask(dev, 0x6100c0 + (crtc * 0x800), 1, 0);
+	else
 	if (dev_priv->card_type >= NV_50)
 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
@@ -436,8 +461,8 @@
 		       struct nouveau_fence **pfence)
 {
 	struct nouveau_fence_chan *fctx = chan->fence;
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct drm_device *dev = chan->dev;
+	struct drm_device *dev = nouveau_drv(chan->drm);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	unsigned long flags;
 	int ret;
 
@@ -492,7 +517,7 @@
 	struct nouveau_fence *fence;
 	int ret;
 
-	if (!dev_priv->channel)
+	if (!nvdrm_channel(dev))
 		return -ENODEV;
 
 	s = kzalloc(sizeof(*s), GFP_KERNEL);
@@ -513,10 +538,10 @@
 	/* Choose the channel the flip will be handled in */
 	fence = new_bo->bo.sync_obj;
 	if (fence)
-		chan = nouveau_channel_get_unlocked(fence->channel);
+		chan = fence->channel;
 	if (!chan)
-		chan = nouveau_channel_get_unlocked(dev_priv->channel);
-	mutex_lock(&chan->mutex);
+		chan = nvdrm_channel(dev);
+	mutex_lock(nvchan_mutex(chan));
 
 	/* Emit a page flip */
 	if (dev_priv->card_type >= NV_50) {
@@ -525,13 +550,13 @@
 		else
 			ret = nv50_display_flip_next(crtc, fb, chan);
 		if (ret) {
-			nouveau_channel_put(&chan);
+			mutex_unlock(nvchan_mutex(chan));
 			goto fail_unreserve;
 		}
 	}
 
 	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
-	nouveau_channel_put(&chan);
+	mutex_unlock(nvchan_mutex(chan));
 	if (ret)
 		goto fail_unreserve;
 
@@ -554,14 +579,14 @@
 			 struct nouveau_page_flip_state *ps)
 {
 	struct nouveau_fence_chan *fctx = chan->fence;
-	struct drm_device *dev = chan->dev;
+	struct drm_device *dev = nouveau_drv(chan->drm);
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
 	if (list_empty(&fctx->flip)) {
-		NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
+		NV_ERROR(dev, "unexpected pageflip\n");
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 		return -EINVAL;
 	}
@@ -592,7 +617,7 @@
 nouveau_flip_complete(void *data)
 {
 	struct nouveau_channel *chan = data;
-	struct drm_device *dev = chan->dev;
+	struct drm_device *dev = nouveau_drv(chan->drm);
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_page_flip_state state;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index efd0823..40f91e1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -24,41 +24,16 @@
  *
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
+#include <core/client.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
-
-void
-nouveau_dma_init(struct nouveau_channel *chan)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nouveau_bo *pushbuf = chan->pushbuf_bo;
-
-	if (dev_priv->card_type >= NV_50) {
-		const int ib_size = pushbuf->bo.mem.size / 2;
-
-		chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2;
-		chan->dma.ib_max = (ib_size / 8) - 1;
-		chan->dma.ib_put = 0;
-		chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
-
-		chan->dma.max = (pushbuf->bo.mem.size - ib_size) >> 2;
-	} else {
-		chan->dma.max  = (pushbuf->bo.mem.size >> 2) - 2;
-	}
-
-	chan->dma.put  = 0;
-	chan->dma.cur  = chan->dma.put;
-	chan->dma.free = chan->dma.max - chan->dma.cur;
-}
 
 void
 OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
 {
 	bool is_iomem;
-	u32 *mem = ttm_kmap_obj_virtual(&chan->pushbuf_bo->kmap, &is_iomem);
+	u32 *mem = ttm_kmap_obj_virtual(&chan->push.buffer->kmap, &is_iomem);
 	mem = &mem[chan->dma.cur];
 	if (is_iomem)
 		memcpy_toio((void __force __iomem *)mem, data, nr_dwords * 4);
@@ -79,9 +54,9 @@
 {
 	uint64_t val;
 
-	val = nvchan_rd32(chan, chan->user_get);
+	val = nv_ro32(chan->object, chan->user_get);
         if (chan->user_get_hi)
-                val |= (uint64_t)nvchan_rd32(chan, chan->user_get_hi) << 32;
+                val |= (uint64_t)nv_ro32(chan->object, chan->user_get_hi) << 32;
 
 	/* reset counter as long as GET is still advancing, this is
 	 * to avoid misdetecting a GPU lockup if the GPU happens to
@@ -93,32 +68,33 @@
 	}
 
 	if ((++*timeout & 0xff) == 0) {
-		DRM_UDELAY(1);
+		udelay(1);
 		if (*timeout > 100000)
 			return -EBUSY;
 	}
 
-	if (val < chan->pushbuf_base ||
-	    val > chan->pushbuf_base + (chan->dma.max << 2))
+	if (val < chan->push.vma.offset ||
+	    val > chan->push.vma.offset + (chan->dma.max << 2))
 		return -EINVAL;
 
-	return (val - chan->pushbuf_base) >> 2;
+	return (val - chan->push.vma.offset) >> 2;
 }
 
 void
 nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
 	      int delta, int length)
 {
-	struct nouveau_bo *pb = chan->pushbuf_bo;
+	struct nouveau_bo *pb = chan->push.buffer;
 	struct nouveau_vma *vma;
 	int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
 	u64 offset;
 
-	vma = nouveau_bo_vma_find(bo, chan->vm);
+	vma = nouveau_bo_vma_find(bo, nv_client(chan->cli)->vm);
 	BUG_ON(!vma);
 	offset = vma->offset + delta;
 
 	BUG_ON(chan->dma.ib_free < 1);
+
 	nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
 	nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8);
 
@@ -128,7 +104,7 @@
 	/* Flush writes. */
 	nouveau_bo_rd32(pb, 0);
 
-	nvchan_wr32(chan, 0x8c, chan->dma.ib_put);
+	nv_wo32(chan->object, 0x8c, chan->dma.ib_put);
 	chan->dma.ib_free--;
 }
 
@@ -138,7 +114,7 @@
 	uint32_t cnt = 0, prev_get = 0;
 
 	while (chan->dma.ib_free < count) {
-		uint32_t get = nvchan_rd32(chan, 0x88);
+		uint32_t get = nv_ro32(chan->object, 0x88);
 		if (get != prev_get) {
 			prev_get = get;
 			cnt = 0;
@@ -249,7 +225,7 @@
 			 * instruct the GPU to jump back to the start right
 			 * after processing the currently pending commands.
 			 */
-			OUT_RING(chan, chan->pushbuf_base | 0x20000000);
+			OUT_RING(chan, chan->push.vma.offset | 0x20000000);
 
 			/* wait for GET to depart from the skips area.
 			 * prevents writing GET==PUT and causing a race
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index 8db68be..5c2e229 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -27,10 +27,10 @@
 #ifndef __NOUVEAU_DMA_H__
 #define __NOUVEAU_DMA_H__
 
-#ifndef NOUVEAU_DMA_DEBUG
-#define NOUVEAU_DMA_DEBUG 0
-#endif
+#include "nouveau_bo.h"
+#include "nouveau_chan.h"
 
+int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
 void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *,
 		   int delta, int length);
 
@@ -116,12 +116,7 @@
 static inline void
 OUT_RING(struct nouveau_channel *chan, int data)
 {
-	if (NOUVEAU_DMA_DEBUG) {
-		NV_INFO(chan->dev, "Ch%d/0x%08x: 0x%08x\n",
-			chan->id, chan->dma.cur << 2, data);
-	}
-
-	nouveau_bo_wr32(chan->pushbuf_bo, chan->dma.cur++, data);
+	nouveau_bo_wr32(chan->push.buffer, chan->dma.cur++, data);
 }
 
 extern void
@@ -159,24 +154,19 @@
 
 #define WRITE_PUT(val) do {                                                    \
 	DRM_MEMORYBARRIER();                                                   \
-	nouveau_bo_rd32(chan->pushbuf_bo, 0);                                  \
-	nvchan_wr32(chan, chan->user_put, ((val) << 2) + chan->pushbuf_base);  \
+	nouveau_bo_rd32(chan->push.buffer, 0);                                 \
+	nv_wo32(chan->object, chan->user_put, ((val) << 2) + chan->push.vma.offset);  \
 } while (0)
 
 static inline void
 FIRE_RING(struct nouveau_channel *chan)
 {
-	if (NOUVEAU_DMA_DEBUG) {
-		NV_INFO(chan->dev, "Ch%d/0x%08x: PUSH!\n",
-			chan->id, chan->dma.cur << 2);
-	}
-
 	if (chan->dma.cur == chan->dma.put)
 		return;
 	chan->accel_done = true;
 
 	if (chan->dma.ib_max) {
-		nv50_dma_push(chan, chan->pushbuf_bo, chan->dma.put << 2,
+		nv50_dma_push(chan, chan->push.buffer, chan->dma.put << 2,
 			      (chan->dma.cur - chan->dma.put) << 2);
 	} else {
 		WRITE_PUT(chan->dma.cur);
@@ -191,4 +181,31 @@
 	chan->dma.cur = chan->dma.put;
 }
 
+/* FIFO methods */
+#define NV01_SUBCHAN_OBJECT                                          0x00000000
+#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH                          0x00000010
+#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_LOW                           0x00000014
+#define NV84_SUBCHAN_SEMAPHORE_SEQUENCE                              0x00000018
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER                               0x0000001c
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL                 0x00000001
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG                    0x00000002
+#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL                0x00000004
+#define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD                         0x00001000
+#define NV84_SUBCHAN_NOTIFY_INTR                                     0x00000020
+#define NV84_SUBCHAN_WRCACHE_FLUSH                                   0x00000024
+#define NV10_SUBCHAN_REF_CNT                                         0x00000050
+#define NVSW_SUBCHAN_PAGE_FLIP                                       0x00000054
+#define NV11_SUBCHAN_DMA_SEMAPHORE                                   0x00000060
+#define NV11_SUBCHAN_SEMAPHORE_OFFSET                                0x00000064
+#define NV11_SUBCHAN_SEMAPHORE_ACQUIRE                               0x00000068
+#define NV11_SUBCHAN_SEMAPHORE_RELEASE                               0x0000006c
+#define NV40_SUBCHAN_YIELD                                           0x00000080
+
+/* NV_SW object class */
+#define NV_SW_DMA_VBLSEM                                             0x0000018c
+#define NV_SW_VBLSEM_OFFSET                                          0x00000400
+#define NV_SW_VBLSEM_RELEASE_VALUE                                   0x00000404
+#define NV_SW_VBLSEM_RELEASE                                         0x00000408
+#define NV_SW_PAGE_FLIP                                              0x00000500
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 3b4e65d..92ecf50 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -27,12 +27,20 @@
 
 #include <core/device.h>
 #include <core/client.h>
+#include <core/gpuobj.h>
 #include <core/class.h>
 
 #include <subdev/device.h>
+#include <subdev/vm.h>
 
 #include "nouveau_drm.h"
+#include "nouveau_dma.h"
 #include "nouveau_agp.h"
+#include "nouveau_abi16.h"
+#include "nouveau_fbcon.h"
+#include "nouveau_fence.h"
+
+#include "nouveau_ttm.h"
 
 int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *);
 void nouveau_pci_remove(struct pci_dev *);
@@ -43,7 +51,6 @@
 
 int nouveau_load(struct drm_device *, unsigned long);
 int nouveau_unload(struct drm_device *);
-void *nouveau_newpriv(struct drm_device *);
 
 MODULE_PARM_DESC(config, "option string to pass to driver core");
 static char *nouveau_config;
@@ -53,6 +60,10 @@
 static char *nouveau_debug;
 module_param_named(debug, nouveau_debug, charp, 0400);
 
+MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration");
+static int nouveau_noaccel = 0;
+module_param_named(noaccel, nouveau_noaccel, int, 0400);
+
 static u64
 nouveau_name(struct pci_dev *pdev)
 {
@@ -82,17 +93,112 @@
 nouveau_cli_destroy(struct nouveau_cli *cli)
 {
 	struct nouveau_object *client = nv_object(cli);
+	nouveau_vm_ref(NULL, &cli->base.vm, NULL);
 	nouveau_client_fini(&cli->base, false);
 	atomic_set(&client->refcount, 1);
 	nouveau_object_ref(NULL, &client);
 }
 
+static void
+nouveau_accel_fini(struct nouveau_drm *drm)
+{
+	nouveau_gpuobj_ref(NULL, &drm->notify);
+	nouveau_channel_del(&drm->channel);
+	if (drm->fence)
+		nouveau_fence(drm)->dtor(drm);
+}
+
+static void
+nouveau_accel_init(struct nouveau_drm *drm)
+{
+	struct nouveau_device *device = nv_device(drm->device);
+	struct nouveau_object *object;
+	int ret;
+
+	if (nouveau_noaccel)
+		return;
+
+	/* initialise synchronisation routines */
+	if      (device->card_type < NV_10) ret = nv04_fence_create(drm);
+	else if (device->chipset   <  0x84) ret = nv10_fence_create(drm);
+	else if (device->card_type < NV_C0) ret = nv84_fence_create(drm);
+	else                                ret = nvc0_fence_create(drm);
+	if (ret) {
+		NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret);
+		nouveau_accel_fini(drm);
+		return;
+	}
+
+	ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN,
+				  NvDmaFB, NvDmaTT, &drm->channel);
+	if (ret) {
+		NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
+		nouveau_accel_fini(drm);
+		return;
+	}
+
+	if (device->card_type < NV_C0) {
+		ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0,
+					&drm->notify);
+		if (ret) {
+			NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
+			nouveau_accel_fini(drm);
+			return;
+		}
+
+		ret = nouveau_object_new(nv_object(drm),
+					 drm->channel->handle, NvNotify0,
+					 0x003d, &(struct nv_dma_class) {
+						.flags = NV_DMA_TARGET_VRAM |
+							 NV_DMA_ACCESS_RDWR,
+						.start = drm->notify->addr,
+						.limit = drm->notify->addr + 31
+						}, sizeof(struct nv_dma_class),
+					 &object);
+		if (ret) {
+			nouveau_accel_fini(drm);
+			return;
+		}
+	}
+
+
+	nouveau_bo_move_init(drm->channel);
+}
+
 static int __devinit
 nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent)
 {
 	struct nouveau_device *device;
+	struct apertures_struct *aper;
+	bool boot = false;
 	int ret;
 
+	/* remove conflicting drivers (vesafb, efifb etc) */
+	aper = alloc_apertures(3);
+	if (!aper)
+		return -ENOMEM;
+
+	aper->ranges[0].base = pci_resource_start(pdev, 1);
+	aper->ranges[0].size = pci_resource_len(pdev, 1);
+	aper->count = 1;
+
+	if (pci_resource_len(pdev, 2)) {
+		aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
+		aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
+		aper->count++;
+	}
+
+	if (pci_resource_len(pdev, 3)) {
+		aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
+		aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
+		aper->count++;
+	}
+
+#ifdef CONFIG_X86
+	boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+	remove_conflicting_framebuffers(aper, "nouveaufb", boot);
+
 	ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
 				    nouveau_config, nouveau_debug, &device);
 	if (ret)
@@ -102,7 +208,7 @@
 
 	ret = nouveau_pci_probe(pdev, pent);
 	if (ret) {
-		nouveau_device_destroy(&device);
+		nouveau_object_ref(NULL, (struct nouveau_object **)&device);
 		return ret;
 	}
 
@@ -113,6 +219,7 @@
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
 	struct pci_dev *pdev = dev->pdev;
+	struct nouveau_device *device;
 	struct nouveau_drm *drm;
 	int ret;
 
@@ -122,6 +229,7 @@
 		return ret;
 
 	INIT_LIST_HEAD(&drm->clients);
+	spin_lock_init(&drm->tile.lock);
 	drm->dev = dev;
 
 	/* make sure AGP controller is in a consistent state before we
@@ -142,7 +250,7 @@
 					 }, sizeof(struct nv_device_class),
 					 &drm->device);
 		if (ret)
-			return ret;
+			goto fail_device;
 
 		nouveau_agp_reset(drm);
 		nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE);
@@ -158,15 +266,32 @@
 	if (ret)
 		goto fail_device;
 
+	device = nv_device(drm->device);
+
 	/* initialise AGP */
 	nouveau_agp_init(drm);
 
-	ret = nouveau_load(dev, flags);
+	if (device->card_type >= NV_50) {
+		ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40),
+				     0x1000, &drm->client.base.vm);
+		if (ret)
+			goto fail_device;
+	}
+
+	ret = nouveau_ttm_init(drm);
 	if (ret)
 		goto fail_device;
 
+	ret = nouveau_load(dev, flags);
+	if (ret)
+		goto fail_load;
+
+	nouveau_accel_init(drm);
+	nouveau_fbcon_init(dev);
 	return 0;
 
+fail_load:
+	nouveau_ttm_fini(drm);
 fail_device:
 	nouveau_cli_destroy(&drm->client);
 	return ret;
@@ -179,10 +304,14 @@
 	struct pci_dev *pdev = dev->pdev;
 	int ret;
 
+	nouveau_fbcon_fini(dev);
+	nouveau_accel_fini(drm);
+
 	ret = nouveau_unload(dev);
 	if (ret)
 		return ret;
 
+	nouveau_ttm_fini(drm);
 	nouveau_agp_fini(drm);
 
 	pci_set_drvdata(pdev, drm->client.base.device);
@@ -193,10 +322,11 @@
 static void
 nouveau_drm_remove(struct pci_dev *pdev)
 {
-	struct nouveau_device *device;
+	struct nouveau_object *device;
 	nouveau_pci_remove(pdev);
 	device = pci_get_drvdata(pdev);
-	nouveau_device_destroy(&device);
+	nouveau_object_ref(NULL, &device);
+	nouveau_object_debug();
 }
 
 int
@@ -211,10 +341,23 @@
 	    pm_state.event == PM_EVENT_PRETHAW)
 		return 0;
 
+	NV_INFO(drm, "suspending fbcon...\n");
+	nouveau_fbcon_set_suspend(dev, 1);
+
+	NV_INFO(drm, "suspending drm...\n");
 	ret = nouveau_pci_suspend(pdev, pm_state);
 	if (ret)
 		return ret;
 
+	NV_INFO(drm, "evicting buffers...\n");
+	ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
+
+	if (drm->fence && nouveau_fence(drm)->suspend) {
+		if (!nouveau_fence(drm)->suspend(drm))
+			return -ENOMEM;
+	}
+
+	NV_INFO(drm, "suspending client object trees...\n");
 	list_for_each_entry(cli, &drm->clients, head) {
 		ret = nouveau_client_fini(&cli->base, true);
 		if (ret)
@@ -255,6 +398,7 @@
 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
 		return 0;
 
+	NV_INFO(drm, "re-enabling device...\n");
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 	ret = pci_enable_device(pdev);
@@ -264,17 +408,70 @@
 
 	nouveau_agp_reset(drm);
 
+	NV_INFO(drm, "resuming client object trees...\n");
 	nouveau_client_init(&drm->client.base);
+	nouveau_agp_init(drm);
 
 	list_for_each_entry(cli, &drm->clients, head) {
 		nouveau_client_init(&cli->base);
 	}
 
-	nouveau_agp_init(drm);
+	if (drm->fence && nouveau_fence(drm)->resume)
+		nouveau_fence(drm)->resume(drm);
 
 	return nouveau_pci_resume(pdev);
 }
 
+int
+nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
+{
+	struct pci_dev *pdev = dev->pdev;
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_cli *cli;
+	int ret;
+
+	ret = nouveau_cli_create(pdev, fpriv->pid, sizeof(*cli), (void **)&cli);
+	if (ret)
+		return ret;
+
+	if (nv_device(drm->device)->card_type >= NV_50) {
+		ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40),
+				     0x1000, &cli->base.vm);
+		if (ret) {
+			nouveau_cli_destroy(cli);
+			return ret;
+		}
+	}
+
+	fpriv->driver_priv = cli;
+
+	mutex_lock(&drm->client.mutex);
+	list_add(&cli->head, &drm->clients);
+	mutex_unlock(&drm->client.mutex);
+	return 0;
+}
+
+void
+nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv)
+{
+	struct nouveau_cli *cli = nouveau_cli(fpriv);
+	struct nouveau_drm *drm = nouveau_drm(dev);
+
+	if (cli->abi16)
+		nouveau_abi16_fini(cli->abi16);
+
+	mutex_lock(&drm->client.mutex);
+	list_del(&cli->head);
+	mutex_unlock(&drm->client.mutex);
+}
+
+void
+nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
+{
+	struct nouveau_cli *cli = nouveau_cli(fpriv);
+	nouveau_cli_destroy(cli);
+}
+
 static struct pci_device_id
 nouveau_drm_pci_table[] = {
 	{
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 8769806..2e3364d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -3,20 +3,50 @@
 
 #include <core/client.h>
 
+#include <subdev/vm.h>
+
 #include <drmP.h>
 #include <drm/nouveau_drm.h>
 
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_memory.h"
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_page_alloc.h"
+
+struct nouveau_channel;
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+#include "nouveau_revcompat.h"
+#include "nouveau_fence.h"
+
+struct nouveau_drm_tile {
+	struct nouveau_fence *fence;
+	bool used;
+};
+
 enum nouveau_drm_handle {
 	NVDRM_CLIENT = 0xffffffff,
 	NVDRM_DEVICE = 0xdddddddd,
+	NVDRM_PUSH   = 0xbbbb0000, /* |= client chid */
+	NVDRM_CHAN   = 0xcccc0000, /* |= client chid */
 };
 
 struct nouveau_cli {
 	struct nouveau_client base;
 	struct list_head head;
 	struct mutex mutex;
+	void *abi16;
 };
 
+static inline struct nouveau_cli *
+nouveau_cli(struct drm_file *fpriv)
+{
+	return fpriv ? fpriv->driver_priv : NULL;
+}
+
 struct nouveau_drm {
 	struct nouveau_cli client;
 	struct drm_device *dev;
@@ -33,8 +63,46 @@
 		u32 base;
 		u32 size;
 	} agp;
+
+	/* TTM interface support */
+	struct {
+		struct drm_global_reference mem_global_ref;
+		struct ttm_bo_global_ref bo_global_ref;
+		struct ttm_bo_device bdev;
+		atomic_t validate_sequence;
+		int (*move)(struct nouveau_channel *,
+			    struct ttm_buffer_object *,
+			    struct ttm_mem_reg *, struct ttm_mem_reg *);
+		int mtrr;
+	} ttm;
+
+	/* GEM interface support */
+	struct {
+		u64 vram_available;
+		u64 gart_available;
+	} gem;
+
+	/* synchronisation */
+	void *fence;
+
+	/* context for accelerated drm-internal operations */
+	struct nouveau_channel *channel;
+	struct nouveau_gpuobj *notify;
+	struct nouveau_fbdev *fbcon;
+
+	/* nv10-nv40 tiling regions */
+	struct {
+		struct nouveau_drm_tile reg[15];
+		spinlock_t lock;
+	} tile;
 };
 
+static inline struct nouveau_drm *
+nouveau_drm(struct drm_device *dev)
+{
+	return nouveau_newpriv(dev);
+}
+
 int nouveau_drm_suspend(struct pci_dev *, pm_message_t);
 int nouveau_drm_resume(struct pci_dev *);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index db150d9..2294cb8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -35,7 +35,6 @@
 #include "nouveau_fbcon.h"
 #include "nouveau_fence.h"
 #include "nouveau_pm.h"
-#include <engine/fifo.h>
 #include "nv50_display.h"
 
 #include "drm_pciids.h"
@@ -68,14 +67,6 @@
 int nouveau_ignorelid = 0;
 module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
 
-MODULE_PARM_DESC(noaccel, "Disable all acceleration");
-int nouveau_noaccel = -1;
-module_param_named(noaccel, nouveau_noaccel, int, 0400);
-
-MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
-int nouveau_nofbaccel = 0;
-module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
-
 MODULE_PARM_DESC(force_post, "Force POST");
 int nouveau_force_post = 0;
 module_param_named(force_post, nouveau_force_post, int, 0400);
@@ -148,19 +139,11 @@
 nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
 {
 	struct drm_device *dev = pci_get_drvdata(pdev);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct nouveau_fence_priv *fence = dev_priv->fence.func;
-	struct nouveau_channel *chan;
 	struct drm_crtc *crtc;
-	int ret, i, e;
 
 	NV_INFO(dev, "Disabling display...\n");
 	nouveau_display_fini(dev);
 
-	NV_INFO(dev, "Disabling fbcon...\n");
-	nouveau_fbcon_set_suspend(dev, 1);
-
 	NV_INFO(dev, "Unpinning framebuffer(s)...\n");
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
@@ -179,74 +162,23 @@
 		nouveau_bo_unpin(nv_crtc->cursor.nvbo);
 	}
 
-	NV_INFO(dev, "Evicting buffers...\n");
-	ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
-
-	NV_INFO(dev, "Idling channels...\n");
-	for (i = 0; i < (pfifo ? pfifo->channels : 0); i++) {
-		chan = dev_priv->channels.ptr[i];
-
-		if (chan && chan->pushbuf_bo)
-			nouveau_channel_idle(chan);
-	}
-
-	if (fence->suspend) {
-		if (!fence->suspend(dev))
-			return -ENOMEM;
-	}
-
-	for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
-		if (!dev_priv->eng[e])
-			continue;
-
-		ret = dev_priv->eng[e]->fini(dev, e, true);
-		if (ret) {
-			NV_ERROR(dev, "... engine %d failed: %d\n", e, ret);
-			goto out_abort;
-		}
-	}
-
 	return 0;
-
-out_abort:
-	NV_INFO(dev, "Re-enabling acceleration..\n");
-	for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
-		if (dev_priv->eng[e])
-			dev_priv->eng[e]->init(dev, e);
-	}
-	return ret;
 }
 
 int
 nouveau_pci_resume(struct pci_dev *pdev)
 {
 	struct drm_device *dev = pci_get_drvdata(pdev);
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fence_priv *fence = dev_priv->fence.func;
-	struct nouveau_engine *engine = &dev_priv->engine;
 	struct drm_crtc *crtc;
-	int ret, i;
+	int ret;
 
-	/* Make the CRTCs accessible */
-	engine->display.early_init(dev);
-
-	NV_INFO(dev, "POSTing device...\n");
 	ret = nouveau_run_vbios_init(dev);
 	if (ret)
 		return ret;
 
-	NV_INFO(dev, "Reinitialising engines...\n");
-	for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
-		if (dev_priv->eng[i])
-			dev_priv->eng[i]->init(dev, i);
-	}
-
-	if (fence->resume)
-		fence->resume(dev);
-
 	nouveau_irq_postinstall(dev);
 
+#if 0
 	/* Re-write SKIPS, they'll have been lost over the suspend */
 	if (nouveau_vram_pushbuf) {
 		struct nouveau_channel *chan;
@@ -261,6 +193,7 @@
 				nouveau_bo_wr32(chan->pushbuf_bo, i, 0);
 		}
 	}
+#endif
 
 	nouveau_pm_resume(dev);
 
@@ -343,6 +276,9 @@
 
 int nouveau_drm_load(struct drm_device *, unsigned long);
 int nouveau_drm_unload(struct drm_device *);
+int  nouveau_drm_open(struct drm_device *, struct drm_file *);
+void nouveau_drm_preclose(struct drm_device *dev, struct drm_file *);
+void nouveau_drm_postclose(struct drm_device *, struct drm_file *);
 
 static struct drm_driver driver = {
 	.driver_features =
@@ -353,13 +289,9 @@
 	.firstopen = nouveau_firstopen,
 	.lastclose = nouveau_lastclose,
 	.unload = nouveau_drm_unload,
-	.open = nouveau_open,
-	.preclose = nouveau_preclose,
-	.postclose = nouveau_postclose,
-#if defined(CONFIG_DRM_NOUVEAU_DEBUG)
-	.debugfs_init = nouveau_debugfs_init,
-	.debugfs_cleanup = nouveau_debugfs_takedown,
-#endif
+	.open = nouveau_drm_open,
+	.preclose = nouveau_drm_preclose,
+	.postclose = nouveau_drm_postclose,
 	.irq_preinstall = nouveau_irq_preinstall,
 	.irq_postinstall = nouveau_irq_postinstall,
 	.irq_uninstall = nouveau_irq_uninstall,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 08ce60b..f1cce65 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -64,24 +64,11 @@
 	NV_MEM_TYPE_GDDR5
 };
 
-struct nouveau_fpriv {
-	spinlock_t lock;
-	struct list_head channels;
-	struct nouveau_vm *vm;
-};
-
-static inline struct nouveau_fpriv *
-nouveau_fpriv(struct drm_file *file_priv)
-{
-	return file_priv ? file_priv->driver_priv : NULL;
-}
-
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
 #include <nouveau_drm.h>
 #include "nouveau_reg.h"
 #include <nouveau_bios.h>
-#include "nouveau_util.h"
 
 struct nouveau_grctx;
 struct nouveau_mem;
@@ -90,8 +77,7 @@
 #include "nouveau_compat.h"
 
 #define nouveau_gpuobj_new(d,c,s,a,f,o) \
-	_nouveau_gpuobj_new((d), (c) ? ((struct nouveau_channel *)(c))->ramin : NULL, \
-			    (s), (a), (f), (o))
+	_nouveau_gpuobj_new((d), NULL, (s), (a), (f), (o))
 
 #define nouveau_vm_new(d,o,l,m,v) \
 	_nouveau_vm_new((d), (o), (l), (m), (v))
@@ -102,40 +88,15 @@
 #define MAX_NUM_DCB_ENTRIES 16
 
 #define NOUVEAU_MAX_CHANNEL_NR 4096
-#define NOUVEAU_MAX_TILE_NR 15
 
 #include "nouveau_bo.h"
 #include "nouveau_gem.h"
 
-/* TODO: submit equivalent to TTM generic API upstream? */
-static inline void __iomem *
-nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
-{
-	bool is_iomem;
-	void __iomem *ioptr = (void __force __iomem *)ttm_kmap_obj_virtual(
-						&nvbo->kmap, &is_iomem);
-	WARN_ON_ONCE(ioptr && !is_iomem);
-	return ioptr;
-}
-
 enum nouveau_flags {
 	NV_NFORCE   = 0x10000000,
 	NV_NFORCE2  = 0x20000000
 };
 
-#define NVOBJ_ENGINE_SW		0
-#define NVOBJ_ENGINE_GR		1
-#define NVOBJ_ENGINE_CRYPT	2
-#define NVOBJ_ENGINE_COPY0	3
-#define NVOBJ_ENGINE_COPY1	4
-#define NVOBJ_ENGINE_MPEG	5
-#define NVOBJ_ENGINE_PPP	NVOBJ_ENGINE_MPEG
-#define NVOBJ_ENGINE_BSP	6
-#define NVOBJ_ENGINE_VP		7
-#define NVOBJ_ENGINE_FIFO	14
-#define NVOBJ_ENGINE_NR		16
-#define NVOBJ_ENGINE_DISPLAY	(NVOBJ_ENGINE_NR + 0) /*XXX*/
-
 struct nouveau_page_flip_state {
 	struct list_head head;
 	struct drm_pending_vblank_event *event;
@@ -148,95 +109,6 @@
 	NOUVEAU_KCHANNEL_MUTEX
 };
 
-struct nouveau_channel {
-	struct drm_device *dev;
-	struct list_head list;
-	int id;
-
-	/* references to the channel data structure */
-	struct kref ref;
-	/* users of the hardware channel resources, the hardware
-	 * context will be kicked off when it reaches zero. */
-	atomic_t users;
-	struct mutex mutex;
-
-	/* owner of this fifo */
-	struct drm_file *file_priv;
-	/* mapping of the fifo itself */
-	struct drm_local_map *map;
-
-	/* mapping of the regs controlling the fifo */
-	void __iomem *user;
-	uint32_t user_get;
-	uint32_t user_get_hi;
-	uint32_t user_put;
-
-	/* DMA push buffer */
-	struct nouveau_gpuobj *pushbuf;
-	struct nouveau_bo     *pushbuf_bo;
-	struct nouveau_vma     pushbuf_vma;
-	uint64_t               pushbuf_base;
-
-	/* Notifier memory */
-	struct nouveau_bo *notifier_bo;
-	struct nouveau_vma notifier_vma;
-	struct drm_mm notifier_heap;
-
-	/* PFIFO context */
-	struct nouveau_gpuobj *engptr;
-	struct nouveau_gpuobj *ramfc;
-
-	/* Execution engine contexts */
-	void *engctx[NVOBJ_ENGINE_NR];
-	void *fence;
-
-	/* NV50 VM */
-	struct nouveau_vm     *vm;
-	struct nouveau_gpuobj *vm_pd;
-
-	/* Objects */
-	struct nouveau_gpuobj *ramin; /* Private instmem */
-	struct nouveau_ramht  *ramht; /* Hash table */
-
-	/* GPU object info for stuff used in-kernel (mm_enabled) */
-	uint32_t m2mf_ntfy;
-	uint32_t vram_handle;
-	uint32_t gart_handle;
-	bool accel_done;
-
-	/* Push buffer state (only for drm's channel on !mm_enabled) */
-	struct {
-		int max;
-		int free;
-		int cur;
-		int put;
-		/* access via pushbuf_bo */
-
-		int ib_base;
-		int ib_max;
-		int ib_free;
-		int ib_put;
-	} dma;
-
-	struct {
-		bool active;
-		char name[32];
-		struct drm_info_list info;
-	} 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, bool suspend);
-	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 (*set_tile_region)(struct drm_device *dev, int i);
-	void (*tlb_flush)(struct drm_device *, int engine);
-};
-
 struct nouveau_display_engine {
 	void *priv;
 	int (*early_init)(struct drm_device *);
@@ -434,6 +306,8 @@
 	NV_E0      = 0xe0,
 };
 
+struct nouveau_channel;
+
 struct drm_nouveau_private {
 	struct drm_device *dev;
 	bool noaccel;
@@ -447,92 +321,29 @@
 	int flags;
 	u32 crystal;
 
-	struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
-
-	struct list_head classes;
-
 	struct nouveau_bo *vga_ram;
 
 	/* interrupt handling */
 	void (*irq_handler[32])(struct drm_device *);
 	bool msi_enabled;
 
-	struct {
-		struct drm_global_reference mem_global_ref;
-		struct ttm_bo_global_ref bo_global_ref;
-		struct ttm_bo_device bdev;
-		atomic_t validate_sequence;
-		int (*move)(struct nouveau_channel *,
-			    struct ttm_buffer_object *,
-			    struct ttm_mem_reg *, struct ttm_mem_reg *);
-	} ttm;
-
-	struct {
-		void *func;
-		spinlock_t lock;
-		struct drm_mm heap;
-		struct nouveau_bo *bo;
-	} fence;
-
-	struct {
-		spinlock_t lock;
-		struct nouveau_channel *ptr[NOUVEAU_MAX_CHANNEL_NR];
-	} channels;
-
 	struct nouveau_engine engine;
-	struct nouveau_channel *channel;
 
 	/* For PFIFO and PGRAPH. */
 	spinlock_t context_switch_lock;
 
-	/* VM/PRAMIN flush, legacy PRAMIN aperture */
-	spinlock_t vm_lock;
-
 	/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
 	struct nouveau_ramht  *ramht;
 
-	struct {
-		enum {
-			NOUVEAU_GART_NONE = 0,
-			NOUVEAU_GART_AGP,	/* AGP */
-			NOUVEAU_GART_PDMA,	/* paged dma object */
-			NOUVEAU_GART_HW		/* on-chip gart/vm */
-		} type;
-		uint64_t aper_base;
-		uint64_t aper_size;
-		uint64_t aper_free;
-
-		struct ttm_backend_func *func;
-
-		struct nouveau_gpuobj *sg_ctxdma;
-	} gart_info;
-
-	/* nv10-nv40 tiling regions */
-	struct {
-		struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
-		spinlock_t lock;
-	} tile;
-
 	uint64_t fb_available_size;
 	uint64_t fb_mappable_pages;
-	uint64_t fb_aper_free;
 	int fb_mtrr;
 
-	/* G8x/G9x virtual address space */
-	struct nouveau_vm *chan_vm;
-
 	struct nvbios vbios;
 	u8 *mxms;
 	struct list_head i2c_ports;
 
 	struct backlight_device *backlight;
-
-	struct {
-		struct dentry *channel_root;
-	} debugfs;
-
-	struct nouveau_fbdev *nfbdev;
-	struct apertures_struct *apertures;
 };
 
 static inline struct drm_nouveau_private *
@@ -541,12 +352,6 @@
 	return dev->dev_private;
 }
 
-static inline struct drm_nouveau_private *
-nouveau_bdev(struct ttm_bo_device *bd)
-{
-	return container_of(bd, struct drm_nouveau_private, ttm.bdev);
-}
-
 /* nouveau_drv.c */
 extern int nouveau_modeset;
 extern int nouveau_duallink;
@@ -560,7 +365,6 @@
 extern char *nouveau_tv_norm;
 extern int nouveau_reg_debug;
 extern int nouveau_ignorelid;
-extern int nouveau_nofbaccel;
 extern int nouveau_noaccel;
 extern int nouveau_force_post;
 extern int nouveau_override_conntype;
@@ -574,9 +378,6 @@
 extern int nouveau_pci_resume(struct pci_dev *pdev);
 
 /* nouveau_state.c */
-extern int  nouveau_open(struct drm_device *, struct drm_file *);
-extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
-extern void nouveau_postclose(struct drm_device *, struct drm_file *);
 extern int  nouveau_load(struct drm_device *, unsigned long flags);
 extern int  nouveau_firstopen(struct drm_device *);
 extern void nouveau_lastclose(struct drm_device *);
@@ -596,76 +397,16 @@
 extern void nouveau_mem_timing_read(struct drm_device *,
 				    struct nouveau_pm_memtiming *);
 extern int nouveau_mem_vbios_type(struct drm_device *);
-extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
-extern const struct ttm_mem_type_manager_func nouveau_gart_manager;
-extern const struct ttm_mem_type_manager_func nv04_gart_manager;
+extern struct nouveau_tile_reg *nv10_mem_set_tiling(
+	struct drm_device *dev, uint32_t addr, uint32_t size,
+	uint32_t pitch, uint32_t flags);
+extern void nv10_mem_put_tile_region(struct drm_device *dev,
+				     struct nouveau_tile_reg *tile,
+				     struct nouveau_fence *fence);
 
-/* nouveau_notifier.c */
-extern int  nouveau_notifier_init_channel(struct nouveau_channel *);
-extern void nouveau_notifier_takedown_channel(struct nouveau_channel *);
-extern int  nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle,
-				   int cout, uint32_t start, uint32_t end,
-				   uint32_t *offset);
-
-/* nouveau_channel.c */
-extern void nouveau_channel_cleanup(struct drm_device *, struct drm_file *);
-extern int  nouveau_channel_alloc(struct drm_device *dev,
-				  struct nouveau_channel **chan,
-				  struct drm_file *file_priv,
-				  uint32_t fb_ctxdma, uint32_t tt_ctxdma);
-extern struct nouveau_channel *
-nouveau_channel_get_unlocked(struct nouveau_channel *);
-extern struct nouveau_channel *
-nouveau_channel_get(struct drm_file *, int id);
-extern void nouveau_channel_put_unlocked(struct nouveau_channel **);
-extern void nouveau_channel_put(struct nouveau_channel **);
-extern void nouveau_channel_ref(struct nouveau_channel *chan,
-				struct nouveau_channel **pchan);
 extern int  nouveau_channel_idle(struct nouveau_channel *chan);
 
 /* nouveau_gpuobj.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)                                                               \
-		return ret;                                                    \
-} while (0)
-
-#define NVOBJ_MTHD(d, c, m, e) do {                                            \
-	int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e));                 \
-	if (ret)                                                               \
-		return ret;                                                    \
-} while (0)
-
-extern int  nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
-extern int  nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
-				    int (*exec)(struct nouveau_channel *,
-						u32 class, u32 mthd, u32 data));
-extern int  nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
-extern int  nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
-extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
-				       uint32_t vram_h, uint32_t tt_h);
-extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
-extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
-				  uint64_t offset, uint64_t size, int access,
-				  int target, struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, u32 handle, int class);
-extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base,
-			       u64 size, int target, int access, u32 type,
-			       u32 comp, struct nouveau_gpuobj **pobj);
-extern void nv50_gpuobj_dma_init(struct nouveau_gpuobj *, u32 offset,
-				 int class, u64 base, u64 size, int target,
-				 int access, u32 type, u32 comp);
-
 int  nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
 			   u32 flags, struct nouveau_vma *vma);
 void nouveau_gpuobj_unmap(struct nouveau_vma *vma);
@@ -681,49 +422,6 @@
 extern int         nouveau_irq_postinstall(struct drm_device *);
 extern void        nouveau_irq_uninstall(struct drm_device *);
 
-/* nouveau_sgdma.c */
-extern int nouveau_sgdma_init(struct drm_device *);
-extern void nouveau_sgdma_takedown(struct drm_device *);
-extern uint32_t nouveau_sgdma_get_physical(struct drm_device *,
-					   uint32_t offset);
-extern struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev,
-					       unsigned long size,
-					       uint32_t page_flags,
-					       struct page *dummy_read_page);
-
-/* nouveau_debugfs.c */
-#if defined(CONFIG_DRM_NOUVEAU_DEBUG)
-extern int  nouveau_debugfs_init(struct drm_minor *);
-extern void nouveau_debugfs_takedown(struct drm_minor *);
-extern int  nouveau_debugfs_channel_init(struct nouveau_channel *);
-extern void nouveau_debugfs_channel_fini(struct nouveau_channel *);
-#else
-static inline int
-nouveau_debugfs_init(struct drm_minor *minor)
-{
-	return 0;
-}
-
-static inline void nouveau_debugfs_takedown(struct drm_minor *minor)
-{
-}
-
-static inline int
-nouveau_debugfs_channel_init(struct nouveau_channel *chan)
-{
-	return 0;
-}
-
-static inline void
-nouveau_debugfs_channel_fini(struct nouveau_channel *chan)
-{
-}
-#endif
-
-/* nouveau_dma.c */
-extern void nouveau_dma_init(struct nouveau_channel *);
-extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
-
 /* nouveau_acpi.c */
 #define ROM_BIOS_PAGE 4096
 #if defined(CONFIG_ACPI)
@@ -785,72 +483,8 @@
 /* nouveau_hdmi.c */
 void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *);
 
-/* nv04_graph.c */
-extern int  nv04_graph_create(struct drm_device *);
-extern int  nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
-extern int  nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
-				      u32 class, u32 mthd, u32 data);
-extern struct nouveau_bitfield nv04_graph_nsource[];
-
-/* nv10_graph.c */
-extern int  nv10_graph_create(struct drm_device *);
-extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern struct nouveau_bitfield nv10_graph_intr[];
-extern struct nouveau_bitfield nv10_graph_nstatus[];
-
-/* nv20_graph.c */
-extern int  nv20_graph_create(struct drm_device *);
-
-/* nv40_graph.c */
-extern int  nv40_graph_create(struct drm_device *);
-extern void nv40_grctx_init(struct drm_device *, u32 *size);
-extern void nv40_grctx_fill(struct drm_device *, struct nouveau_gpuobj *);
-
-/* nv50_graph.c */
-extern int  nv50_graph_create(struct drm_device *);
-extern struct nouveau_enum nv50_data_error_names[];
-extern int  nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
-extern int  nv50_grctx_init(struct drm_device *, u32 *, u32, u32 *, u32 *);
-extern void nv50_grctx_fill(struct drm_device *, struct nouveau_gpuobj *);
-
-/* nvc0_graph.c */
-extern int  nvc0_graph_create(struct drm_device *);
-extern int  nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
-
-/* nve0_graph.c */
-extern int  nve0_graph_create(struct drm_device *);
-
-/* nv84_crypt.c */
-extern int  nv84_crypt_create(struct drm_device *);
-
-/* nv98_crypt.c */
-extern int  nv98_crypt_create(struct drm_device *dev);
-
-/* nva3_copy.c */
-extern int  nva3_copy_create(struct drm_device *dev);
-
-/* nvc0_copy.c */
-extern int  nvc0_copy_create(struct drm_device *dev, int engine);
-
-/* nv31_mpeg.c */
-extern int  nv31_mpeg_create(struct drm_device *dev);
-
-/* nv50_mpeg.c */
-extern int  nv50_mpeg_create(struct drm_device *dev);
-
-/* nv84_bsp.c */
-/* nv98_bsp.c */
-extern int  nv84_bsp_create(struct drm_device *dev);
-
-/* nv84_vp.c */
-/* nv98_vp.c */
-extern int  nv84_vp_create(struct drm_device *dev);
-
-/* nv98_ppp.c */
-extern int  nv98_ppp_create(struct drm_device *dev);
-
 extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
-				 unsigned long arg);
+			         unsigned long arg);
 
 /* nvd0_display.c */
 extern int nvd0_display_create(struct drm_device *);
@@ -895,18 +529,6 @@
 #endif /* def __BIG_ENDIAN else */
 #endif /* !ioread32_native */
 
-/* channel control reg access */
-static inline u32 nvchan_rd32(struct nouveau_channel *chan, unsigned reg)
-{
-	return ioread32_native(chan->user + reg);
-}
-
-static inline void nvchan_wr32(struct nouveau_channel *chan,
-							unsigned reg, u32 val)
-{
-	iowrite32_native(val, chan->user + reg);
-}
-
 /* register access */
 #define nv_rd08 _nv_rd08
 #define nv_wr08 _nv_wr08
@@ -1023,13 +645,6 @@
 		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
  */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index f3f0b4c3..8b8bc83 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -43,19 +43,31 @@
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
-#include "nouveau_drv.h"
-#include <nouveau_drm.h>
-#include "nouveau_crtc.h"
+
+#include "nouveau_drm.h"
+#include "nouveau_gem.h"
+#include "nouveau_bo.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
-#include "nouveau_dma.h"
+#include "nouveau_chan.h"
+
+#include "nouveau_crtc.h"
+
+#include <core/client.h>
+#include <core/device.h>
+
+#include <subdev/fb.h>
+
+MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
+static int nouveau_nofbaccel = 0;
+module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 
 static void
 nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fbdev *fbcon = info->par;
+	struct nouveau_drm *drm = nouveau_newpriv(fbcon->dev);
+	struct nouveau_device *device = nv_device(drm->device);
 	int ret;
 
 	if (info->state != FBINFO_STATE_RUNNING)
@@ -63,15 +75,15 @@
 
 	ret = -ENODEV;
 	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-	    mutex_trylock(&dev_priv->channel->mutex)) {
-		if (dev_priv->card_type < NV_50)
+	    mutex_trylock(&drm->client.mutex)) {
+		if (device->card_type < NV_50)
 			ret = nv04_fbcon_fillrect(info, rect);
 		else
-		if (dev_priv->card_type < NV_C0)
+		if (device->card_type < NV_C0)
 			ret = nv50_fbcon_fillrect(info, rect);
 		else
 			ret = nvc0_fbcon_fillrect(info, rect);
-		mutex_unlock(&dev_priv->channel->mutex);
+		mutex_unlock(&drm->client.mutex);
 	}
 
 	if (ret == 0)
@@ -85,9 +97,9 @@
 static void
 nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
 {
-	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fbdev *fbcon = info->par;
+	struct nouveau_drm *drm = nouveau_newpriv(fbcon->dev);
+	struct nouveau_device *device = nv_device(drm->device);
 	int ret;
 
 	if (info->state != FBINFO_STATE_RUNNING)
@@ -95,15 +107,15 @@
 
 	ret = -ENODEV;
 	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-	    mutex_trylock(&dev_priv->channel->mutex)) {
-		if (dev_priv->card_type < NV_50)
+	    mutex_trylock(&drm->client.mutex)) {
+		if (device->card_type < NV_50)
 			ret = nv04_fbcon_copyarea(info, image);
 		else
-		if (dev_priv->card_type < NV_C0)
+		if (device->card_type < NV_C0)
 			ret = nv50_fbcon_copyarea(info, image);
 		else
 			ret = nvc0_fbcon_copyarea(info, image);
-		mutex_unlock(&dev_priv->channel->mutex);
+		mutex_unlock(&drm->client.mutex);
 	}
 
 	if (ret == 0)
@@ -117,9 +129,9 @@
 static void
 nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 {
-	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fbdev *fbcon = info->par;
+	struct nouveau_drm *drm = nouveau_newpriv(fbcon->dev);
+	struct nouveau_device *device = nv_device(drm->device);
 	int ret;
 
 	if (info->state != FBINFO_STATE_RUNNING)
@@ -127,15 +139,15 @@
 
 	ret = -ENODEV;
 	if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-	    mutex_trylock(&dev_priv->channel->mutex)) {
-		if (dev_priv->card_type < NV_50)
+	    mutex_trylock(&drm->client.mutex)) {
+		if (device->card_type < NV_50)
 			ret = nv04_fbcon_imageblit(info, image);
 		else
-		if (dev_priv->card_type < NV_C0)
+		if (device->card_type < NV_C0)
 			ret = nv50_fbcon_imageblit(info, image);
 		else
 			ret = nvc0_fbcon_imageblit(info, image);
-		mutex_unlock(&dev_priv->channel->mutex);
+		mutex_unlock(&drm->client.mutex);
 	}
 
 	if (ret == 0)
@@ -149,10 +161,9 @@
 static int
 nouveau_fbcon_sync(struct fb_info *info)
 {
-	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_fbdev *fbcon = info->par;
+	struct nouveau_drm *drm = nouveau_newpriv(fbcon->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	if (!chan || !chan->accel_done || in_interrupt() ||
@@ -160,11 +171,11 @@
 	    info->flags & FBINFO_HWACCEL_DISABLED)
 		return 0;
 
-	if (!mutex_trylock(&chan->mutex))
+	if (!mutex_trylock(&drm->client.mutex))
 		return 0;
 
 	ret = nouveau_channel_idle(chan);
-	mutex_unlock(&chan->mutex);
+	mutex_unlock(&drm->client.mutex);
 	if (ret) {
 		nouveau_fbcon_gpu_lockup(info);
 		return 0;
@@ -224,9 +235,9 @@
 }
 
 static void
-nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
+nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
-	struct fb_info *info = nfbdev->helper.fbdev;
+	struct fb_info *info = fbcon->helper.fbdev;
 	struct fb_fillrect rect;
 
 	/* Clear the entire fbcon.  The drm will program every connector
@@ -242,11 +253,12 @@
 }
 
 static int
-nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
+nouveau_fbcon_create(struct nouveau_fbdev *fbcon,
 		     struct drm_fb_helper_surface_size *sizes)
 {
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct drm_device *dev = fbcon->dev;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_device *device = nv_device(drm->device);
 	struct fb_info *info;
 	struct drm_framebuffer *fb;
 	struct nouveau_framebuffer *nouveau_fb;
@@ -254,7 +266,6 @@
 	struct nouveau_bo *nvbo;
 	struct drm_mode_fb_cmd2 mode_cmd;
 	struct pci_dev *pdev = dev->pdev;
-	struct device *device = &pdev->dev;
 	int size, ret;
 
 	mode_cmd.width = sizes->surface_width;
@@ -272,37 +283,38 @@
 	ret = nouveau_gem_new(dev, size, 0, NOUVEAU_GEM_DOMAIN_VRAM,
 			      0, 0x0000, &nvbo);
 	if (ret) {
-		NV_ERROR(dev, "failed to allocate framebuffer\n");
+		NV_ERROR(drm, "failed to allocate framebuffer\n");
 		goto out;
 	}
 
 	ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM);
 	if (ret) {
-		NV_ERROR(dev, "failed to pin fb: %d\n", ret);
+		NV_ERROR(drm, "failed to pin fb: %d\n", ret);
 		nouveau_bo_ref(NULL, &nvbo);
 		goto out;
 	}
 
 	ret = nouveau_bo_map(nvbo);
 	if (ret) {
-		NV_ERROR(dev, "failed to map fb: %d\n", ret);
+		NV_ERROR(drm, "failed to map fb: %d\n", ret);
 		nouveau_bo_unpin(nvbo);
 		nouveau_bo_ref(NULL, &nvbo);
 		goto out;
 	}
 
-	chan = nouveau_nofbaccel ? NULL : dev_priv->channel;
-	if (chan && dev_priv->card_type >= NV_50) {
-		ret = nouveau_bo_vma_add(nvbo, chan->vm, &nfbdev->nouveau_fb.vma);
+	chan = nouveau_nofbaccel ? NULL : drm->channel;
+	if (chan && device->card_type >= NV_50) {
+		ret = nouveau_bo_vma_add(nvbo, nv_client(chan->cli)->vm,
+					&fbcon->nouveau_fb.vma);
 		if (ret) {
-			NV_ERROR(dev, "failed to map fb into chan: %d\n", ret);
+			NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
 			chan = NULL;
 		}
 	}
 
 	mutex_lock(&dev->struct_mutex);
 
-	info = framebuffer_alloc(0, device);
+	info = framebuffer_alloc(0, &pdev->dev);
 	if (!info) {
 		ret = -ENOMEM;
 		goto out_unref;
@@ -314,16 +326,16 @@
 		goto out_unref;
 	}
 
-	info->par = nfbdev;
+	info->par = fbcon;
 
-	nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
+	nouveau_framebuffer_init(dev, &fbcon->nouveau_fb, &mode_cmd, nvbo);
 
-	nouveau_fb = &nfbdev->nouveau_fb;
+	nouveau_fb = &fbcon->nouveau_fb;
 	fb = &nouveau_fb->base;
 
 	/* setup helper */
-	nfbdev->helper.fb = fb;
-	nfbdev->helper.fbdev = info;
+	fbcon->helper.fb = fb;
+	fbcon->helper.fbdev = info;
 
 	strcpy(info->fix.id, "nouveaufb");
 	if (nouveau_nofbaccel)
@@ -342,25 +354,18 @@
 	info->screen_size = size;
 
 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
-	drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
-
-	/* Set aperture base/size for vesafb takeover */
-	info->apertures = dev_priv->apertures;
-	if (!info->apertures) {
-		ret = -ENOMEM;
-		goto out_unref;
-	}
+	drm_fb_helper_fill_var(info, &fbcon->helper, sizes->fb_width, sizes->fb_height);
 
 	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
 	mutex_unlock(&dev->struct_mutex);
 
-	if (dev_priv->channel && !nouveau_nofbaccel) {
+	if (chan) {
 		ret = -ENODEV;
-		if (dev_priv->card_type < NV_50)
+		if (device->card_type < NV_50)
 			ret = nv04_fbcon_accel_init(info);
 		else
-		if (dev_priv->card_type < NV_C0)
+		if (device->card_type < NV_C0)
 			ret = nv50_fbcon_accel_init(info);
 		else
 			ret = nvc0_fbcon_accel_init(info);
@@ -369,13 +374,12 @@
 			info->fbops = &nouveau_fbcon_ops;
 	}
 
-	nouveau_fbcon_zfill(dev, nfbdev);
+	nouveau_fbcon_zfill(dev, fbcon);
 
 	/* To allow resizeing without swapping buffers */
-	NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
-						nouveau_fb->base.width,
-						nouveau_fb->base.height,
-						nvbo->bo.offset, nvbo);
+	NV_INFO(drm, "allocated %dx%d fb: 0x%lx, bo %p\n",
+		nouveau_fb->base.width, nouveau_fb->base.height,
+		nvbo->bo.offset, nvbo);
 
 	vga_switcheroo_client_fb_set(dev->pdev, info);
 	return 0;
@@ -390,12 +394,12 @@
 nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
 				    struct drm_fb_helper_surface_size *sizes)
 {
-	struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper;
+	struct nouveau_fbdev *fbcon = (struct nouveau_fbdev *)helper;
 	int new_fb = 0;
 	int ret;
 
 	if (!helper->fb) {
-		ret = nouveau_fbcon_create(nfbdev, sizes);
+		ret = nouveau_fbcon_create(fbcon, sizes);
 		if (ret)
 			return ret;
 		new_fb = 1;
@@ -406,18 +410,18 @@
 void
 nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	drm_fb_helper_hotplug_event(&drm->fbcon->helper);
 }
 
 static int
-nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
+nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
-	struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
+	struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb;
 	struct fb_info *info;
 
-	if (nfbdev->helper.fbdev) {
-		info = nfbdev->helper.fbdev;
+	if (fbcon->helper.fbdev) {
+		info = fbcon->helper.fbdev;
 		unregister_framebuffer(info);
 		if (info->cmap.len)
 			fb_dealloc_cmap(&info->cmap);
@@ -430,17 +434,17 @@
 		drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
 		nouveau_fb->nvbo = NULL;
 	}
-	drm_fb_helper_fini(&nfbdev->helper);
+	drm_fb_helper_fini(&fbcon->helper);
 	drm_framebuffer_cleanup(&nouveau_fb->base);
 	return 0;
 }
 
 void nouveau_fbcon_gpu_lockup(struct fb_info *info)
 {
-	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
+	struct nouveau_fbdev *fbcon = info->par;
+	struct nouveau_drm *drm = nouveau_newpriv(fbcon->dev);
 
-	NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
+	NV_ERROR(drm, "GPU lockup - switching to software fbcon\n");
 	info->flags |= FBINFO_HWACCEL_DISABLED;
 }
 
@@ -451,74 +455,81 @@
 };
 
 
-int nouveau_fbcon_init(struct drm_device *dev)
+int
+nouveau_fbcon_init(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fbdev *nfbdev;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
+	struct nouveau_fbdev *fbcon;
 	int preferred_bpp;
 	int ret;
 
-	nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
-	if (!nfbdev)
+	if (!dev->mode_config.num_crtc)
+		return 0;
+
+	fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
+	if (!fbcon)
 		return -ENOMEM;
 
-	nfbdev->dev = dev;
-	dev_priv->nfbdev = nfbdev;
-	nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
+	fbcon->dev = dev;
+	drm->fbcon = fbcon;
+	fbcon->helper.funcs = &nouveau_fbcon_helper_funcs;
 
-	ret = drm_fb_helper_init(dev, &nfbdev->helper,
+	ret = drm_fb_helper_init(dev, &fbcon->helper,
 				 dev->mode_config.num_crtc, 4);
 	if (ret) {
-		kfree(nfbdev);
+		kfree(fbcon);
 		return ret;
 	}
 
-	drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
+	drm_fb_helper_single_add_all_connectors(&fbcon->helper);
 
-	if (nvfb_vram_size(dev) <= 32 * 1024 * 1024)
+	if (pfb->ram.size <= 32 * 1024 * 1024)
 		preferred_bpp = 8;
-	else if (nvfb_vram_size(dev) <= 64 * 1024 * 1024)
+	else
+	if (pfb->ram.size <= 64 * 1024 * 1024)
 		preferred_bpp = 16;
 	else
 		preferred_bpp = 32;
 
-	drm_fb_helper_initial_config(&nfbdev->helper, preferred_bpp);
+	drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
 	return 0;
 }
 
-void nouveau_fbcon_fini(struct drm_device *dev)
+void
+nouveau_fbcon_fini(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 
-	if (!dev_priv->nfbdev)
+	if (!drm->fbcon)
 		return;
 
-	nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
-	kfree(dev_priv->nfbdev);
-	dev_priv->nfbdev = NULL;
+	nouveau_fbcon_destroy(dev, drm->fbcon);
+	kfree(drm->fbcon);
+	drm->fbcon = NULL;
 }
 
 void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 
-	dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
-	dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+	drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
+	drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
 }
 
 void nouveau_fbcon_restore_accel(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
 }
 
 void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 	console_lock();
 	if (state == 0)
 		nouveau_fbcon_save_disable_accel(dev);
-	fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
+	fb_set_suspend(drm->fbcon->helper.fbdev, state);
 	if (state == 1)
 		nouveau_fbcon_restore_accel(dev);
 	console_unlock();
@@ -526,6 +537,6 @@
 
 void nouveau_fbcon_zfill_all(struct drm_device *dev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	nouveau_fbcon_zfill(dev, drm->fbcon);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index b73c29f8..e6404e3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -30,6 +30,7 @@
 #include "drm_fb_helper.h"
 
 #include "nouveau_fb.h"
+
 struct nouveau_fbdev {
 	struct drm_fb_helper helper;
 	struct nouveau_framebuffer nouveau_fb;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index a1835d7..5b5471b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -30,11 +30,9 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 
-#include "nouveau_drv.h"
-#include <core/ramht.h>
-#include "nouveau_fence.h"
-#include "nouveau_software.h"
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
+#include "nouveau_fence.h"
 
 void
 nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
@@ -59,12 +57,10 @@
 	spin_lock_init(&fctx->lock);
 }
 
-void
+static void
 nouveau_fence_update(struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fence_priv *priv = chan->drm->fence;
 	struct nouveau_fence_chan *fctx = chan->fence;
 	struct nouveau_fence *fence, *fnext;
 
@@ -85,9 +81,7 @@
 int
 nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fence_priv *priv = chan->drm->fence;
 	struct nouveau_fence_chan *fctx = chan->fence;
 	int ret;
 
@@ -150,20 +144,17 @@
 int
 nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fence_priv *priv = chan->drm->fence;
 	struct nouveau_channel *prev;
 	int ret = 0;
 
-	prev = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
+	prev = fence ? fence->channel : NULL;
 	if (prev) {
 		if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
 			ret = priv->sync(fence, prev, chan);
 			if (unlikely(ret))
 				ret = nouveau_fence_wait(fence, true, false);
 		}
-		nouveau_channel_put_unlocked(&prev);
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index 8ee6575..bedafd1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -1,6 +1,8 @@
 #ifndef __NOUVEAU_FENCE_H__
 #define __NOUVEAU_FENCE_H__
 
+struct nouveau_drm;
+
 struct nouveau_fence {
 	struct list_head head;
 	struct kref kref;
@@ -22,8 +24,6 @@
 bool nouveau_fence_done(struct nouveau_fence *);
 int  nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
 int  nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
-void nouveau_fence_idle(struct nouveau_channel *);
-void nouveau_fence_update(struct nouveau_channel *);
 
 struct nouveau_fence_chan {
 	struct list_head pending;
@@ -34,9 +34,9 @@
 };
 
 struct nouveau_fence_priv {
-	void (*dtor)(struct drm_device *);
-	bool (*suspend)(struct drm_device *);
-	void (*resume)(struct drm_device *);
+	void (*dtor)(struct nouveau_drm *);
+	bool (*suspend)(struct nouveau_drm *);
+	void (*resume)(struct nouveau_drm *);
 	int  (*context_new)(struct nouveau_channel *);
 	void (*context_del)(struct nouveau_channel *);
 	int  (*emit)(struct nouveau_fence *);
@@ -45,10 +45,12 @@
 	u32  (*read)(struct nouveau_channel *);
 };
 
+#define nouveau_fence(drm) ((struct nouveau_fence_priv *)(drm)->fence)
+
 void nouveau_fence_context_new(struct nouveau_fence_chan *);
 void nouveau_fence_context_del(struct nouveau_fence_chan *);
 
-int nv04_fence_create(struct drm_device *dev);
+int nv04_fence_create(struct nouveau_drm *);
 int nv04_fence_mthd(struct nouveau_channel *, u32, u32, u32);
 
 int  nv10_fence_emit(struct nouveau_fence *);
@@ -56,12 +58,12 @@
 		     struct nouveau_channel *);
 u32  nv10_fence_read(struct nouveau_channel *);
 void nv10_fence_context_del(struct nouveau_channel *);
-void nv10_fence_destroy(struct drm_device *);
-int  nv10_fence_create(struct drm_device *dev);
+void nv10_fence_destroy(struct nouveau_drm *);
+int  nv10_fence_create(struct nouveau_drm *);
 
-int nv50_fence_create(struct drm_device *dev);
-int nv84_fence_create(struct drm_device *dev);
-int nvc0_fence_create(struct drm_device *dev);
+int nv50_fence_create(struct nouveau_drm *);
+int nv84_fence_create(struct nouveau_drm *);
+int nvc0_fence_create(struct nouveau_drm *);
 u64 nvc0_fence_crtc(struct nouveau_channel *, int crtc);
 
 int nouveau_flip_complete(void *chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 96a34bc..ba744da 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -23,16 +23,19 @@
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  */
-#include <linux/dma-buf.h>
-#include "drmP.h"
-#include "drm.h"
 
-#include "nouveau_drv.h"
+#include <linux/dma-buf.h>
 #include <nouveau_drm.h>
+
+#include <subdev/fb.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
 #include "nouveau_fence.h"
+#include "nouveau_abi16.h"
 
-#define nouveau_gem_pushbuf_sync(chan) 0
+#include "nouveau_ttm.h"
+#include "nouveau_gem.h"
 
 int
 nouveau_gem_object_new(struct drm_gem_object *gem)
@@ -67,19 +70,19 @@
 int
 nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
 {
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
 	struct nouveau_vma *vma;
 	int ret;
 
-	if (!fpriv->vm)
+	if (!cli->base.vm)
 		return 0;
 
 	ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
 	if (ret)
 		return ret;
 
-	vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+	vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
 	if (!vma) {
 		vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 		if (!vma) {
@@ -87,7 +90,7 @@
 			goto out;
 		}
 
-		ret = nouveau_bo_vma_add(nvbo, fpriv->vm, vma);
+		ret = nouveau_bo_vma_add(nvbo, cli->base.vm, vma);
 		if (ret) {
 			kfree(vma);
 			goto out;
@@ -104,19 +107,19 @@
 void
 nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
 {
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
 	struct nouveau_vma *vma;
 	int ret;
 
-	if (!fpriv->vm)
+	if (!cli->base.vm)
 		return;
 
 	ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0);
 	if (ret)
 		return;
 
-	vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+	vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
 	if (vma) {
 		if (--vma->refcount == 0) {
 			nouveau_bo_vma_del(nvbo, vma);
@@ -131,7 +134,7 @@
 		uint32_t tile_mode, uint32_t tile_flags,
 		struct nouveau_bo **pnvbo)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nouveau_bo *nvbo;
 	u32 flags = 0;
 	int ret;
@@ -155,7 +158,7 @@
 	 */
 	nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM |
 			      NOUVEAU_GEM_DOMAIN_GART;
-	if (dev_priv->card_type >= NV_50)
+	if (nv_device(drm->device)->card_type >= NV_50)
 		nvbo->valid_domains &= domain;
 
 	nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
@@ -173,7 +176,7 @@
 nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
 		 struct drm_nouveau_gem_info *rep)
 {
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
+	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
 	struct nouveau_vma *vma;
 
@@ -183,8 +186,8 @@
 		rep->domain = NOUVEAU_GEM_DOMAIN_VRAM;
 
 	rep->offset = nvbo->bo.offset;
-	if (fpriv->vm) {
-		vma = nouveau_bo_vma_find(nvbo, fpriv->vm);
+	if (cli->base.vm) {
+		vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
 		if (!vma)
 			return -EINVAL;
 
@@ -202,15 +205,16 @@
 nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
 		      struct drm_file *file_priv)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_drm *drm = nouveau_drm(dev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
 	struct drm_nouveau_gem_new *req = data;
 	struct nouveau_bo *nvbo = NULL;
 	int ret = 0;
 
-	dev_priv->ttm.bdev.dev_mapping = dev->dev_mapping;
+	drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping;
 
-	if (!nvfb_flags_valid(dev, req->info.tile_flags)) {
-		NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags);
+	if (!pfb->memtype_valid(pfb, req->info.tile_flags)) {
+		NV_ERROR(drm, "bad page flags: 0x%08x\n", req->info.tile_flags);
 		return -EINVAL;
 	}
 
@@ -312,16 +316,16 @@
 	      struct drm_nouveau_gem_pushbuf_bo *pbbo,
 	      int nr_buffers, struct validate_op *op)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct drm_device *dev = chan->drm->dev;
+	struct nouveau_drm *drm = nouveau_drm(dev);
 	uint32_t sequence;
 	int trycnt = 0;
 	int ret, i;
 
-	sequence = atomic_add_return(1, &dev_priv->ttm.validate_sequence);
+	sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
 retry:
 	if (++trycnt > 100000) {
-		NV_ERROR(dev, "%s failed and gave up.\n", __func__);
+		NV_ERROR(drm, "%s failed and gave up.\n", __func__);
 		return -EINVAL;
 	}
 
@@ -332,14 +336,14 @@
 
 		gem = drm_gem_object_lookup(dev, file_priv, b->handle);
 		if (!gem) {
-			NV_ERROR(dev, "Unknown handle 0x%08x\n", b->handle);
+			NV_ERROR(drm, "Unknown handle 0x%08x\n", b->handle);
 			validate_fini(op, NULL);
 			return -ENOENT;
 		}
 		nvbo = gem->driver_private;
 
 		if (nvbo->reserved_by && nvbo->reserved_by == file_priv) {
-			NV_ERROR(dev, "multiple instances of buffer %d on "
+			NV_ERROR(drm, "multiple instances of buffer %d on "
 				      "validation list\n", b->handle);
 			drm_gem_object_unreference_unlocked(gem);
 			validate_fini(op, NULL);
@@ -354,7 +358,7 @@
 			drm_gem_object_unreference_unlocked(gem);
 			if (unlikely(ret)) {
 				if (ret != -ERESTARTSYS)
-					NV_ERROR(dev, "fail reserve\n");
+					NV_ERROR(drm, "fail reserve\n");
 				return ret;
 			}
 			goto retry;
@@ -373,7 +377,7 @@
 		if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)
 			list_add_tail(&nvbo->entry, &op->gart_list);
 		else {
-			NV_ERROR(dev, "invalid valid domains: 0x%08x\n",
+			NV_ERROR(drm, "invalid valid domains: 0x%08x\n",
 				 b->valid_domains);
 			list_add_tail(&nvbo->entry, &op->both_list);
 			validate_fini(op, NULL);
@@ -407,10 +411,9 @@
 validate_list(struct nouveau_channel *chan, struct list_head *list,
 	      struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+	struct nouveau_drm *drm = chan->drm;
 	struct drm_nouveau_gem_pushbuf_bo __user *upbbo =
 				(void __force __user *)(uintptr_t)user_pbbo_ptr;
-	struct drm_device *dev = chan->dev;
 	struct nouveau_bo *nvbo;
 	int ret, relocs = 0;
 
@@ -419,7 +422,7 @@
 
 		ret = validate_sync(chan, nvbo);
 		if (unlikely(ret)) {
-			NV_ERROR(dev, "fail pre-validate sync\n");
+			NV_ERROR(drm, "fail pre-validate sync\n");
 			return ret;
 		}
 
@@ -427,24 +430,24 @@
 					     b->write_domains,
 					     b->valid_domains);
 		if (unlikely(ret)) {
-			NV_ERROR(dev, "fail set_domain\n");
+			NV_ERROR(drm, "fail set_domain\n");
 			return ret;
 		}
 
 		ret = nouveau_bo_validate(nvbo, true, false, false);
 		if (unlikely(ret)) {
 			if (ret != -ERESTARTSYS)
-				NV_ERROR(dev, "fail ttm_validate\n");
+				NV_ERROR(drm, "fail ttm_validate\n");
 			return ret;
 		}
 
 		ret = validate_sync(chan, nvbo);
 		if (unlikely(ret)) {
-			NV_ERROR(dev, "fail post-validate sync\n");
+			NV_ERROR(drm, "fail post-validate sync\n");
 			return ret;
 		}
 
-		if (dev_priv->card_type < NV_50) {
+		if (nv_device(drm->device)->card_type < NV_50) {
 			if (nvbo->bo.offset == b->presumed.offset &&
 			    ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
 			      b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
@@ -476,7 +479,7 @@
 			     uint64_t user_buffers, int nr_buffers,
 			     struct validate_op *op, int *apply_relocs)
 {
-	struct drm_device *dev = chan->dev;
+	struct nouveau_drm *drm = chan->drm;
 	int ret, relocs = 0;
 
 	INIT_LIST_HEAD(&op->vram_list);
@@ -489,14 +492,14 @@
 	ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
 	if (unlikely(ret)) {
 		if (ret != -ERESTARTSYS)
-			NV_ERROR(dev, "validate_init\n");
+			NV_ERROR(drm, "validate_init\n");
 		return ret;
 	}
 
 	ret = validate_list(chan, &op->vram_list, pbbo, user_buffers);
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
-			NV_ERROR(dev, "validate vram_list\n");
+			NV_ERROR(drm, "validate vram_list\n");
 		validate_fini(op, NULL);
 		return ret;
 	}
@@ -505,7 +508,7 @@
 	ret = validate_list(chan, &op->gart_list, pbbo, user_buffers);
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
-			NV_ERROR(dev, "validate gart_list\n");
+			NV_ERROR(drm, "validate gart_list\n");
 		validate_fini(op, NULL);
 		return ret;
 	}
@@ -514,7 +517,7 @@
 	ret = validate_list(chan, &op->both_list, pbbo, user_buffers);
 	if (unlikely(ret < 0)) {
 		if (ret != -ERESTARTSYS)
-			NV_ERROR(dev, "validate both_list\n");
+			NV_ERROR(drm, "validate both_list\n");
 		validate_fini(op, NULL);
 		return ret;
 	}
@@ -547,6 +550,7 @@
 				struct drm_nouveau_gem_pushbuf *req,
 				struct drm_nouveau_gem_pushbuf_bo *bo)
 {
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
 	struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
 	int ret = 0;
 	unsigned i;
@@ -562,7 +566,7 @@
 		uint32_t data;
 
 		if (unlikely(r->bo_index > req->nr_buffers)) {
-			NV_ERROR(dev, "reloc bo index invalid\n");
+			NV_ERROR(drm, "reloc bo index invalid\n");
 			ret = -EINVAL;
 			break;
 		}
@@ -572,7 +576,7 @@
 			continue;
 
 		if (unlikely(r->reloc_bo_index > req->nr_buffers)) {
-			NV_ERROR(dev, "reloc container bo index invalid\n");
+			NV_ERROR(drm, "reloc container bo index invalid\n");
 			ret = -EINVAL;
 			break;
 		}
@@ -580,7 +584,7 @@
 
 		if (unlikely(r->reloc_bo_offset + 4 >
 			     nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
-			NV_ERROR(dev, "reloc outside of bo\n");
+			NV_ERROR(drm, "reloc outside of bo\n");
 			ret = -EINVAL;
 			break;
 		}
@@ -589,7 +593,7 @@
 			ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
 					  &nvbo->kmap);
 			if (ret) {
-				NV_ERROR(dev, "failed kmap for reloc\n");
+				NV_ERROR(drm, "failed kmap for reloc\n");
 				break;
 			}
 			nvbo->validate_mapped = true;
@@ -614,7 +618,7 @@
 		ret = ttm_bo_wait(&nvbo->bo, false, false, false);
 		spin_unlock(&nvbo->bo.bdev->fence_lock);
 		if (ret) {
-			NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret);
+			NV_ERROR(drm, "reloc wait_idle failed: %d\n", ret);
 			break;
 		}
 
@@ -629,62 +633,67 @@
 nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
 			  struct drm_file *file_priv)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
+	struct nouveau_abi16_chan *temp;
+	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct drm_nouveau_gem_pushbuf *req = data;
 	struct drm_nouveau_gem_pushbuf_push *push;
 	struct drm_nouveau_gem_pushbuf_bo *bo;
-	struct nouveau_channel *chan;
+	struct nouveau_channel *chan = NULL;
 	struct validate_op op;
 	struct nouveau_fence *fence = NULL;
 	int i, j, ret = 0, do_reloc = 0;
 
-	chan = nouveau_channel_get(file_priv, req->channel);
-	if (IS_ERR(chan))
-		return PTR_ERR(chan);
+	if (unlikely(!abi16))
+		return -ENOMEM;
 
-	req->vram_available = dev_priv->fb_aper_free;
-	req->gart_available = dev_priv->gart_info.aper_free;
+	list_for_each_entry(temp, &abi16->channels, head) {
+		if (temp->chan->handle == (NVDRM_CHAN | req->channel)) {
+			chan = temp->chan;
+			break;
+		}
+	}
+
+	if (!chan)
+		return nouveau_abi16_put(abi16, -ENOENT);
+
+	req->vram_available = drm->gem.vram_available;
+	req->gart_available = drm->gem.gart_available;
 	if (unlikely(req->nr_push == 0))
 		goto out_next;
 
 	if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
-		NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n",
+		NV_ERROR(drm, "pushbuf push count exceeds limit: %d max %d\n",
 			 req->nr_push, NOUVEAU_GEM_MAX_PUSH);
-		nouveau_channel_put(&chan);
-		return -EINVAL;
+		return nouveau_abi16_put(abi16, -EINVAL);
 	}
 
 	if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
-		NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n",
+		NV_ERROR(drm, "pushbuf bo count exceeds limit: %d max %d\n",
 			 req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
-		nouveau_channel_put(&chan);
-		return -EINVAL;
+		return nouveau_abi16_put(abi16, -EINVAL);
 	}
 
 	if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
-		NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n",
+		NV_ERROR(drm, "pushbuf reloc count exceeds limit: %d max %d\n",
 			 req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
-		nouveau_channel_put(&chan);
-		return -EINVAL;
+		return nouveau_abi16_put(abi16, -EINVAL);
 	}
 
 	push = u_memcpya(req->push, req->nr_push, sizeof(*push));
-	if (IS_ERR(push)) {
-		nouveau_channel_put(&chan);
-		return PTR_ERR(push);
-	}
+	if (IS_ERR(push))
+		return nouveau_abi16_put(abi16, PTR_ERR(push));
 
 	bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
 	if (IS_ERR(bo)) {
 		kfree(push);
-		nouveau_channel_put(&chan);
-		return PTR_ERR(bo);
+		return nouveau_abi16_put(abi16, PTR_ERR(bo));
 	}
 
 	/* Ensure all push buffers are on validate list */
 	for (i = 0; i < req->nr_push; i++) {
 		if (push[i].bo_index >= req->nr_buffers) {
-			NV_ERROR(dev, "push %d buffer not in list\n", i);
+			NV_ERROR(drm, "push %d buffer not in list\n", i);
 			ret = -EINVAL;
 			goto out_prevalid;
 		}
@@ -695,7 +704,7 @@
 					   req->nr_buffers, &op, &do_reloc);
 	if (ret) {
 		if (ret != -ERESTARTSYS)
-			NV_ERROR(dev, "validate: %d\n", ret);
+			NV_ERROR(drm, "validate: %d\n", ret);
 		goto out_prevalid;
 	}
 
@@ -703,7 +712,7 @@
 	if (do_reloc) {
 		ret = nouveau_gem_pushbuf_reloc_apply(dev, req, bo);
 		if (ret) {
-			NV_ERROR(dev, "reloc apply: %d\n", ret);
+			NV_ERROR(drm, "reloc apply: %d\n", ret);
 			goto out;
 		}
 	}
@@ -711,7 +720,7 @@
 	if (chan->dma.ib_max) {
 		ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
 		if (ret) {
-			NV_INFO(dev, "nv50cal_space: %d\n", ret);
+			NV_ERROR(drm, "nv50cal_space: %d\n", ret);
 			goto out;
 		}
 
@@ -723,10 +732,10 @@
 				      push[i].length);
 		}
 	} else
-	if (dev_priv->chipset >= 0x25) {
+	if (nv_device(drm->device)->chipset >= 0x25) {
 		ret = RING_SPACE(chan, req->nr_push * 2);
 		if (ret) {
-			NV_ERROR(dev, "cal_space: %d\n", ret);
+			NV_ERROR(drm, "cal_space: %d\n", ret);
 			goto out;
 		}
 
@@ -740,7 +749,7 @@
 	} else {
 		ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS));
 		if (ret) {
-			NV_ERROR(dev, "jmp_space: %d\n", ret);
+			NV_ERROR(drm, "jmp_space: %d\n", ret);
 			goto out;
 		}
 
@@ -749,7 +758,7 @@
 				bo[push[i].bo_index].user_priv;
 			uint32_t cmd;
 
-			cmd = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
+			cmd = chan->push.vma.offset + ((chan->dma.cur + 2) << 2);
 			cmd |= 0x20000000;
 			if (unlikely(cmd != req->suffix0)) {
 				if (!nvbo->kmap.virtual) {
@@ -778,7 +787,7 @@
 
 	ret = nouveau_fence_new(chan, &fence);
 	if (ret) {
-		NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
+		NV_ERROR(drm, "error fencing pushbuf: %d\n", ret);
 		WIND_RING(chan);
 		goto out;
 	}
@@ -796,17 +805,16 @@
 		req->suffix0 = 0x00000000;
 		req->suffix1 = 0x00000000;
 	} else
-	if (dev_priv->chipset >= 0x25) {
+	if (nv_device(drm->device)->chipset >= 0x25) {
 		req->suffix0 = 0x00020000;
 		req->suffix1 = 0x00000000;
 	} else {
 		req->suffix0 = 0x20000000 |
-			      (chan->pushbuf_base + ((chan->dma.cur + 2) << 2));
+			      (chan->push.vma.offset + ((chan->dma.cur + 2) << 2));
 		req->suffix1 = 0x00000000;
 	}
 
-	nouveau_channel_put(&chan);
-	return ret;
+	return nouveau_abi16_put(abi16, ret);
 }
 
 static inline uint32_t
diff --git a/drivers/gpu/drm/nouveau/nouveau_gpuobj.c b/drivers/gpu/drm/nouveau/nouveau_gpuobj.c
deleted file mode 100644
index a774b7a..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_gpuobj.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (C) 2006 Ben Skeggs.
- *
- * All Rights Reserved.
- *
- * 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 (including the
- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 <darktama@iinet.net.au>
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <nouveau_drm.h>
-#include <engine/fifo.h>
-#include <core/ramht.h>
-#include "nouveau_software.h"
-
-struct nouveau_gpuobj_method {
-	struct list_head head;
-	u32 mthd;
-	int (*exec)(struct nouveau_channel *, u32 class, u32 mthd, u32 data);
-};
-
-struct nouveau_gpuobj_class {
-	struct list_head head;
-	struct list_head methods;
-	u32 id;
-	u32 engine;
-};
-
-int
-nouveau_gpuobj_class_new(struct drm_device *dev, u32 class, u32 engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj_class *oc;
-
-	oc = kzalloc(sizeof(*oc), GFP_KERNEL);
-	if (!oc)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&oc->methods);
-	oc->id = class;
-	oc->engine = engine;
-	list_add(&oc->head, &dev_priv->classes);
-	return 0;
-}
-
-int
-nouveau_gpuobj_mthd_new(struct drm_device *dev, u32 class, u32 mthd,
-			int (*exec)(struct nouveau_channel *, u32, u32, u32))
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj_method *om;
-	struct nouveau_gpuobj_class *oc;
-
-	list_for_each_entry(oc, &dev_priv->classes, head) {
-		if (oc->id == class)
-			goto found;
-	}
-
-	return -EINVAL;
-
-found:
-	om = kzalloc(sizeof(*om), GFP_KERNEL);
-	if (!om)
-		return -ENOMEM;
-
-	om->mthd = mthd;
-	om->exec = exec;
-	list_add(&om->head, &oc->methods);
-	return 0;
-}
-
-int
-nouveau_gpuobj_mthd_call(struct nouveau_channel *chan,
-			 u32 class, u32 mthd, u32 data)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nouveau_gpuobj_method *om;
-	struct nouveau_gpuobj_class *oc;
-
-	list_for_each_entry(oc, &dev_priv->classes, head) {
-		if (oc->id != class)
-			continue;
-
-		list_for_each_entry(om, &oc->methods, head) {
-			if (om->mthd == mthd)
-				return om->exec(chan, class, mthd, data);
-		}
-	}
-
-	return -ENOENT;
-}
-
-int
-nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid,
-			  u32 class, u32 mthd, u32 data)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct nouveau_channel *chan = NULL;
-	unsigned long flags;
-	int ret = -EINVAL;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	if (chid >= 0 && chid < pfifo->channels)
-		chan = dev_priv->channels.ptr[chid];
-	if (chan)
-		ret = nouveau_gpuobj_mthd_call(chan, class, mthd, data);
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return ret;
-}
-
-void
-nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class,
-		     u64 base, u64 size, int target, int access,
-		     u32 type, u32 comp)
-{
-	struct drm_nouveau_private *dev_priv = obj->dev->dev_private;
-	u32 flags0;
-
-	flags0  = (comp << 29) | (type << 22) | class;
-	flags0 |= 0x00100000;
-
-	switch (access) {
-	case NV_MEM_ACCESS_RO: flags0 |= 0x00040000; break;
-	case NV_MEM_ACCESS_RW:
-	case NV_MEM_ACCESS_WO: flags0 |= 0x00080000; break;
-	default:
-		break;
-	}
-
-	switch (target) {
-	case NV_MEM_TARGET_VRAM:
-		flags0 |= 0x00010000;
-		break;
-	case NV_MEM_TARGET_PCI:
-		flags0 |= 0x00020000;
-		break;
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		flags0 |= 0x00030000;
-		break;
-	case NV_MEM_TARGET_GART:
-		base += dev_priv->gart_info.aper_base;
-	default:
-		flags0 &= ~0x00100000;
-		break;
-	}
-
-	/* convert to base + limit */
-	size = (base + size) - 1;
-
-	nv_wo32(obj, offset + 0x00, flags0);
-	nv_wo32(obj, offset + 0x04, lower_32_bits(size));
-	nv_wo32(obj, offset + 0x08, lower_32_bits(base));
-	nv_wo32(obj, offset + 0x0c, upper_32_bits(size) << 24 |
-				    upper_32_bits(base));
-	nv_wo32(obj, offset + 0x10, 0x00000000);
-	nv_wo32(obj, offset + 0x14, 0x00000000);
-
-	nvimem_flush(obj->dev);
-}
-
-int
-nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size,
-		    int target, int access, u32 type, u32 comp,
-		    struct nouveau_gpuobj **pobj)
-{
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_FREE, pobj);
-	if (ret)
-		return ret;
-
-	nv50_gpuobj_dma_init(*pobj, 0, class, base, size, target,
-			     access, type, comp);
-	return 0;
-}
-
-int
-nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
-		       u64 size, int access, int target,
-		       struct nouveau_gpuobj **pobj)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj;
-	u32 flags0, flags2;
-	int ret;
-
-	if (dev_priv->card_type >= NV_50) {
-		u32 comp = (target == NV_MEM_TARGET_VM) ? NV_MEM_COMP_VM : 0;
-		u32 type = (target == NV_MEM_TARGET_VM) ? NV_MEM_TYPE_VM : 0;
-
-		return nv50_gpuobj_dma_new(chan, class, base, size,
-					   target, access, type, comp, pobj);
-	}
-
-	if (target == NV_MEM_TARGET_GART) {
-		struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma;
-
-		if (dev_priv->gart_info.type == NOUVEAU_GART_PDMA) {
-			if (base == 0) {
-				nouveau_gpuobj_ref(gart, pobj);
-				return 0;
-			}
-
-			base   = nouveau_sgdma_get_physical(dev, base);
-			target = NV_MEM_TARGET_PCI;
-		} else {
-			base += dev_priv->gart_info.aper_base;
-			if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
-				target = NV_MEM_TARGET_PCI_NOSNOOP;
-			else
-				target = NV_MEM_TARGET_PCI;
-		}
-	}
-
-	flags0  = class;
-	flags0 |= 0x00003000; /* PT present, PT linear */
-	flags2  = 0;
-
-	switch (target) {
-	case NV_MEM_TARGET_PCI:
-		flags0 |= 0x00020000;
-		break;
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		flags0 |= 0x00030000;
-		break;
-	default:
-		break;
-	}
-
-	switch (access) {
-	case NV_MEM_ACCESS_RO:
-		flags0 |= 0x00004000;
-		break;
-	case NV_MEM_ACCESS_WO:
-		flags0 |= 0x00008000;
-	default:
-		flags2 |= 0x00000002;
-		break;
-	}
-
-	flags0 |= (base & 0x00000fff) << 20;
-	flags2 |= (base & 0xfffff000);
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, flags0);
-	nv_wo32(obj, 0x04, size - 1);
-	nv_wo32(obj, 0x08, flags2);
-	nv_wo32(obj, 0x0c, flags2);
-
-	obj->engine = NVOBJ_ENGINE_SW;
-	obj->class  = class;
-	*pobj = obj;
-	return 0;
-}
-
-int
-nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
-{
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj_class *oc;
-	int ret;
-
-	NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
-
-	list_for_each_entry(oc, &dev_priv->classes, head) {
-		struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
-
-		if (oc->id != class)
-			continue;
-
-		if (!chan->engctx[oc->engine]) {
-			ret = eng->context_new(chan, oc->engine);
-			if (ret)
-				return ret;
-		}
-
-		return eng->object_new(chan, oc->engine, handle, class);
-	}
-
-	return -EINVAL;
-}
-
-static int
-nv04_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 0x10000, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nv50_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 0x10000, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 0x0200, 0, 0, &chan->ramfc);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 0x1000, 0, 0, &chan->engptr);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 0x4000, 0, 0, &chan->vm_pd);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nv84_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 0x10000, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 0x0200, 0, 0, &chan->engptr);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 0x4000, 0, 0, &chan->vm_pd);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm)
-{
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, &chan->ramin);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, 65536, 0x1000, 0, &chan->vm_pd);
-	if (ret)
-		return ret;
-
-	nouveau_vm_ref(vm, &chan->vm, chan->vm_pd);
-
-	nv_wo32(chan->ramin, 0x0200, lower_32_bits(chan->vm_pd->addr));
-	nv_wo32(chan->ramin, 0x0204, upper_32_bits(chan->vm_pd->addr));
-	nv_wo32(chan->ramin, 0x0208, 0xffffffff);
-	nv_wo32(chan->ramin, 0x020c, 0x000000ff);
-
-	return 0;
-}
-
-int
-nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
-			    uint32_t vram_h, uint32_t tt_h)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(chan->file_priv);
-	struct nouveau_vm *vm = fpriv ? fpriv->vm : dev_priv->chan_vm;
-	struct nouveau_gpuobj *vram = NULL, *tt = NULL;
-	int ret;
-
-	NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
-	if (dev_priv->card_type >= NV_C0)
-		return nvc0_gpuobj_channel_init(chan, vm);
-
-	/* Allocate a chunk of memory for per-channel object storage */
-	if (dev_priv->chipset >= 0x84)
-		ret = nv84_gpuobj_channel_init_pramin(chan);
-	else
-	if (dev_priv->chipset == 0x50)
-		ret = nv50_gpuobj_channel_init_pramin(chan);
-	else
-		ret = nv04_gpuobj_channel_init_pramin(chan);
-	if (ret) {
-		NV_ERROR(dev, "init pramin\n");
-		return ret;
-	}
-
-	/* NV50 VM
-	 *  - Allocate per-channel page-directory
-	 *  - Link with shared channel VM
-	 */
-	if (vm)
-		nouveau_vm_ref(vm, &chan->vm, chan->vm_pd);
-
-	/* RAMHT */
-	if (dev_priv->card_type < NV_50) {
-		nouveau_ramht_ref(dev_priv->ramht, &chan->ramht, NULL);
-	} else {
-		struct nouveau_gpuobj *ramht = NULL;
-
-		ret = nouveau_gpuobj_new(dev, chan, 0x8000, 16,
-					 NVOBJ_FLAG_ZERO_ALLOC, &ramht);
-		if (ret)
-			return ret;
-
-		ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
-		nouveau_gpuobj_ref(NULL, &ramht);
-		if (ret)
-			return ret;
-	}
-
-	/* VRAM ctxdma */
-	if (dev_priv->card_type >= NV_50) {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     0, (1ULL << 40), NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VM, &vram);
-		if (ret) {
-			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
-			return ret;
-		}
-	} else {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     0, dev_priv->fb_available_size,
-					     NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VRAM, &vram);
-		if (ret) {
-			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
-			return ret;
-		}
-	}
-
-	ret = nouveau_ramht_insert(chan, vram_h, vram);
-	nouveau_gpuobj_ref(NULL, &vram);
-	if (ret) {
-		NV_ERROR(dev, "Error adding VRAM ctxdma to RAMHT: %d\n", ret);
-		return ret;
-	}
-
-	/* TT memory ctxdma */
-	if (dev_priv->card_type >= NV_50) {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     0, (1ULL << 40), NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VM, &tt);
-	} else {
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     0, dev_priv->gart_info.aper_size,
-					     NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_GART, &tt);
-	}
-
-	if (ret) {
-		NV_ERROR(dev, "Error creating TT ctxdma: %d\n", ret);
-		return ret;
-	}
-
-	ret = nouveau_ramht_insert(chan, tt_h, tt);
-	nouveau_gpuobj_ref(NULL, &tt);
-	if (ret) {
-		NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-void
-nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
-{
-	NV_DEBUG(chan->dev, "ch%d\n", chan->id);
-
-	nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
-	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
-	nouveau_gpuobj_ref(NULL, &chan->ramfc);
-	nouveau_gpuobj_ref(NULL, &chan->engptr);
-
-	nouveau_gpuobj_ref(NULL, &chan->ramin);
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 1a75a96..25e2e63 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -36,7 +36,6 @@
 #include "nouveau_drv.h"
 #include "nouveau_reg.h"
 #include <core/ramht.h>
-#include "nouveau_util.h"
 
 void
 nouveau_irq_preinstall(struct drm_device *dev)
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 73176bc..9c35d14 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -37,146 +37,6 @@
 
 #include "nouveau_drv.h"
 #include "nouveau_pm.h"
-#include <core/mm.h>
-#include <engine/fifo.h>
-#include "nouveau_fence.h"
-
-/*
- * Cleanup everything
- */
-void
-nouveau_mem_vram_fini(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	ttm_bo_device_release(&dev_priv->ttm.bdev);
-
-	nouveau_ttm_global_release(dev_priv);
-
-	if (dev_priv->fb_mtrr >= 0) {
-		drm_mtrr_del(dev_priv->fb_mtrr,
-			     pci_resource_start(dev->pdev, 1),
-			     pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
-		dev_priv->fb_mtrr = -1;
-	}
-}
-
-void
-nouveau_mem_gart_fini(struct drm_device *dev)
-{
-	nouveau_sgdma_takedown(dev);
-}
-
-int
-nouveau_mem_vram_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
-	int ret, dma_bits;
-
-	dma_bits = 32;
-	if (dev_priv->card_type >= NV_50) {
-		if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
-			dma_bits = 40;
-	} else
-	if (0 && pci_is_pcie(dev->pdev) &&
-	    dev_priv->chipset  > 0x40 &&
-	    dev_priv->chipset != 0x45) {
-		if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39)))
-			dma_bits = 39;
-	}
-
-	ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
-	if (ret)
-		return ret;
-	ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
-	if (ret) {
-		/* Reset to default value. */
-		pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32));
-	}
-
-
-	ret = nouveau_ttm_global_init(dev_priv);
-	if (ret)
-		return ret;
-
-	ret = ttm_bo_device_init(&dev_priv->ttm.bdev,
-				 dev_priv->ttm.bo_global_ref.ref.object,
-				 &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
-				 dma_bits <= 32 ? true : false);
-	if (ret) {
-		NV_ERROR(dev, "Error initialising bo driver: %d\n", ret);
-		return ret;
-	}
-
-	dev_priv->fb_available_size = nvfb_vram_size(dev);
-	dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
-	if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
-		dev_priv->fb_mappable_pages = pci_resource_len(dev->pdev, 1);
-	dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
-
-	dev_priv->fb_available_size -= nvimem_reserved(dev);
-	dev_priv->fb_aper_free = dev_priv->fb_available_size;
-
-	/* mappable vram */
-	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
-			     dev_priv->fb_available_size >> PAGE_SHIFT);
-	if (ret) {
-		NV_ERROR(dev, "Failed VRAM mm init: %d\n", ret);
-		return ret;
-	}
-
-	if (dev_priv->card_type < NV_50) {
-		ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM,
-				     0, 0, NULL, &dev_priv->vga_ram);
-		if (ret == 0)
-			ret = nouveau_bo_pin(dev_priv->vga_ram,
-					     TTM_PL_FLAG_VRAM);
-
-		if (ret) {
-			NV_WARN(dev, "failed to reserve VGA memory\n");
-			nouveau_bo_ref(NULL, &dev_priv->vga_ram);
-		}
-	}
-
-	dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
-					 pci_resource_len(dev->pdev, 1),
-					 DRM_MTRR_WC);
-	return 0;
-}
-
-int
-nouveau_mem_gart_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
-	int ret;
-
-	if (!nvdrm_gart_init(dev, &dev_priv->gart_info.aper_base,
-				  &dev_priv->gart_info.aper_size))
-		dev_priv->gart_info.type = NOUVEAU_GART_AGP;
-
-	if (dev_priv->gart_info.type == NOUVEAU_GART_NONE) {
-		ret = nouveau_sgdma_init(dev);
-		if (ret) {
-			NV_ERROR(dev, "Error initialising PCI(E): %d\n", ret);
-			return ret;
-		}
-	}
-
-	NV_INFO(dev, "%d MiB GART (aperture)\n",
-		(int)(dev_priv->gart_info.aper_size >> 20));
-	dev_priv->gart_info.aper_free = dev_priv->gart_info.aper_size;
-
-	ret = ttm_bo_init_mm(bdev, TTM_PL_TT,
-			     dev_priv->gart_info.aper_size >> PAGE_SHIFT);
-	if (ret) {
-		NV_ERROR(dev, "Failed TT mm init: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
 
 static int
 nv40_mem_timing_calc(struct drm_device *dev, u32 freq,
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
deleted file mode 100644
index 2cc4779..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2007 Ben Skeggs.
- *
- * All Rights Reserved.
- *
- * 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 (including the
- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <core/ramht.h>
-
-int
-nouveau_notifier_init_channel(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_bo *ntfy = NULL;
-	uint32_t flags, ttmpl;
-	int ret;
-
-	if (nouveau_vram_notify) {
-		flags = NOUVEAU_GEM_DOMAIN_VRAM;
-		ttmpl = TTM_PL_FLAG_VRAM;
-	} else {
-		flags = NOUVEAU_GEM_DOMAIN_GART;
-		ttmpl = TTM_PL_FLAG_TT;
-	}
-
-	ret = nouveau_gem_new(dev, PAGE_SIZE, 0, flags, 0, 0, &ntfy);
-	if (ret)
-		return ret;
-
-	ret = nouveau_bo_pin(ntfy, ttmpl);
-	if (ret)
-		goto out_err;
-
-	ret = nouveau_bo_map(ntfy);
-	if (ret)
-		goto out_err;
-
-	if (dev_priv->card_type >= NV_50) {
-		ret = nouveau_bo_vma_add(ntfy, chan->vm, &chan->notifier_vma);
-		if (ret)
-			goto out_err;
-	}
-
-	ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
-	if (ret)
-		goto out_err;
-
-	chan->notifier_bo = ntfy;
-out_err:
-	if (ret) {
-		nouveau_bo_vma_del(ntfy, &chan->notifier_vma);
-		drm_gem_object_unreference_unlocked(ntfy->gem);
-	}
-
-	return ret;
-}
-
-void
-nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->dev;
-
-	if (!chan->notifier_bo)
-		return;
-
-	nouveau_bo_vma_del(chan->notifier_bo, &chan->notifier_vma);
-	nouveau_bo_unmap(chan->notifier_bo);
-	mutex_lock(&dev->struct_mutex);
-	nouveau_bo_unpin(chan->notifier_bo);
-	mutex_unlock(&dev->struct_mutex);
-	drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
-	drm_mm_takedown(&chan->notifier_heap);
-}
-
-int
-nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
-		       int size, uint32_t start, uint32_t end,
-		       uint32_t *b_offset)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *nobj = NULL;
-	struct drm_mm_node *mem;
-	uint64_t offset;
-	int target, ret;
-
-	mem = drm_mm_search_free_in_range(&chan->notifier_heap, size, 0,
-					  start, end, 0);
-	if (mem)
-		mem = drm_mm_get_block_range(mem, size, 0, start, end);
-	if (!mem) {
-		NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
-		return -ENOMEM;
-	}
-
-	if (dev_priv->card_type < NV_50) {
-		if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM)
-			target = NV_MEM_TARGET_VRAM;
-		else
-			target = NV_MEM_TARGET_GART;
-		offset  = chan->notifier_bo->bo.offset;
-	} else {
-		target = NV_MEM_TARGET_VM;
-		offset = chan->notifier_vma.offset;
-	}
-	offset += mem->start;
-
-	ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset,
-				     mem->size, NV_MEM_ACCESS_RW, target,
-				     &nobj);
-	if (ret) {
-		drm_mm_put_block(mem);
-		NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
-		return ret;
-	}
-
-	ret = nouveau_ramht_insert(chan, handle, nobj);
-	nouveau_gpuobj_ref(NULL, &nobj);
-	if (ret) {
-		drm_mm_put_block(mem);
-		NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
-		return ret;
-	}
-
-	*b_offset = mem->start;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
index cce47fa..de0b81f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -27,7 +27,6 @@
 
 #include "nouveau_drv.h"
 #include <nouveau_drm.h>
-#include "nouveau_dma.h"
 
 #include <linux/dma-buf.h>
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_revcompat.c b/drivers/gpu/drm/nouveau/nouveau_revcompat.c
new file mode 100644
index 0000000..d5c3390
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_revcompat.c
@@ -0,0 +1,22 @@
+#include "nouveau_revcompat.h"
+#include "nouveau_drv.h"
+#include "nv50_display.h"
+
+struct nouveau_drm *
+nouveau_newpriv(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	return dev_priv->newpriv;
+}
+
+struct nouveau_bo *
+nv50sema(struct drm_device *dev, int crtc)
+{
+	return nv50_display(dev)->crtc[crtc].sem.bo;
+}
+
+struct nouveau_bo *
+nvd0sema(struct drm_device *dev, int crtc)
+{
+	return nvd0_display_crtc_sema(dev, crtc);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_revcompat.h b/drivers/gpu/drm/nouveau/nouveau_revcompat.h
new file mode 100644
index 0000000..41cf61f1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_revcompat.h
@@ -0,0 +1,12 @@
+#ifndef __NOUVEAU_REVCOMPAT_H__
+#define __NOUVEAU_REVCOMPAT_H__
+
+#include "drmP.h"
+
+struct nouveau_drm *
+nouveau_newpriv(struct drm_device *);
+
+struct nouveau_bo *nv50sema(struct drm_device *dev, int crtc);
+struct nouveau_bo *nvd0sema(struct drm_device *dev, int crtc);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 464beda..ca5492a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -1,11 +1,10 @@
-#include "drmP.h"
-#include "nouveau_drv.h"
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 
-#define NV_CTXDMA_PAGE_SHIFT 12
-#define NV_CTXDMA_PAGE_SIZE  (1 << NV_CTXDMA_PAGE_SHIFT)
-#define NV_CTXDMA_PAGE_MASK  (NV_CTXDMA_PAGE_SIZE - 1)
+#include <subdev/fb.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_ttm.h"
 
 struct nouveau_sgdma_be {
 	/* this has to be the first field so populate/unpopulated in
@@ -22,7 +21,6 @@
 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
 
 	if (ttm) {
-		NV_DEBUG(nvbe->dev, "\n");
 		ttm_dma_tt_fini(&nvbe->ttm);
 		kfree(nvbe);
 	}
@@ -93,16 +91,18 @@
 			 unsigned long size, uint32_t page_flags,
 			 struct page *dummy_read_page)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(bdev);
 	struct nouveau_sgdma_be *nvbe;
 
 	nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL);
 	if (!nvbe)
 		return NULL;
 
-	nvbe->dev = dev;
-	nvbe->ttm.ttm.func = dev_priv->gart_info.func;
+	nvbe->dev = drm->dev;
+	if (nv_device(drm->device)->card_type < NV_50)
+		nvbe->ttm.ttm.func = &nv04_sgdma_backend;
+	else
+		nvbe->ttm.ttm.func = &nv50_sgdma_backend;
 
 	if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page)) {
 		kfree(nvbe);
@@ -110,51 +110,3 @@
 	}
 	return &nvbe->ttm.ttm;
 }
-
-int
-nouveau_sgdma_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 aper_size;
-
-	if (dev_priv->card_type >= NV_50)
-		aper_size = 512 * 1024 * 1024;
-	else
-		aper_size = 128 * 1024 * 1024;
-
-	if (dev_priv->card_type >= NV_50) {
-		dev_priv->gart_info.aper_base = 0;
-		dev_priv->gart_info.aper_size = aper_size;
-		dev_priv->gart_info.type = NOUVEAU_GART_HW;
-		dev_priv->gart_info.func = &nv50_sgdma_backend;
-	} else {
-		dev_priv->gart_info.aper_base = 0;
-		dev_priv->gart_info.aper_size = aper_size;
-		dev_priv->gart_info.type = NOUVEAU_GART_PDMA;
-		dev_priv->gart_info.func = &nv04_sgdma_backend;
-		dev_priv->gart_info.sg_ctxdma = nv04vm_refdma(dev);
-	}
-
-	return 0;
-}
-
-void
-nouveau_sgdma_takedown(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
-}
-
-uint32_t
-nouveau_sgdma_get_physical(struct drm_device *dev, uint32_t offset)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
-	int pte = (offset >> NV_CTXDMA_PAGE_SHIFT) + 2;
-
-	BUG_ON(dev_priv->card_type >= NV_50);
-
-	return (nv_ro32(gpuobj, 4 * pte) & ~NV_CTXDMA_PAGE_MASK) |
-		(offset & NV_CTXDMA_PAGE_MASK);
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_software.h b/drivers/gpu/drm/nouveau/nouveau_software.h
deleted file mode 100644
index 2105a9e..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_software.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __NOUVEAU_SOFTWARE_H__
-#define __NOUVEAU_SOFTWARE_H__
-
-#include "nouveau_fence.h"
-
-struct nouveau_software_priv {
-	struct nouveau_exec_engine base;
-	struct list_head vblank;
-	spinlock_t peephole_lock;
-};
-
-struct nouveau_software_chan {
-	int (*flip)(void *data);
-	void *flip_data;
-
-	struct {
-		struct list_head list;
-		u32 channel;
-		u32 ctxdma;
-		u32 offset;
-		u32 value;
-		u32 head;
-	} vblank;
-};
-
-static inline void
-nouveau_software_context_new(struct nouveau_channel *chan,
-			     struct nouveau_software_chan *pch)
-{
-	pch->flip = nouveau_flip_complete;
-	pch->flip_data = chan;
-}
-
-static inline void
-nouveau_software_create(struct nouveau_software_priv *psw)
-{
-	INIT_LIST_HEAD(&psw->vblank);
-	spin_lock_init(&psw->peephole_lock);
-}
-
-static inline u16
-nouveau_software_class(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	if (dev_priv->card_type <= NV_04)
-		return 0x006e;
-	if (dev_priv->card_type <= NV_40)
-		return 0x016e;
-	if (dev_priv->card_type <= NV_50)
-		return 0x506e;
-	if (dev_priv->card_type <= NV_E0)
-		return 0x906e;
-	return 0x0000;
-}
-
-int nv04_software_create(struct drm_device *);
-int nv50_software_create(struct drm_device *);
-int nvc0_software_create(struct drm_device *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 5c2836f..4349b33 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -35,13 +35,9 @@
 #include "nouveau_drv.h"
 #include <nouveau_drm.h>
 #include "nouveau_fbcon.h"
-#include <core/ramht.h>
 #include "nouveau_pm.h"
 #include "nv04_display.h"
 #include "nv50_display.h"
-#include <engine/fifo.h>
-#include "nouveau_fence.h"
-#include "nouveau_software.h"
 
 static void nouveau_stub_takedown(struct drm_device *dev) {}
 static int nouveau_stub_init(struct drm_device *dev) { return 0; }
@@ -266,38 +262,6 @@
 	return can_switch;
 }
 
-static void
-nouveau_card_channel_fini(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	if (dev_priv->channel) {
-		nouveau_channel_put_unlocked(&dev_priv->channel);
-		nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL);
-	}
-}
-
-static int
-nouveau_card_channel_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	int ret;
-
-	ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x1000, &dev_priv->chan_vm);
-	if (ret)
-		return ret;
-
-	ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT);
-	dev_priv->channel = chan;
-	if (ret)
-		return ret;
-	mutex_unlock(&dev_priv->channel->mutex);
-
-	nouveau_bo_move_init(chan);
-	return 0;
-}
-
 static const struct vga_switcheroo_client_ops nouveau_switcheroo_ops = {
 	.set_gpu_state = nouveau_switcheroo_set_state,
 	.reprobe = nouveau_switcheroo_reprobe,
@@ -309,7 +273,7 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_engine *engine;
-	int ret, e = 0;
+	int ret;
 
 	vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
 	vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops);
@@ -319,11 +283,7 @@
 	if (ret)
 		goto out;
 	engine = &dev_priv->engine;
-	spin_lock_init(&dev_priv->channels.lock);
-	spin_lock_init(&dev_priv->tile.lock);
 	spin_lock_init(&dev_priv->context_switch_lock);
-	spin_lock_init(&dev_priv->vm_lock);
-	INIT_LIST_HEAD(&dev_priv->classes);
 
 	/* Make the CRTCs and I2C buses accessible */
 	ret = engine->display.early_init(dev);
@@ -343,187 +303,9 @@
 		nv_mask(dev, 0x00088080, 0x00000800, 0x00000000);
 	}
 
-	ret = nouveau_mem_vram_init(dev);
-	if (ret)
-		goto out_bios;
-
-	ret = nouveau_mem_gart_init(dev);
-	if (ret)
-		goto out_ttmvram;
-
-	if (!dev_priv->noaccel) {
-		switch (dev_priv->card_type) {
-		case NV_04:
-			nv04_fifo_create(dev);
-			break;
-		case NV_10:
-		case NV_20:
-		case NV_30:
-			if (dev_priv->chipset < 0x17)
-				nv10_fifo_create(dev);
-			else
-				nv17_fifo_create(dev);
-			break;
-		case NV_40:
-			nv40_fifo_create(dev);
-			break;
-		case NV_50:
-			if (dev_priv->chipset == 0x50)
-				nv50_fifo_create(dev);
-			else
-				nv84_fifo_create(dev);
-			break;
-		case NV_C0:
-		case NV_D0:
-			nvc0_fifo_create(dev);
-			break;
-		case NV_E0:
-			nve0_fifo_create(dev);
-			break;
-		default:
-			break;
-		}
-
-		switch (dev_priv->card_type) {
-		case NV_04:
-			nv04_fence_create(dev);
-			break;
-		case NV_10:
-		case NV_20:
-		case NV_30:
-		case NV_40:
-		case NV_50:
-			if (dev_priv->chipset < 0x84)
-				nv50_fence_create(dev);
-			else
-				nv84_fence_create(dev);
-			break;
-		case NV_C0:
-		case NV_D0:
-		case NV_E0:
-			nvc0_fence_create(dev);
-			break;
-		default:
-			break;
-		}
-
-		switch (dev_priv->card_type) {
-		case NV_04:
-		case NV_10:
-		case NV_20:
-		case NV_30:
-		case NV_40:
-			nv04_software_create(dev);
-			break;
-		case NV_50:
-			nv50_software_create(dev);
-			break;
-		case NV_C0:
-		case NV_D0:
-		case NV_E0:
-			nvc0_software_create(dev);
-			break;
-		default:
-			break;
-		}
-
-		switch (dev_priv->card_type) {
-		case NV_04:
-			nv04_graph_create(dev);
-			break;
-		case NV_10:
-			nv10_graph_create(dev);
-			break;
-		case NV_20:
-		case NV_30:
-			nv20_graph_create(dev);
-			break;
-		case NV_40:
-			nv40_graph_create(dev);
-			break;
-		case NV_50:
-			nv50_graph_create(dev);
-			break;
-		case NV_C0:
-		case NV_D0:
-			nvc0_graph_create(dev);
-			break;
-		case NV_E0:
-			nve0_graph_create(dev);
-			break;
-		default:
-			break;
-		}
-
-		switch (dev_priv->chipset) {
-		case 0x84:
-		case 0x86:
-		case 0x92:
-		case 0x94:
-		case 0x96:
-		case 0xa0:
-			nv84_crypt_create(dev);
-			break;
-		case 0x98:
-		case 0xaa:
-		case 0xac:
-			nv98_crypt_create(dev);
-			break;
-		}
-
-		switch (dev_priv->card_type) {
-		case NV_50:
-			switch (dev_priv->chipset) {
-			case 0xa3:
-			case 0xa5:
-			case 0xa8:
-				nva3_copy_create(dev);
-				break;
-			}
-			break;
-		case NV_C0:
-			if (!(nv_rd32(dev, 0x022500) & 0x00000200))
-				nvc0_copy_create(dev, 1);
-		case NV_D0:
-			if (!(nv_rd32(dev, 0x022500) & 0x00000100))
-				nvc0_copy_create(dev, 0);
-			break;
-		default:
-			break;
-		}
-
-		if (dev_priv->chipset >= 0xa3 || dev_priv->chipset == 0x98) {
-			nv84_bsp_create(dev);
-			nv84_vp_create(dev);
-			nv98_ppp_create(dev);
-		} else
-		if (dev_priv->chipset >= 0x84) {
-			nv50_mpeg_create(dev);
-			nv84_bsp_create(dev);
-			nv84_vp_create(dev);
-		} else
-		if (dev_priv->chipset >= 0x50) {
-			nv50_mpeg_create(dev);
-		} else
-		if (dev_priv->card_type == NV_40 ||
-		    dev_priv->chipset == 0x31 ||
-		    dev_priv->chipset == 0x34 ||
-		    dev_priv->chipset == 0x36) {
-			nv31_mpeg_create(dev);
-		}
-
-		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;
-			}
-		}
-	}
-
 	ret = nouveau_irq_init(dev);
 	if (ret)
-		goto out_engine;
+		goto out_bios;
 
 	ret = nouveau_display_create(dev);
 	if (ret)
@@ -532,42 +314,20 @@
 	nouveau_backlight_init(dev);
 	nouveau_pm_init(dev);
 
-	if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
-		ret = nouveau_card_channel_init(dev);
+	if (dev->mode_config.num_crtc) {
+		ret = nouveau_display_init(dev);
 		if (ret)
 			goto out_pm;
 	}
 
-	if (dev->mode_config.num_crtc) {
-		ret = nouveau_display_init(dev);
-		if (ret)
-			goto out_chan;
-
-		nouveau_fbcon_init(dev);
-	}
-
 	return 0;
 
-out_chan:
-	nouveau_card_channel_fini(dev);
 out_pm:
 	nouveau_pm_fini(dev);
 	nouveau_backlight_exit(dev);
 	nouveau_display_destroy(dev);
 out_irq:
 	nouveau_irq_fini(dev);
-out_engine:
-	if (!dev_priv->noaccel) {
-		for (e = e - 1; e >= 0; e--) {
-			if (!dev_priv->eng[e])
-				continue;
-			dev_priv->eng[e]->fini(dev, e, false);
-			dev_priv->eng[e]->destroy(dev,e );
-		}
-	}
-	nouveau_mem_gart_fini(dev);
-out_ttmvram:
-	nouveau_mem_vram_fini(dev);
 out_bios:
 	nouveau_bios_takedown(dev);
 out_display_early:
@@ -582,39 +342,19 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_engine *engine = &dev_priv->engine;
-	int e;
 
-	if (dev->mode_config.num_crtc) {
-		nouveau_fbcon_fini(dev);
+	if (dev->mode_config.num_crtc)
 		nouveau_display_fini(dev);
-	}
 
-	nouveau_card_channel_fini(dev);
 	nouveau_pm_fini(dev);
 	nouveau_backlight_exit(dev);
 	nouveau_display_destroy(dev);
 
-	if (!dev_priv->noaccel) {
-		for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
-			if (dev_priv->eng[e]) {
-				dev_priv->eng[e]->fini(dev, e, false);
-				dev_priv->eng[e]->destroy(dev,e );
-			}
-		}
-	}
-
 	if (dev_priv->vga_ram) {
 		nouveau_bo_unpin(dev_priv->vga_ram);
 		nouveau_bo_ref(NULL, &dev_priv->vga_ram);
 	}
 
-	mutex_lock(&dev->struct_mutex);
-	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
-	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
-	mutex_unlock(&dev->struct_mutex);
-	nouveau_mem_gart_fini(dev);
-	nouveau_mem_vram_fini(dev);
-
 	nouveau_bios_takedown(dev);
 	engine->display.late_takedown(dev);
 
@@ -624,56 +364,6 @@
 	vga_client_register(dev->pdev, NULL, NULL, NULL);
 }
 
-int
-nouveau_open(struct drm_device *dev, struct drm_file *file_priv)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fpriv *fpriv;
-	int ret;
-
-	fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
-	if (unlikely(!fpriv))
-		return -ENOMEM;
-
-	spin_lock_init(&fpriv->lock);
-	INIT_LIST_HEAD(&fpriv->channels);
-
-	if (dev_priv->card_type == NV_50) {
-		ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL,
-				     &fpriv->vm);
-		if (ret) {
-			kfree(fpriv);
-			return ret;
-		}
-	} else
-	if (dev_priv->card_type >= NV_C0) {
-		ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL,
-				     &fpriv->vm);
-		if (ret) {
-			kfree(fpriv);
-			return ret;
-		}
-	}
-
-	file_priv->driver_priv = fpriv;
-	return 0;
-}
-
-/* here a client dies, release the stuff that was allocated for its
- * file_priv */
-void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv)
-{
-	nouveau_channel_cleanup(dev, file_priv);
-}
-
-void
-nouveau_postclose(struct drm_device *dev, struct drm_file *file_priv)
-{
-	struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
-	nouveau_vm_ref(NULL, &fpriv->vm, NULL);
-	kfree(fpriv);
-}
-
 /* first module load, setup the mmio/fb mapping */
 /* KMS: we need mmio at load time, not when the first drm client opens. */
 int nouveau_firstopen(struct drm_device *dev)
@@ -704,55 +394,6 @@
 #endif
 }
 
-static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev)
-{
-	struct pci_dev *pdev = dev->pdev;
-	struct apertures_struct *aper = alloc_apertures(3);
-	if (!aper)
-		return NULL;
-
-	aper->ranges[0].base = pci_resource_start(pdev, 1);
-	aper->ranges[0].size = pci_resource_len(pdev, 1);
-	aper->count = 1;
-
-	if (pci_resource_len(pdev, 2)) {
-		aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
-		aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
-		aper->count++;
-	}
-
-	if (pci_resource_len(pdev, 3)) {
-		aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
-		aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
-		aper->count++;
-	}
-
-	return aper;
-}
-
-static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	bool primary = false;
-	dev_priv->apertures = nouveau_get_apertures(dev);
-	if (!dev_priv->apertures)
-		return -ENOMEM;
-
-#ifdef CONFIG_X86
-	primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
-#endif
-
-	remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
-	return 0;
-}
-
-void *
-nouveau_newpriv(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	return dev_priv->newpriv;
-}
-
 int nouveau_load(struct drm_device *dev, unsigned long flags)
 {
 	struct drm_nouveau_private *dev_priv;
@@ -840,30 +481,6 @@
 
 	NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal);
 
-	/* Determine whether we'll attempt acceleration or not, some
-	 * cards are disabled by default here due to them being known
-	 * non-functional, or never been tested due to lack of hw.
-	 */
-	dev_priv->noaccel = !!nouveau_noaccel;
-	if (nouveau_noaccel == -1) {
-		switch (dev_priv->chipset) {
-		case 0xd9: /* known broken */
-		case 0xe4: /* needs binary driver firmware */
-		case 0xe7: /* needs binary driver firmware */
-			NV_INFO(dev, "acceleration disabled by default, pass "
-				     "noaccel=0 to force enable\n");
-			dev_priv->noaccel = true;
-			break;
-		default:
-			dev_priv->noaccel = false;
-			break;
-		}
-	}
-
-	ret = nouveau_remove_conflicting_drivers(dev);
-	if (ret)
-		goto err_priv;
-
 	nouveau_OF_copy_vbios_to_ramin(dev);
 
 	/* Special flags */
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index e729535..560e816 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -24,9 +24,13 @@
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/instmem.h>
 
-#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nouveau_ttm.h"
+#include "nouveau_gem.h"
 
 static int
 nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
@@ -60,11 +64,10 @@
 nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
 			 struct ttm_mem_reg *mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-	struct drm_device *dev = dev_priv->dev;
-
+	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
 	nouveau_mem_node_cleanup(mem->mm_node);
-	nvfb_vram_put(dev, (struct nouveau_mem **)&mem->mm_node);
+	pfb->ram.put(pfb, (struct nouveau_mem **)&mem->mm_node);
 }
 
 static int
@@ -73,8 +76,8 @@
 			 struct ttm_placement *placement,
 			 struct ttm_mem_reg *mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-	struct drm_device *dev = dev_priv->dev;
+	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+	struct nouveau_fb *pfb = nouveau_fb(drm->device);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nouveau_mem *node;
 	u32 size_nc = 0;
@@ -83,9 +86,9 @@
 	if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
 		size_nc = 1 << nvbo->page_shift;
 
-	ret = nvfb_vram_get(dev, mem->num_pages << PAGE_SHIFT,
-			mem->page_alignment << PAGE_SHIFT, size_nc,
-			(nvbo->tile_flags >> 8) & 0x3ff, &node);
+	ret = pfb->ram.get(pfb, mem->num_pages << PAGE_SHIFT,
+			   mem->page_alignment << PAGE_SHIFT, size_nc,
+			   (nvbo->tile_flags >> 8) & 0x3ff, &node);
 	if (ret) {
 		mem->mm_node = NULL;
 		return (ret == -ENOSPC) ? 0 : ret;
@@ -158,11 +161,9 @@
 			 struct ttm_placement *placement,
 			 struct ttm_mem_reg *mem)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
 	struct nouveau_mem *node;
 
-	if (unlikely((mem->num_pages << PAGE_SHIFT) >=
-		     dev_priv->gart_info.aper_size))
+	if (unlikely((mem->num_pages << PAGE_SHIFT) >= 512 * 1024 * 1024))
 		return -ENOMEM;
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
@@ -188,13 +189,17 @@
 	nouveau_gart_manager_debug
 };
 
+#include <core/subdev/vm/nv04.h>
 static int
 nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
-	struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev);
-	struct drm_device *dev = dev_priv->dev;
-	man->priv = nv04vm_ref(dev);
-	return (man->priv != NULL) ? 0 : -ENODEV;
+	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
+	struct nouveau_vmmgr *vmm = nouveau_vmmgr(drm->device);
+	struct nv04_vmmgr_priv *priv = (void *)vmm;
+	struct nouveau_vm *vm = NULL;
+	nouveau_vm_ref(priv->vm, &vm, NULL);
+	man->priv = vm;
+	return 0;
 }
 
 static int
@@ -260,13 +265,12 @@
 nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
 {
 	struct drm_file *file_priv = filp->private_data;
-	struct drm_nouveau_private *dev_priv =
-		file_priv->minor->dev->dev_private;
+	struct nouveau_drm *drm = nouveau_newpriv(file_priv->minor->dev);
 
 	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
 		return drm_mmap(filp, vma);
 
-	return ttm_bo_mmap(filp, vma, &dev_priv->ttm.bdev);
+	return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
 
 static int
@@ -282,12 +286,12 @@
 }
 
 int
-nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
+nouveau_ttm_global_init(struct nouveau_drm *drm)
 {
 	struct drm_global_reference *global_ref;
 	int ret;
 
-	global_ref = &dev_priv->ttm.mem_global_ref;
+	global_ref = &drm->ttm.mem_global_ref;
 	global_ref->global_type = DRM_GLOBAL_TTM_MEM;
 	global_ref->size = sizeof(struct ttm_mem_global);
 	global_ref->init = &nouveau_ttm_mem_global_init;
@@ -296,12 +300,12 @@
 	ret = drm_global_item_ref(global_ref);
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("Failed setting up TTM memory accounting\n");
-		dev_priv->ttm.mem_global_ref.release = NULL;
+		drm->ttm.mem_global_ref.release = NULL;
 		return ret;
 	}
 
-	dev_priv->ttm.bo_global_ref.mem_glob = global_ref->object;
-	global_ref = &dev_priv->ttm.bo_global_ref.ref;
+	drm->ttm.bo_global_ref.mem_glob = global_ref->object;
+	global_ref = &drm->ttm.bo_global_ref.ref;
 	global_ref->global_type = DRM_GLOBAL_TTM_BO;
 	global_ref->size = sizeof(struct ttm_bo_global);
 	global_ref->init = &ttm_bo_global_init;
@@ -310,8 +314,8 @@
 	ret = drm_global_item_ref(global_ref);
 	if (unlikely(ret != 0)) {
 		DRM_ERROR("Failed setting up TTM BO subsystem\n");
-		drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
-		dev_priv->ttm.mem_global_ref.release = NULL;
+		drm_global_item_unref(&drm->ttm.mem_global_ref);
+		drm->ttm.mem_global_ref.release = NULL;
 		return ret;
 	}
 
@@ -319,12 +323,105 @@
 }
 
 void
-nouveau_ttm_global_release(struct drm_nouveau_private *dev_priv)
+nouveau_ttm_global_release(struct nouveau_drm *drm)
 {
-	if (dev_priv->ttm.mem_global_ref.release == NULL)
+	if (drm->ttm.mem_global_ref.release == NULL)
 		return;
 
-	drm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
-	drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
-	dev_priv->ttm.mem_global_ref.release = NULL;
+	drm_global_item_unref(&drm->ttm.bo_global_ref.ref);
+	drm_global_item_unref(&drm->ttm.mem_global_ref);
+	drm->ttm.mem_global_ref.release = NULL;
+}
+
+int
+nouveau_ttm_init(struct nouveau_drm *drm)
+{
+	struct drm_device *dev = drm->dev;
+	u32 bits;
+	int ret;
+
+	if (nv_device(drm->device)->card_type >= NV_50) {
+		if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
+			bits = 40;
+		else
+			bits = 32;
+	} else {
+		bits = 32;
+	}
+
+	ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+	if (ret)
+		return ret;
+
+	ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+	if (ret)
+		pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32));
+
+	ret = nouveau_ttm_global_init(drm);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&drm->ttm.bdev,
+				  drm->ttm.bo_global_ref.ref.object,
+				  &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
+				  bits <= 32 ? true : false);
+	if (ret) {
+		NV_ERROR(drm, "error initialising bo driver, %d\n", ret);
+		return ret;
+	}
+
+	/* VRAM init */
+	drm->gem.vram_available  = nouveau_fb(drm->device)->ram.size;
+	drm->gem.vram_available -= nouveau_instmem(drm->device)->reserved;
+
+	ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
+			      drm->gem.vram_available >> PAGE_SHIFT);
+	if (ret) {
+		NV_ERROR(drm, "VRAM mm init failed, %d\n", ret);
+		return ret;
+	}
+
+	drm->ttm.mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+				     pci_resource_len(dev->pdev, 1),
+				     DRM_MTRR_WC);
+
+	/* GART init */
+	if (drm->agp.stat != ENABLED) {
+		drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit;
+		if (drm->gem.gart_available > 512 * 1024 * 1024)
+			drm->gem.gart_available = 512 * 1024 * 1024;
+	} else {
+		drm->gem.gart_available = drm->agp.size;
+	}
+
+	ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT,
+			      drm->gem.gart_available >> PAGE_SHIFT);
+	if (ret) {
+		NV_ERROR(drm, "GART mm init failed, %d\n", ret);
+		return ret;
+	}
+
+	NV_INFO(drm, "VRAM: %d MiB\n", (u32)(drm->gem.vram_available >> 20));
+	NV_INFO(drm, "GART: %d MiB\n", (u32)(drm->gem.gart_available >> 20));
+	return 0;
+}
+
+void
+nouveau_ttm_fini(struct nouveau_drm *drm)
+{
+	mutex_lock(&drm->dev->struct_mutex);
+	ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
+	ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
+	mutex_unlock(&drm->dev->struct_mutex);
+
+	ttm_bo_device_release(&drm->ttm.bdev);
+
+	nouveau_ttm_global_release(drm);
+
+	if (drm->ttm.mtrr >= 0) {
+		drm_mtrr_del(drm->ttm.mtrr,
+			     pci_resource_start(drm->dev->pdev, 1),
+			     pci_resource_len(drm->dev->pdev, 1), DRM_MTRR_WC);
+		drm->ttm.mtrr = -1;
+	}
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.h b/drivers/gpu/drm/nouveau/nouveau_ttm.h
new file mode 100644
index 0000000..9f4d271
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.h
@@ -0,0 +1,21 @@
+#ifndef __NOUVEAU_TTM_H__
+#define __NOUVEAU_TTM_H__
+
+static inline struct nouveau_drm *
+nouveau_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct nouveau_drm, ttm.bdev);
+}
+
+extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
+extern const struct ttm_mem_type_manager_func nouveau_gart_manager;
+extern const struct ttm_mem_type_manager_func nv04_gart_manager;
+
+struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_bo_device *,
+					unsigned long size, u32 page_flags,
+					struct page *dummy_read_page);
+
+int  nouveau_ttm_init(struct nouveau_drm *drm);
+void nouveau_ttm_fini(struct nouveau_drm *drm);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c
deleted file mode 100644
index 6bff634..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_util.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2010 Nouveau Project
- *
- * All Rights Reserved.
- *
- * 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 (including the
- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#include <linux/ratelimit.h>
-#include "nouveau_util.h"
-
-#include <core/enum.h>
-
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-int
-nouveau_ratelimit(void)
-{
-	return __ratelimit(&nouveau_ratelimit_state);
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h
deleted file mode 100644
index 1142937..0000000
--- a/drivers/gpu/drm/nouveau/nouveau_util.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 Nouveau Project
- *
- * All Rights Reserved.
- *
- * 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 (including the
- * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#ifndef __NOUVEAU_UTIL_H__
-#define __NOUVEAU_UTIL_H__
-
-#include <core/enum.h>
-
-int nouveau_ratelimit(void);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index 81947ea..6ab9363 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -32,9 +32,6 @@
 #include "nouveau_encoder.h"
 #include "nouveau_connector.h"
 
-static void nv04_vblank_crtc0_isr(struct drm_device *);
-static void nv04_vblank_crtc1_isr(struct drm_device *);
-
 int
 nv04_display_early_init(struct drm_device *dev)
 {
@@ -126,8 +123,6 @@
 		func->save(encoder);
 	}
 
-	nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr);
-	nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr);
 	return 0;
 }
 
@@ -141,9 +136,6 @@
 
 	NV_DEBUG_KMS(dev, "\n");
 
-	nouveau_irq_unregister(dev, 24);
-	nouveau_irq_unregister(dev, 25);
-
 	/* Turn every CRTC off. */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct drm_mode_set modeset = {
@@ -203,17 +195,3 @@
 	if (nv_two_heads(dev))
 		NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
 }
-
-static void
-nv04_vblank_crtc0_isr(struct drm_device *dev)
-{
-	nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
-	drm_handle_vblank(dev, 0);
-}
-
-static void
-nv04_vblank_crtc1_isr(struct drm_device *dev)
-{
-	nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
-	drm_handle_vblank(dev, 1);
-}
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 06fb68a..35480b67 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -22,19 +22,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include <core/object.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fbcon.h"
 
 int
 nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, 4);
@@ -53,9 +52,8 @@
 nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, 7);
@@ -81,9 +79,8 @@
 nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	uint32_t fg;
 	uint32_t bg;
 	uint32_t dsize;
@@ -142,9 +139,10 @@
 {
 	struct nouveau_fbdev *nfbdev = info->par;
 	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
-	const int sub = NvSubCtxSurf2D;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_channel *chan = drm->channel;
+	struct nouveau_device *device = nv_device(drm->device);
+	struct nouveau_object *object;
 	int surface_fmt, pattern_fmt, rect_fmt;
 	int ret;
 
@@ -176,31 +174,35 @@
 		return -EINVAL;
 	}
 
-	ret = nouveau_gpuobj_gr_new(chan, NvCtxSurf2D,
-				    dev_priv->card_type >= NV_10 ?
-				    0x0062 : 0x0042);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvCtxSurf2D,
+				 device->card_type >= NV_10 ? 0x0062 : 0x0042,
+				 NULL, 0, &object);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_gr_new(chan, NvClipRect, 0x0019);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvClipRect,
+				 0x0019, NULL, 0, &object);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_gr_new(chan, NvRop, 0x0043);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvRop,
+				 0x0043, NULL, 0, &object);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_gr_new(chan, NvImagePatt, 0x0044);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImagePatt,
+				 0x0044, NULL, 0, &object);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_gr_new(chan, NvGdiRect, 0x004a);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvGdiRect,
+				 0x004a, NULL, 0, &object);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_gr_new(chan, NvImageBlit,
-				    dev_priv->chipset >= 0x11 ?
-				    0x009f : 0x005f);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImageBlit,
+				 device->chipset >= 0x11 ? 0x009f : 0x005f,
+				 NULL, 0, &object);
 	if (ret)
 		return ret;
 
@@ -209,25 +211,25 @@
 		return 0;
 	}
 
-	BEGIN_NV04(chan, sub, 0x0000, 1);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 	OUT_RING(chan, NvCtxSurf2D);
-	BEGIN_NV04(chan, sub, 0x0184, 2);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0184, 2);
 	OUT_RING(chan, NvDmaFB);
 	OUT_RING(chan, NvDmaFB);
-	BEGIN_NV04(chan, sub, 0x0300, 4);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 4);
 	OUT_RING(chan, surface_fmt);
 	OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16));
 	OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 	OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 
-	BEGIN_NV04(chan, sub, 0x0000, 1);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 	OUT_RING(chan, NvRop);
-	BEGIN_NV04(chan, sub, 0x0300, 1);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 1);
 	OUT_RING(chan, 0x55);
 
-	BEGIN_NV04(chan, sub, 0x0000, 1);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 	OUT_RING(chan, NvImagePatt);
-	BEGIN_NV04(chan, sub, 0x0300, 8);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 8);
 	OUT_RING(chan, pattern_fmt);
 #ifdef __BIG_ENDIAN
 	OUT_RING(chan, 2);
@@ -241,9 +243,9 @@
 	OUT_RING(chan, ~0);
 	OUT_RING(chan, ~0);
 
-	BEGIN_NV04(chan, sub, 0x0000, 1);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 	OUT_RING(chan, NvClipRect);
-	BEGIN_NV04(chan, sub, 0x0300, 2);
+	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 2);
 	OUT_RING(chan, 0);
 	OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual);
 
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c
index 1b45a4f..a220b94 100644
--- a/drivers/gpu/drm/nouveau/nv04_fence.c
+++ b/drivers/gpu/drm/nouveau/nv04_fence.c
@@ -22,15 +22,14 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include <engine/fifo.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fence.h"
 
 struct nv04_fence_chan {
 	struct nouveau_fence_chan base;
-	atomic_t sequence;
 };
 
 struct nv04_fence_priv {
@@ -57,19 +56,11 @@
 	return -ENODEV;
 }
 
-int
-nv04_fence_mthd(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv04_fence_chan *fctx = chan->fence;
-	atomic_set(&fctx->sequence, data);
-	return 0;
-}
-
 static u32
 nv04_fence_read(struct nouveau_channel *chan)
 {
-	struct nv04_fence_chan *fctx = chan->fence;
-	return atomic_read(&fctx->sequence);
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	return atomic_read(&fifo->refcnt);
 }
 
 static void
@@ -87,7 +78,6 @@
 	struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
 	if (fctx) {
 		nouveau_fence_context_new(&fctx->base);
-		atomic_set(&fctx->sequence, 0);
 		chan->fence = fctx;
 		return 0;
 	}
@@ -95,23 +85,19 @@
 }
 
 static void
-nv04_fence_destroy(struct drm_device *dev)
+nv04_fence_destroy(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_fence_priv *priv = dev_priv->fence.func;
-
-	dev_priv->fence.func = NULL;
+	struct nv04_fence_priv *priv = drm->fence;
+	drm->fence = NULL;
 	kfree(priv);
 }
 
 int
-nv04_fence_create(struct drm_device *dev)
+nv04_fence_create(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv04_fence_priv *priv;
-	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -121,6 +107,5 @@
 	priv->base.emit = nv04_fence_emit;
 	priv->base.sync = nv04_fence_sync;
 	priv->base.read = nv04_fence_read;
-	dev_priv->fence.func = &priv->base;
-	return ret;
+	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nv04_software.c b/drivers/gpu/drm/nouveau/nv04_software.c
deleted file mode 100644
index ceeb868..0000000
--- a/drivers/gpu/drm/nouveau/nv04_software.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2012 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"
-#include <core/ramht.h>
-#include "nouveau_fence.h"
-#include "nouveau_software.h"
-#include "nouveau_hw.h"
-
-struct nv04_software_priv {
-	struct nouveau_software_priv base;
-};
-
-struct nv04_software_chan {
-	struct nouveau_software_chan base;
-};
-
-static int
-mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv04_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	return pch->base.flip(pch->base.flip_data);
-}
-
-static int
-nv04_software_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct nv04_software_chan *pch;
-
-	pch = kzalloc(sizeof(*pch), GFP_KERNEL);
-	if (!pch)
-		return -ENOMEM;
-
-	nouveau_software_context_new(chan, &pch->base);
-	chan->engctx[engine] = pch;
-	return 0;
-}
-
-static void
-nv04_software_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv04_software_chan *pch = chan->engctx[engine];
-	chan->engctx[engine] = NULL;
-	kfree(pch);
-}
-
-static int
-nv04_software_object_new(struct nouveau_channel *chan, int engine,
-			 u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 0;
-	obj->class  = class;
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
-}
-
-static int
-nv04_software_init(struct drm_device *dev, int engine)
-{
-	return 0;
-}
-
-static int
-nv04_software_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	return 0;
-}
-
-static void
-nv04_software_destroy(struct drm_device *dev, int engine)
-{
-	struct nv04_software_priv *psw = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, SW);
-	kfree(psw);
-}
-
-int
-nv04_software_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv04_software_priv *psw;
-
-	psw = kzalloc(sizeof(*psw), GFP_KERNEL);
-	if (!psw)
-		return -ENOMEM;
-
-	psw->base.base.destroy = nv04_software_destroy;
-	psw->base.base.init = nv04_software_init;
-	psw->base.base.fini = nv04_software_fini;
-	psw->base.base.context_new = nv04_software_context_new;
-	psw->base.base.context_del = nv04_software_context_del;
-	psw->base.base.object_new = nv04_software_object_new;
-	nouveau_software_create(&psw->base);
-
-	NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
-	if (dev_priv->card_type <= NV_04) {
-		NVOBJ_CLASS(dev, 0x006e, SW);
-		NVOBJ_MTHD (dev, 0x006e, 0x0150, nv04_fence_mthd);
-		NVOBJ_MTHD (dev, 0x006e, 0x0500, mthd_flip);
-	} else {
-		NVOBJ_CLASS(dev, 0x016e, SW);
-		NVOBJ_MTHD (dev, 0x016e, 0x0500, mthd_flip);
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c
index dd7f17d..ce752bf 100644
--- a/drivers/gpu/drm/nouveau/nv10_fence.c
+++ b/drivers/gpu/drm/nouveau/nv10_fence.c
@@ -22,10 +22,11 @@
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include <core/object.h>
+#include <core/class.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fence.h"
 
 struct nv10_fence_chan {
@@ -64,12 +65,11 @@
 nv17_fence_sync(struct nouveau_fence *fence,
 		struct nouveau_channel *prev, struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nv10_fence_priv *priv = dev_priv->fence.func;
+	struct nv10_fence_priv *priv = chan->drm->fence;
 	u32 value;
 	int ret;
 
-	if (!mutex_trylock(&prev->mutex))
+	if (!mutex_trylock(&prev->cli->mutex))
 		return -EBUSY;
 
 	spin_lock(&priv->lock);
@@ -96,14 +96,14 @@
 		FIRE_RING (chan);
 	}
 
-	mutex_unlock(&prev->mutex);
+	mutex_unlock(&prev->cli->mutex);
 	return 0;
 }
 
 u32
 nv10_fence_read(struct nouveau_channel *chan)
 {
-	return nvchan_rd32(chan, 0x0048);
+	return nv_ro32(chan->object, 0x0048);
 }
 
 void
@@ -118,10 +118,8 @@
 static int
 nv10_fence_context_new(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nv10_fence_priv *priv = dev_priv->fence.func;
+	struct nv10_fence_priv *priv = chan->drm->fence;
 	struct nv10_fence_chan *fctx;
-	struct nouveau_gpuobj *obj;
 	int ret = 0;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -132,15 +130,19 @@
 
 	if (priv->bo) {
 		struct ttm_mem_reg *mem = &priv->bo->bo.mem;
+		struct nouveau_object *object;
+		u32 start = mem->start * PAGE_SIZE;
+		u32 limit = mem->start + mem->size - 1;
 
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
-					     mem->start * PAGE_SIZE, mem->size,
-					     NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VRAM, &obj);
-		if (!ret) {
-			ret = nouveau_ramht_insert(chan, NvSema, obj);
-			nouveau_gpuobj_ref(NULL, &obj);
-		}
+		ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
+					 NvSema, 0x0002,
+					 &(struct nv_dma_class) {
+						.flags = NV_DMA_TARGET_VRAM |
+							 NV_DMA_ACCESS_RDWR,
+						.start = start,
+						.limit = limit,
+					 }, sizeof(struct nv_dma_class),
+					 &object);
 	}
 
 	if (ret)
@@ -149,24 +151,22 @@
 }
 
 void
-nv10_fence_destroy(struct drm_device *dev)
+nv10_fence_destroy(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv10_fence_priv *priv = dev_priv->fence.func;
-
+	struct nv10_fence_priv *priv = drm->fence;
+	nouveau_bo_unmap(priv->bo);
 	nouveau_bo_ref(NULL, &priv->bo);
-	dev_priv->fence.func = NULL;
+	drm->fence = NULL;
 	kfree(priv);
 }
 
 int
-nv10_fence_create(struct drm_device *dev)
+nv10_fence_create(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv10_fence_priv *priv;
 	int ret = 0;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -176,11 +176,10 @@
 	priv->base.emit = nv10_fence_emit;
 	priv->base.read = nv10_fence_read;
 	priv->base.sync = nv10_fence_sync;
-	dev_priv->fence.func = &priv->base;
 	spin_lock_init(&priv->lock);
 
-	if (dev_priv->chipset >= 0x17) {
-		ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+	if (nv_device(drm->device)->chipset >= 0x17) {
+		ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
 				     0, 0x0000, NULL, &priv->bo);
 		if (!ret) {
 			ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
@@ -197,6 +196,6 @@
 	}
 
 	if (ret)
-		nv10_fence_destroy(dev);
+		nv10_fence_destroy(drm);
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index d857525..93f536d 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -27,7 +27,6 @@
 #include <nouveau_bios.h>
 #include "nouveau_pm.h"
 #include "nouveau_hw.h"
-#include <engine/fifo.h>
 
 #define min2(a,b) ((a) < (b) ? (a) : (b))
 
@@ -259,7 +258,7 @@
 	if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000))
 		goto resume;
 	nv_mask(dev, 0x003200, 0x00000001, 0x00000000);
-	nv04_fifo_cache_pull(dev, false);
+	//XXX: nv04_fifo_cache_pull(dev, false);
 
 	if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev))
 		goto resume;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 83419a2..ae72f76 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -31,7 +31,6 @@
 #include "nouveau_connector.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
-#include <core/ramht.h>
 #include "drm_crtc_helper.h"
 #include "nouveau_fence.h"
 
@@ -102,17 +101,17 @@
 		BEGIN_NV04(evo, 0, 0x0084, 1);
 		OUT_RING  (evo, 0x00000000);
 
-		nv_wo32(disp->ntfy, 0x000, 0x00000000);
+		nv_wo32(disp->ramin, 0x2000, 0x00000000);
 		FIRE_RING (evo);
 
 		start = nv_timer_read(dev);
 		do {
-			if (nv_ro32(disp->ntfy, 0x000))
+			if (nv_ro32(disp->ramin, 0x2000))
 				return 0;
 		} while (nv_timer_read(dev) - start < 2000000000ULL);
 	}
 
-	return -EBUSY;
+	return 0;
 }
 
 int
@@ -217,7 +216,7 @@
 		return ret;
 	evo = nv50_display(dev)->master;
 
-	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->addr >> 8) | 9);
+	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (nv50_display(dev)->ramin->addr >> 8) | 9);
 
 	ret = RING_SPACE(evo, 3);
 	if (ret)
@@ -444,7 +443,7 @@
 			if (dev_priv->chipset < 0x84)
 				OUT_RING  (chan, NvSema);
 			else
-				OUT_RING  (chan, chan->vram_handle);
+				OUT_RING  (chan, chan->vram);
 		} else {
 			u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
 			offset += dispc->sem.offset;
@@ -598,48 +597,6 @@
 }
 
 static void
-nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
-	struct nouveau_software_chan *pch, *tmp;
-
-	list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
-		if (pch->vblank.head != crtc)
-			continue;
-
-		spin_lock(&psw->peephole_lock);
-		nv_wr32(dev, 0x001704, pch->vblank.channel);
-		nv_wr32(dev, 0x001710, 0x80000000 | pch->vblank.ctxdma);
-		if (dev_priv->chipset == 0x50) {
-			nv_wr32(dev, 0x001570, pch->vblank.offset);
-			nv_wr32(dev, 0x001574, pch->vblank.value);
-		} else {
-			nv_wr32(dev, 0x060010, pch->vblank.offset);
-			nv_wr32(dev, 0x060014, pch->vblank.value);
-		}
-		spin_unlock(&psw->peephole_lock);
-
-		list_del(&pch->vblank.list);
-		drm_vblank_put(dev, crtc);
-	}
-
-	drm_handle_vblank(dev, crtc);
-}
-
-static void
-nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
-{
-	if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
-		nv50_display_vblank_crtc_handler(dev, 0);
-
-	if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
-		nv50_display_vblank_crtc_handler(dev, 1);
-
-	nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
-}
-
-static void
 nv50_display_unk10_handler(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -978,8 +935,8 @@
 		}
 
 		if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
-			nv50_display_vblank_handler(dev, intr1);
 			intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
+			delayed |= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
 		}
 
 		clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 25c3013..ef12a7a 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -33,7 +33,6 @@
 #include "nouveau_dma.h"
 #include "nouveau_reg.h"
 #include "nouveau_crtc.h"
-#include "nouveau_software.h"
 #include "nv50_evo.h"
 
 struct nv50_display_crtc {
@@ -47,7 +46,10 @@
 
 struct nv50_display {
 	struct nouveau_channel *master;
-	struct nouveau_gpuobj *ntfy;
+
+	struct nouveau_gpuobj *ramin;
+	u32 dmao;
+	u32 hash;
 
 	struct nv50_display_crtc crtc[2];
 
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
index 7e9a6d6..d7d8080 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.c
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -26,9 +26,22 @@
 
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nv50_display.h"
 
+static u32
+nv50_evo_rd32(struct nouveau_object *object, u32 addr)
+{
+	void __iomem *iomem = object->oclass->ofuncs->rd08;
+	return ioread32_native(iomem + addr);
+}
+
+static void
+nv50_evo_wr32(struct nouveau_object *object, u32 addr, u32 data)
+{
+	void __iomem *iomem = object->oclass->ofuncs->rd08;
+	iowrite32_native(data, iomem + addr);
+}
+
 static void
 nv50_evo_channel_del(struct nouveau_channel **pevo)
 {
@@ -38,21 +51,24 @@
 		return;
 	*pevo = NULL;
 
-	nouveau_ramht_ref(NULL, &evo->ramht, evo);
-	nouveau_gpuobj_channel_takedown(evo);
-	nouveau_bo_unmap(evo->pushbuf_bo);
-	nouveau_bo_ref(NULL, &evo->pushbuf_bo);
+	nouveau_bo_unmap(evo->push.buffer);
+	nouveau_bo_ref(NULL, &evo->push.buffer);
 
-	if (evo->user)
-		iounmap(evo->user);
+	if (evo->object)
+		iounmap(evo->object->oclass->ofuncs);
 
 	kfree(evo);
 }
 
-void
-nv50_evo_dmaobj_init(struct nouveau_gpuobj *obj, u32 memtype, u64 base, u64 size)
+int
+nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype,
+		    u64 base, u64 size, struct nouveau_gpuobj **pobj)
 {
-	struct drm_nouveau_private *dev_priv = obj->dev->dev_private;
+	struct drm_device *dev = evo->fence;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nv50_display *disp = nv50_display(dev);
+	u32 dmao = disp->dmao;
+	u32 hash = disp->hash;
 	u32 flags5;
 
 	if (dev_priv->chipset < 0xc0) {
@@ -67,36 +83,21 @@
 			flags5 = 0x00020000;
 	}
 
-	nv50_gpuobj_dma_init(obj, 0, 0x3d, base, size, NV_MEM_TARGET_VRAM,
-			     NV_MEM_ACCESS_RW, (memtype >> 8) & 0xff, 0);
-	nv_wo32(obj, 0x14, flags5);
-	nvimem_flush(obj->dev);
-}
+	nv_wo32(disp->ramin, dmao + 0x00, 0x0019003d | (memtype << 22));
+	nv_wo32(disp->ramin, dmao + 0x04, lower_32_bits(base + size - 1));
+	nv_wo32(disp->ramin, dmao + 0x08, lower_32_bits(base));
+	nv_wo32(disp->ramin, dmao + 0x0c, upper_32_bits(base + size - 1) << 24 |
+					  upper_32_bits(base));
+	nv_wo32(disp->ramin, dmao + 0x10, 0x00000000);
+	nv_wo32(disp->ramin, dmao + 0x14, flags5);
 
-int
-nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype,
-		    u64 base, u64 size, struct nouveau_gpuobj **pobj)
-{
-	struct nv50_display *disp = nv50_display(evo->dev);
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
+	nv_wo32(disp->ramin, hash + 0x00, handle);
+	nv_wo32(disp->ramin, hash + 0x04, (evo->handle << 28) | (dmao << 10) |
+					   evo->handle);
 
-	ret = nouveau_gpuobj_new(evo->dev, disp->master, 6*4, 32, 0, &obj);
-	if (ret)
-		return ret;
-	obj->engine = NVOBJ_ENGINE_DISPLAY;
-
-	nv50_evo_dmaobj_init(obj, memtype, base, size);
-
-	ret = nouveau_ramht_insert(evo, handle, obj);
-	if (ret)
-		goto out;
-
-	if (pobj)
-		nouveau_gpuobj_ref(obj, pobj);
-out:
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
+	disp->dmao += 0x20;
+	disp->hash += 0x08;
+	return 0;
 }
 
 static int
@@ -112,49 +113,52 @@
 		return -ENOMEM;
 	*pevo = evo;
 
-	evo->id = chid;
-	evo->dev = dev;
+	evo->handle = chid;
+	evo->fence = dev;
 	evo->user_get = 4;
 	evo->user_put = 0;
 
 	ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL,
-			     &evo->pushbuf_bo);
+			     &evo->push.buffer);
 	if (ret == 0)
-		ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM);
+		ret = nouveau_bo_pin(evo->push.buffer, TTM_PL_FLAG_VRAM);
 	if (ret) {
 		NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret);
 		nv50_evo_channel_del(pevo);
 		return ret;
 	}
 
-	ret = nouveau_bo_map(evo->pushbuf_bo);
+	ret = nouveau_bo_map(evo->push.buffer);
 	if (ret) {
 		NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret);
 		nv50_evo_channel_del(pevo);
 		return ret;
 	}
 
-	evo->user = ioremap(pci_resource_start(dev->pdev, 0) +
-			    NV50_PDISPLAY_USER(evo->id), PAGE_SIZE);
-	if (!evo->user) {
-		NV_ERROR(dev, "Error mapping EVO control regs.\n");
-		nv50_evo_channel_del(pevo);
-		return -ENOMEM;
-	}
-
-	/* bind primary evo channel's ramht to the channel */
-	if (disp->master && evo != disp->master)
-		nouveau_ramht_ref(disp->master->ramht, &evo->ramht, NULL);
-
+	evo->object = kzalloc(sizeof(*evo->object), GFP_KERNEL);
+#ifdef NOUVEAU_OBJECT_MAGIC
+	evo->object->_magic = NOUVEAU_OBJECT_MAGIC;
+#endif
+	evo->object->parent = nv_object(disp->ramin)->parent;
+	evo->object->engine = nv_object(disp->ramin)->engine;
+	evo->object->oclass =
+		kzalloc(sizeof(*evo->object->oclass), GFP_KERNEL);
+	evo->object->oclass->ofuncs =
+		kzalloc(sizeof(*evo->object->oclass->ofuncs), GFP_KERNEL);
+	evo->object->oclass->ofuncs->rd32 = nv50_evo_rd32;
+	evo->object->oclass->ofuncs->wr32 = nv50_evo_wr32;
+	evo->object->oclass->ofuncs->rd08 =
+		ioremap(pci_resource_start(dev->pdev, 0) +
+			NV50_PDISPLAY_USER(evo->handle), PAGE_SIZE);
 	return 0;
 }
 
 static int
 nv50_evo_channel_init(struct nouveau_channel *evo)
 {
-	struct drm_device *dev = evo->dev;
-	int id = evo->id, ret, i;
-	u64 pushbuf = evo->pushbuf_bo->bo.offset;
+	struct drm_device *dev = evo->fence;
+	int id = evo->handle, ret, i;
+	u64 pushbuf = evo->push.buffer->bo.offset;
 	u32 tmp;
 
 	tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id));
@@ -205,8 +209,8 @@
 static void
 nv50_evo_channel_fini(struct nouveau_channel *evo)
 {
-	struct drm_device *dev = evo->dev;
-	int id = evo->id;
+	struct drm_device *dev = evo->fence;
+	int id = evo->handle;
 
 	nv_mask(dev, 0x610028, 0x00010001 << id, 0x00000000);
 	nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000);
@@ -231,8 +235,8 @@
 		}
 		nv50_evo_channel_del(&disp->crtc[i].sync);
 	}
-	nouveau_gpuobj_ref(NULL, &disp->ntfy);
 	nv50_evo_channel_del(&disp->master);
+	nouveau_gpuobj_ref(NULL, &disp->ramin);
 }
 
 int
@@ -240,10 +244,23 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_display *disp = nv50_display(dev);
-	struct nouveau_gpuobj *ramht = NULL;
 	struct nouveau_channel *evo;
 	int ret, i, j;
 
+	/* setup object management on it, any other evo channel will
+	 * use this also as there's no per-channel support on the
+	 * hardware
+	 */
+	ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536,
+				 NVOBJ_FLAG_ZERO_ALLOC, &disp->ramin);
+	if (ret) {
+		NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
+		goto err;
+	}
+
+	disp->hash = 0x0000;
+	disp->dmao = 0x1000;
+
 	/* create primary evo channel, the one we use for modesetting
 	 * purporses
 	 */
@@ -252,43 +269,8 @@
 		return ret;
 	evo = disp->master;
 
-	/* setup object management on it, any other evo channel will
-	 * use this also as there's no per-channel support on the
-	 * hardware
-	 */
-	ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536,
-				 NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin);
-	if (ret) {
-		NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
-		goto err;
-	}
-
-	ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht);
-	if (ret) {
-		NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
-		goto err;
-	}
-
-	ret = nouveau_ramht_new(dev, ramht, &evo->ramht);
-	nouveau_gpuobj_ref(NULL, &ramht);
-	if (ret)
-		goto err;
-
-	/* not sure exactly what this is..
-	 *
-	 * the first dword of the structure is used by nvidia to wait on
-	 * full completion of an EVO "update" command.
-	 *
-	 * method 0x8c on the master evo channel will fill a lot more of
-	 * this structure with some undefined info
-	 */
-	ret = nouveau_gpuobj_new(dev, disp->master, 0x1000, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &disp->ntfy);
-	if (ret)
-		goto err;
-
 	ret = nv50_evo_dmaobj_new(disp->master, NvEvoSync, 0x0000,
-				  disp->ntfy->addr, disp->ntfy->size, NULL);
+				  disp->ramin->addr + 0x2000, 0x1000, NULL);
 	if (ret)
 		goto err;
 
@@ -304,13 +286,13 @@
 		goto err;
 
 	ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB32, 0x80000000 |
-				  (dev_priv->chipset < 0xc0 ? 0x7a00 : 0xfe00),
+				  (dev_priv->chipset < 0xc0 ? 0x7a : 0xfe),
 				  0, nvfb_vram_size(dev), NULL);
 	if (ret)
 		goto err;
 
 	ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB16, 0x80000000 |
-				  (dev_priv->chipset < 0xc0 ? 0x7000 : 0xfe00),
+				  (dev_priv->chipset < 0xc0 ? 0x70 : 0xfe),
 				  0, nvfb_vram_size(dev), NULL);
 	if (ret)
 		goto err;
@@ -352,14 +334,14 @@
 
 		ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 |
 					  (dev_priv->chipset < 0xc0 ?
-					  0x7a00 : 0xfe00),
+					  0x7a : 0xfe),
 					  0, nvfb_vram_size(dev), NULL);
 		if (ret)
 			goto err;
 
 		ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 |
 					  (dev_priv->chipset < 0xc0 ?
-					  0x7000 : 0xfe00),
+					  0x70 : 0xfe),
 					  0, nvfb_vram_size(dev), NULL);
 		if (ret)
 			goto err;
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index 1593e24..2028a44 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -22,20 +22,16 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fbcon.h"
-#include <core/mm.h>
 
 int
 nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
@@ -69,9 +65,8 @@
 nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, 12);
@@ -98,9 +93,8 @@
 nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	uint32_t width, dwords, *data = (uint32_t *)image->data;
 	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 	uint32_t *palette = info->pseudo_palette;
@@ -156,10 +150,11 @@
 nv50_fbcon_accel_init(struct fb_info *info)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
 	struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb;
+	struct drm_device *dev = nfbdev->dev;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_channel *chan = drm->channel;
+	struct nouveau_object *object;
 	int ret, format;
 
 	switch (info->var.bits_per_pixel) {
@@ -189,7 +184,8 @@
 		return -EINVAL;
 	}
 
-	ret = nouveau_gpuobj_gr_new(dev_priv->channel, Nv2D, 0x502d);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, Nv2D,
+				 0x502d, NULL, 0, &object);
 	if (ret)
 		return ret;
 
@@ -202,9 +198,9 @@
 	BEGIN_NV04(chan, NvSub2D, 0x0000, 1);
 	OUT_RING(chan, Nv2D);
 	BEGIN_NV04(chan, NvSub2D, 0x0184, 3);
-	OUT_RING(chan, chan->vram_handle);
-	OUT_RING(chan, chan->vram_handle);
-	OUT_RING(chan, chan->vram_handle);
+	OUT_RING(chan, NvDmaFB);
+	OUT_RING(chan, NvDmaFB);
+	OUT_RING(chan, NvDmaFB);
 	BEGIN_NV04(chan, NvSub2D, 0x0290, 1);
 	OUT_RING(chan, 0);
 	BEGIN_NV04(chan, NvSub2D, 0x0888, 1);
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c
index 10aa04f..e717aaa 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -22,12 +22,12 @@
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include <core/object.h>
+#include <core/class.h>
+
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fence.h"
-#include "nv50_display.h"
 
 struct nv50_fence_chan {
 	struct nouveau_fence_chan base;
@@ -43,12 +43,11 @@
 static int
 nv50_fence_context_new(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nv50_fence_priv *priv = dev_priv->fence.func;
+	struct nv50_fence_priv *priv = chan->drm->fence;
 	struct nv50_fence_chan *fctx;
 	struct ttm_mem_reg *mem = &priv->bo->bo.mem;
-	struct nouveau_gpuobj *obj;
-	int ret = 0, i;
+	struct nouveau_object *object;
+	int ret, i;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
 	if (!fctx)
@@ -56,30 +55,29 @@
 
 	nouveau_fence_context_new(&fctx->base);
 
-	ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
-				     mem->start * PAGE_SIZE, mem->size,
-				     NV_MEM_ACCESS_RW,
-				     NV_MEM_TARGET_VRAM, &obj);
-	if (!ret) {
-		ret = nouveau_ramht_insert(chan, NvSema, obj);
-		nouveau_gpuobj_ref(NULL, &obj);
-	}
+	ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
+				 NvSema, 0x0002,
+				 &(struct nv_dma_class) {
+					.flags = NV_DMA_TARGET_VRAM |
+						 NV_DMA_ACCESS_RDWR,
+					.start = mem->start * PAGE_SIZE,
+					.limit = mem->size - 1,
+				 }, sizeof(struct nv_dma_class),
+				 &object);
 
 	/* dma objects for display sync channel semaphore blocks */
-	for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
-		struct nv50_display *pdisp = nv50_display(chan->dev);
-		struct nv50_display_crtc *dispc = &pdisp->crtc[i];
-		struct nouveau_gpuobj *obj = NULL;
+	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
+		struct nouveau_bo *bo = nv50sema(chan->drm->dev, i);
 
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     dispc->sem.bo->bo.offset, 0x1000,
-					     NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VRAM, &obj);
-		if (ret)
-			break;
-
-		ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
-		nouveau_gpuobj_ref(NULL, &obj);
+		ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
+					 NvEvoSema0 + i, 0x003d,
+					 &(struct nv_dma_class) {
+						.flags = NV_DMA_TARGET_VRAM |
+							 NV_DMA_ACCESS_RDWR,
+						.start = bo->bo.offset,
+						.limit = bo->bo.offset + 0xfff,
+					 }, sizeof(struct nv_dma_class),
+					 &object);
 	}
 
 	if (ret)
@@ -88,13 +86,12 @@
 }
 
 int
-nv50_fence_create(struct drm_device *dev)
+nv50_fence_create(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_fence_priv *priv;
 	int ret = 0;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -104,10 +101,9 @@
 	priv->base.emit = nv10_fence_emit;
 	priv->base.read = nv10_fence_read;
 	priv->base.sync = nv17_fence_sync;
-	dev_priv->fence.func = &priv->base;
 	spin_lock_init(&priv->lock);
 
-	ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+	ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
 			     0, 0x0000, NULL, &priv->bo);
 	if (!ret) {
 		ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
@@ -117,9 +113,12 @@
 			nouveau_bo_ref(NULL, &priv->bo);
 	}
 
-	if (ret == 0)
+	if (ret == 0) {
 		nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
-	else
-		nv10_fence_destroy(dev);
+		priv->base.sync = nv17_fence_sync;
+	}
+
+	if (ret)
+		nv10_fence_destroy(drm);
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 142cd4e..ac02084 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -28,7 +28,6 @@
 #include "nouveau_hw.h"
 #include "nouveau_pm.h"
 #include "nouveau_hwsq.h"
-#include "nv50_display.h"
 
 enum clk_src {
 	clk_src_crystal,
diff --git a/drivers/gpu/drm/nouveau/nv50_software.c b/drivers/gpu/drm/nouveau/nv50_software.c
deleted file mode 100644
index 7c9dbe8..0000000
--- a/drivers/gpu/drm/nouveau/nv50_software.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright 2012 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"
-#include <core/ramht.h>
-#include "nouveau_software.h"
-
-#include "nv50_display.h"
-
-struct nv50_software_priv {
-	struct nouveau_software_priv base;
-};
-
-struct nv50_software_chan {
-	struct nouveau_software_chan base;
-};
-
-static int
-mthd_dma_vblsem(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	struct nouveau_gpuobj *gpuobj;
-
-	gpuobj = nouveau_ramht_find(chan, data);
-	if (!gpuobj)
-		return -ENOENT;
-
-	pch->base.vblank.ctxdma = gpuobj->node->offset >> 4;
-	return 0;
-}
-
-static int
-mthd_vblsem_offset(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	pch->base.vblank.offset = data;
-	return 0;
-}
-
-static int
-mthd_vblsem_value(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	pch->base.vblank.value = data;
-	return 0;
-}
-
-static int
-mthd_vblsem_release(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv50_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
-	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	struct drm_device *dev = chan->dev;
-
-	if (data > 1)
-		return -EINVAL;
-
-	drm_vblank_get(dev, data);
-
-	pch->base.vblank.head = data;
-	list_add(&pch->base.vblank.list, &psw->base.vblank);
-	return 0;
-}
-
-static int
-mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
-{
-	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-	return pch->base.flip(pch->base.flip_data);
-}
-
-static int
-nv50_software_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct nv50_software_chan *pch;
-
-	pch = kzalloc(sizeof(*pch), GFP_KERNEL);
-	if (!pch)
-		return -ENOMEM;
-
-	nouveau_software_context_new(chan, &pch->base);
-	pch->base.vblank.channel = chan->ramin->addr >> 12;
-	chan->engctx[engine] = pch;
-	return 0;
-}
-
-static void
-nv50_software_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nv50_software_chan *pch = chan->engctx[engine];
-	chan->engctx[engine] = NULL;
-	kfree(pch);
-}
-
-static int
-nv50_software_object_new(struct nouveau_channel *chan, int engine,
-			 u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 0;
-	obj->class  = class;
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
-}
-
-static int
-nv50_software_init(struct drm_device *dev, int engine)
-{
-	return 0;
-}
-
-static int
-nv50_software_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	return 0;
-}
-
-static void
-nv50_software_destroy(struct drm_device *dev, int engine)
-{
-	struct nv50_software_priv *psw = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, SW);
-	kfree(psw);
-}
-
-int
-nv50_software_create(struct drm_device *dev)
-{
-	struct nv50_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
-	if (!psw)
-		return -ENOMEM;
-
-	psw->base.base.destroy = nv50_software_destroy;
-	psw->base.base.init = nv50_software_init;
-	psw->base.base.fini = nv50_software_fini;
-	psw->base.base.context_new = nv50_software_context_new;
-	psw->base.base.context_del = nv50_software_context_del;
-	psw->base.base.object_new = nv50_software_object_new;
-	nouveau_software_create(&psw->base);
-
-	NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
-	NVOBJ_CLASS(dev, 0x506e, SW);
-	NVOBJ_MTHD (dev, 0x506e, 0x018c, mthd_dma_vblsem);
-	NVOBJ_MTHD (dev, 0x506e, 0x0400, mthd_vblsem_offset);
-	NVOBJ_MTHD (dev, 0x506e, 0x0404, mthd_vblsem_value);
-	NVOBJ_MTHD (dev, 0x506e, 0x0408, mthd_vblsem_release);
-	NVOBJ_MTHD (dev, 0x506e, 0x0500, mthd_flip);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index 5ef87ed..b0d147a 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -22,13 +22,14 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_dma.h"
+#include <core/object.h>
+#include <core/class.h>
+
 #include <engine/fifo.h>
-#include <core/ramht.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
 #include "nouveau_fence.h"
-#include "nv50_display.h"
 
 struct nv84_fence_chan {
 	struct nouveau_fence_chan base;
@@ -43,13 +44,14 @@
 nv84_fence_emit(struct nouveau_fence *fence)
 {
 	struct nouveau_channel *chan = fence->channel;
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
 	int ret = RING_SPACE(chan, 7);
 	if (ret == 0) {
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
 		OUT_RING  (chan, NvSema);
 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
-		OUT_RING  (chan, upper_32_bits(chan->id * 16));
-		OUT_RING  (chan, lower_32_bits(chan->id * 16));
+		OUT_RING  (chan, upper_32_bits(fifo->chid * 16));
+		OUT_RING  (chan, lower_32_bits(fifo->chid * 16));
 		OUT_RING  (chan, fence->sequence);
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
 		FIRE_RING (chan);
@@ -62,13 +64,14 @@
 nv84_fence_sync(struct nouveau_fence *fence,
 		struct nouveau_channel *prev, struct nouveau_channel *chan)
 {
+	struct nouveau_fifo_chan *fifo = (void *)prev->object;
 	int ret = RING_SPACE(chan, 7);
 	if (ret == 0) {
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
 		OUT_RING  (chan, NvSema);
 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
-		OUT_RING  (chan, upper_32_bits(prev->id * 16));
-		OUT_RING  (chan, lower_32_bits(prev->id * 16));
+		OUT_RING  (chan, upper_32_bits(fifo->chid * 16));
+		OUT_RING  (chan, lower_32_bits(fifo->chid * 16));
 		OUT_RING  (chan, fence->sequence);
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
 		FIRE_RING (chan);
@@ -79,9 +82,9 @@
 static u32
 nv84_fence_read(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nv84_fence_priv *priv = dev_priv->fence.func;
-	return nv_ro32(priv->mem, chan->id * 16);
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	struct nv84_fence_priv *priv = chan->drm->fence;
+	return nv_ro32(priv->mem, fifo->chid * 16);
 }
 
 static void
@@ -96,10 +99,10 @@
 static int
 nv84_fence_context_new(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nv84_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	struct nv84_fence_priv *priv = chan->drm->fence;
 	struct nv84_fence_chan *fctx;
-	struct nouveau_gpuobj *obj;
+	struct nouveau_object *object;
 	int ret, i;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -108,58 +111,56 @@
 
 	nouveau_fence_context_new(&fctx->base);
 
-	ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
-				     priv->mem->addr, priv->mem->size,
-				     NV_MEM_ACCESS_RW,
-				     NV_MEM_TARGET_VRAM, &obj);
-	if (ret == 0) {
-		ret = nouveau_ramht_insert(chan, NvSema, obj);
-		nouveau_gpuobj_ref(NULL, &obj);
-		nv_wo32(priv->mem, chan->id * 16, 0x00000000);
-	}
+	ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
+				 NvSema, 0x0002,
+				 &(struct nv_dma_class) {
+					.flags = NV_DMA_TARGET_VRAM |
+						 NV_DMA_ACCESS_RDWR,
+					.start = priv->mem->addr,
+					.limit = priv->mem->addr +
+						 priv->mem->size - 1,
+				 }, sizeof(struct nv_dma_class),
+				 &object);
 
 	/* dma objects for display sync channel semaphore blocks */
-	for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
-		struct nv50_display *pdisp = nv50_display(chan->dev);
-		struct nv50_display_crtc *dispc = &pdisp->crtc[i];
-		struct nouveau_gpuobj *obj = NULL;
+	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
+		struct nouveau_bo *bo = nv50sema(chan->drm->dev, i);
 
-		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-					     dispc->sem.bo->bo.offset, 0x1000,
-					     NV_MEM_ACCESS_RW,
-					     NV_MEM_TARGET_VRAM, &obj);
-		if (ret)
-			break;
-
-		ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
-		nouveau_gpuobj_ref(NULL, &obj);
+		ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
+					 NvEvoSema0 + i, 0x003d,
+					 &(struct nv_dma_class) {
+						.flags = NV_DMA_TARGET_VRAM |
+							 NV_DMA_ACCESS_RDWR,
+						.start = bo->bo.offset,
+						.limit = bo->bo.offset + 0xfff,
+					 }, sizeof(struct nv_dma_class),
+					 &object);
 	}
 
 	if (ret)
 		nv84_fence_context_del(chan);
+	nv_wo32(priv->mem, fifo->chid * 16, 0x00000000);
 	return ret;
 }
 
 static void
-nv84_fence_destroy(struct drm_device *dev)
+nv84_fence_destroy(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv84_fence_priv *priv = dev_priv->fence.func;
-
+	struct nv84_fence_priv *priv = drm->fence;
 	nouveau_gpuobj_ref(NULL, &priv->mem);
-	dev_priv->fence.func = NULL;
+	drm->fence = NULL;
 	kfree(priv);
 }
 
 int
-nv84_fence_create(struct drm_device *dev)
+nv84_fence_create(struct nouveau_drm *drm)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 	struct nv84_fence_priv *priv;
+	u32 chan = pfifo->max + 1;
 	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -169,15 +170,10 @@
 	priv->base.emit = nv84_fence_emit;
 	priv->base.sync = nv84_fence_sync;
 	priv->base.read = nv84_fence_read;
-	dev_priv->fence.func = priv;
 
-	ret = nouveau_gpuobj_new(dev, NULL, 16 * pfifo->channels,
-				 0x1000, 0, &priv->mem);
+	ret = nouveau_gpuobj_new(drm->device, NULL, chan * 16, 0x1000, 0,
+				&priv->mem);
 	if (ret)
-		goto out;
-
-out:
-	if (ret)
-		nv84_fence_destroy(dev);
+		nv84_fence_destroy(drm);
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
index db26e050..cc88f36 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
@@ -22,20 +22,16 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nouveau_drm.h"
 #include "nouveau_dma.h"
-#include <core/ramht.h>
 #include "nouveau_fbcon.h"
-#include <core/mm.h>
 
 int
 nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
@@ -69,9 +65,8 @@
 nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	int ret;
 
 	ret = RING_SPACE(chan, 12);
@@ -98,9 +93,8 @@
 nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	struct nouveau_fbdev *nfbdev = info->par;
-	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
+	struct nouveau_drm *drm = nouveau_newpriv(nfbdev->dev);
+	struct nouveau_channel *chan = drm->channel;
 	uint32_t width, dwords, *data = (uint32_t *)image->data;
 	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
 	uint32_t *palette = info->pseudo_palette;
@@ -157,12 +151,14 @@
 {
 	struct nouveau_fbdev *nfbdev = info->par;
 	struct drm_device *dev = nfbdev->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = dev_priv->channel;
 	struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb;
+	struct nouveau_drm *drm = nouveau_newpriv(dev);
+	struct nouveau_channel *chan = drm->channel;
+	struct nouveau_object *object;
 	int ret, format;
 
-	ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d);
+	ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, Nv2D,
+				 0x902d, NULL, 0, &object);
 	if (ret)
 		return ret;
 
@@ -202,9 +198,6 @@
 
 	BEGIN_NVC0(chan, NvSub2D, 0x0000, 1);
 	OUT_RING  (chan, 0x0000902d);
-	BEGIN_NVC0(chan, NvSub2D, 0x0104, 2);
-	OUT_RING  (chan, upper_32_bits(chan->notifier_vma.offset));
-	OUT_RING  (chan, lower_32_bits(chan->notifier_vma.offset));
 	BEGIN_NVC0(chan, NvSub2D, 0x0290, 1);
 	OUT_RING  (chan, 0);
 	BEGIN_NVC0(chan, NvSub2D, 0x0888, 1);
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c
index 779c5ff..ce612ad 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fence.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fence.c
@@ -22,13 +22,15 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include "nouveau_dma.h"
+#include <core/object.h>
+#include <core/client.h>
+#include <core/class.h>
+
 #include <engine/fifo.h>
-#include <core/ramht.h>
+
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
 #include "nouveau_fence.h"
-#include "nv50_display.h"
 
 struct nvc0_fence_priv {
 	struct nouveau_fence_priv base;
@@ -54,7 +56,8 @@
 {
 	struct nouveau_channel *chan = fence->channel;
 	struct nvc0_fence_chan *fctx = chan->fence;
-	u64 addr = fctx->vma.offset + chan->id * 16;
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	u64 addr = fctx->vma.offset + fifo->chid * 16;
 	int ret;
 
 	ret = RING_SPACE(chan, 5);
@@ -75,7 +78,8 @@
 		struct nouveau_channel *prev, struct nouveau_channel *chan)
 {
 	struct nvc0_fence_chan *fctx = chan->fence;
-	u64 addr = fctx->vma.offset + prev->id * 16;
+	struct nouveau_fifo_chan *fifo = (void *)prev->object;
+	u64 addr = fctx->vma.offset + fifo->chid * 16;
 	int ret;
 
 	ret = RING_SPACE(chan, 5);
@@ -95,31 +99,29 @@
 static u32
 nvc0_fence_read(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
-	return nouveau_bo_rd32(priv->bo, chan->id * 16/4);
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	struct nvc0_fence_priv *priv = chan->drm->fence;
+	return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4);
 }
 
 static void
 nvc0_fence_context_del(struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
+	struct drm_device *dev = chan->drm->dev;
+	struct nvc0_fence_priv *priv = chan->drm->fence;
 	struct nvc0_fence_chan *fctx = chan->fence;
 	int i;
 
-	if (dev_priv->card_type >= NV_D0) {
+	if (nv_device(chan->drm->device)->card_type >= NV_D0) {
 		for (i = 0; i < dev->mode_config.num_crtc; i++) {
-			struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
+			struct nouveau_bo *bo = nvd0sema(dev, i);
 			nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
 		}
 	} else
-	if (dev_priv->card_type >= NV_50) {
-		struct nv50_display *disp = nv50_display(dev);
+	if (nv_device(chan->drm->device)->card_type >= NV_50) {
 		for (i = 0; i < dev->mode_config.num_crtc; i++) {
-			struct nv50_display_crtc *dispc = &disp->crtc[i];
-			nouveau_bo_vma_del(dispc->sem.bo, &fctx->dispc_vma[i]);
+			struct nouveau_bo *bo = nv50sema(dev, i);
+			nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
 		}
 	}
 
@@ -132,9 +134,9 @@
 static int
 nvc0_fence_context_new(struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	struct nouveau_client *client = nouveau_client(fifo);
+	struct nvc0_fence_priv *priv = chan->drm->fence;
 	struct nvc0_fence_chan *fctx;
 	int ret, i;
 
@@ -144,36 +146,35 @@
 
 	nouveau_fence_context_new(&fctx->base);
 
-	ret = nouveau_bo_vma_add(priv->bo, chan->vm, &fctx->vma);
+	ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma);
 	if (ret)
 		nvc0_fence_context_del(chan);
 
 	/* map display semaphore buffers into channel's vm */
-	for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
+	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
 		struct nouveau_bo *bo;
-		if (dev_priv->card_type >= NV_D0)
-			bo = nvd0_display_crtc_sema(dev, i);
+		if (nv_device(chan->drm->device)->card_type >= NV_D0)
+			bo = nvd0sema(chan->drm->dev, i);
 		else
-			bo = nv50_display(dev)->crtc[i].sem.bo;
+			bo = nv50sema(chan->drm->dev, i);
 
-		ret = nouveau_bo_vma_add(bo, chan->vm, &fctx->dispc_vma[i]);
+		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
 	}
 
-	nouveau_bo_wr32(priv->bo, chan->id * 16/4, 0x00000000);
+	nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
 	return ret;
 }
 
 static bool
-nvc0_fence_suspend(struct drm_device *dev)
+nvc0_fence_suspend(struct nouveau_drm *drm)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
+	struct nvc0_fence_priv *priv = drm->fence;
 	int i;
 
-	priv->suspend = vmalloc(pfifo->channels * sizeof(u32));
+	priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
 	if (priv->suspend) {
-		for (i = 0; i < pfifo->channels; i++)
+		for (i = 0; i <= pfifo->max; i++)
 			priv->suspend[i] = nouveau_bo_rd32(priv->bo, i);
 	}
 
@@ -181,15 +182,14 @@
 }
 
 static void
-nvc0_fence_resume(struct drm_device *dev)
+nvc0_fence_resume(struct nouveau_drm *drm)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
+	struct nvc0_fence_priv *priv = drm->fence;
 	int i;
 
 	if (priv->suspend) {
-		for (i = 0; i < pfifo->channels; i++)
+		for (i = 0; i <= pfifo->max; i++)
 			nouveau_bo_wr32(priv->bo, i, priv->suspend[i]);
 		vfree(priv->suspend);
 		priv->suspend = NULL;
@@ -197,26 +197,23 @@
 }
 
 static void
-nvc0_fence_destroy(struct drm_device *dev)
+nvc0_fence_destroy(struct nouveau_drm *drm)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_fence_priv *priv = dev_priv->fence.func;
-
+	struct nvc0_fence_priv *priv = drm->fence;
 	nouveau_bo_unmap(priv->bo);
 	nouveau_bo_ref(NULL, &priv->bo);
-	dev_priv->fence.func = NULL;
+	drm->fence = NULL;
 	kfree(priv);
 }
 
 int
-nvc0_fence_create(struct drm_device *dev)
+nvc0_fence_create(struct nouveau_drm *drm)
 {
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 	struct nvc0_fence_priv *priv;
 	int ret;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -228,10 +225,9 @@
 	priv->base.emit = nvc0_fence_emit;
 	priv->base.sync = nvc0_fence_sync;
 	priv->base.read = nvc0_fence_read;
-	dev_priv->fence.func = priv;
 
-	ret = nouveau_bo_new(dev, 16 * pfifo->channels, 0, TTM_PL_FLAG_VRAM,
-			     0, 0, NULL, &priv->bo);
+	ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
+			     TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
 	if (ret == 0) {
 		ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
 		if (ret == 0)
@@ -241,6 +237,6 @@
 	}
 
 	if (ret)
-		nvc0_fence_destroy(dev);
+		nvc0_fence_destroy(drm);
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nvc0_software.c b/drivers/gpu/drm/nouveau/nvc0_software.c
deleted file mode 100644
index eaaa576..0000000
--- a/drivers/gpu/drm/nouveau/nvc0_software.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2012 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"
-#include <core/ramht.h>
-#include "nouveau_software.h"
-
-#include "nv50_display.h"
-
-struct nvc0_software_priv {
-	struct nouveau_software_priv base;
-};
-
-struct nvc0_software_chan {
-	struct nouveau_software_chan base;
-};
-
-static int
-nvc0_software_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct nvc0_software_chan *pch;
-
-	pch = kzalloc(sizeof(*pch), GFP_KERNEL);
-	if (!pch)
-		return -ENOMEM;
-
-	nouveau_software_context_new(chan, &pch->base);
-	chan->engctx[engine] = pch;
-	return 0;
-}
-
-static void
-nvc0_software_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nvc0_software_chan *pch = chan->engctx[engine];
-	chan->engctx[engine] = NULL;
-	kfree(pch);
-}
-
-static int
-nvc0_software_object_new(struct nouveau_channel *chan, int engine,
-			 u32 handle, u16 class)
-{
-	return 0;
-}
-
-static int
-nvc0_software_init(struct drm_device *dev, int engine)
-{
-	return 0;
-}
-
-static int
-nvc0_software_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	return 0;
-}
-
-static void
-nvc0_software_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_software_priv *psw = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, SW);
-	kfree(psw);
-}
-
-int
-nvc0_software_create(struct drm_device *dev)
-{
-	struct nvc0_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
-	if (!psw)
-		return -ENOMEM;
-
-	psw->base.base.destroy = nvc0_software_destroy;
-	psw->base.base.init = nvc0_software_init;
-	psw->base.base.fini = nvc0_software_fini;
-	psw->base.base.context_new = nvc0_software_context_new;
-	psw->base.base.context_del = nvc0_software_context_del;
-	psw->base.base.object_new = nvc0_software_object_new;
-	nouveau_software_create(&psw->base);
-
-	NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
-	NVOBJ_CLASS(dev, 0x906e, SW);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 2da4927..37b3f3f 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -31,7 +31,6 @@
 #include "nouveau_connector.h"
 #include "nouveau_encoder.h"
 #include "nouveau_crtc.h"
-#include "nouveau_dma.h"
 #include "nouveau_fb.h"
 #include "nouveau_fence.h"
 #include "nv50_display.h"
@@ -1830,15 +1829,7 @@
 		intr &= ~0x00100000;
 	}
 
-	for (i = 0; i < dev->mode_config.num_crtc; i++) {
-		u32 mask = 0x01000000 << i;
-		if (intr & mask) {
-			u32 stat = nv_rd32(dev, 0x6100bc + (i * 0x800));
-			nv_wr32(dev, 0x6100bc + (i * 0x800), stat);
-			intr &= ~mask;
-		}
-	}
-
+	intr &= ~0x0f000000; /* vblank, handled in core */
 	if (intr)
 		NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
 }