[kernel/f14/master] nouveau: more updates

Ben Skeggs bskeggs at fedoraproject.org
Wed Sep 8 06:24:57 UTC 2010


commit 215a71b03df53886372ecce4bb2012335845dbfc
Author: Ben Skeggs <bskeggs at redhat.com>
Date:   Wed Sep 8 16:23:30 2010 +1000

    nouveau: more updates

 drm-nouveau-updates.patch | 4581 ++++++++++++++++++++++++++++++++++++++-------
 kernel.spec               |    5 +-
 2 files changed, 3925 insertions(+), 661 deletions(-)
---
diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch
index 82ded47..9749a29 100644
--- a/drm-nouveau-updates.patch
+++ b/drm-nouveau-updates.patch
@@ -1,7 +1,7 @@
-From c156fa3c71b6581b34526a9b2b649c3f4d57dd3e Mon Sep 17 00:00:00 2001
+From 71c6844b5918cd5b1f8b61735e52be12fb5f80e5 Mon Sep 17 00:00:00 2001
 From: Ben Skeggs <bskeggs at redhat.com>
 Date: Tue, 1 Jun 2010 15:32:24 +1000
-Subject: [PATCH 1/2] drm-nouveau-updates
+Subject: [PATCH] drm-nouveau-updates
 MIME-Version: 1.0
 Content-Type: text/plain; charset=UTF-8
 Content-Transfer-Encoding: 8bit
@@ -843,6 +843,120 @@ Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
 drm/nv50: report BAR access faults
 
 Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: rebase per-channel pramin heap offsets to 0
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: remove nouveau_gpuobj_ref completely, replace with sanity
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: simplify fake gpu objects
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: allow gpuobjs that aren't mapped into aperture
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: rework init ordering so nv50_instmem.c can be less bad
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: tidy ram{ht,fc,ro} a bit
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: add spinlock around ramht modifications
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: fix gpuobj refcount to use atomics
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: protect gpuobj list + global instmem heap with spinlock
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: remove nouveau_gpuobj_late_takedown
+
+Reviewed-by: Francisco Jerez <currojerez at riseup.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: protect ramht_find() from oopsing if on channel without ramht
+
+This doesn't actually happen now, but there's a test case for an earlier
+kernel where a GPU error is signalled on one of nv50's fake channels, and
+the ramht lookup by the IRQ handler triggered an oops.
+
+This adds a check for RAMHT's existance on a channel before looking up
+an object handle.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: fix SOR count for early chipsets
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: Break some long lines in the TV-out code.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: Don't remove ramht entries from the neighboring channels.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: Don't enable AGP FW on nv18.
+
+FW seems to be broken on nv18, it causes random lockups and breaks
+suspend/resume even with the blob.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: Add module parameter to override the default AGP rate.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: PRAMIN is available from the start on pre-nv50.
+
+This makes sure that RAMHT is cleared correctly on start up.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: Remove implicit argument from nv_wait().
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: Simplify tile region handling.
+
+Instead of emptying the caches to avoid a race with the PFIFO puller,
+go straight ahead and try to recover from it when it happens. Also,
+kill pfifo->cache_flush and tile->lock, we don't need them anymore.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: handle fifo pusher errors better
+
+The most important part of this change is that we now instruct PFIFO to
+drop all pending fetches, rather than attempting to skip a single dword
+and hope that things would magically sort themselves out - they usually
+don't, and we end up with PFIFO being completely hung.
+
+This commit also adds somewhat more useful logging when these exceptions
+occur.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
 ---
  drivers/gpu/drm/drm_crtc_helper.c           |   22 +-
  drivers/gpu/drm/i2c/ch7006_drv.c            |   22 +-
@@ -851,15 +965,15 @@ Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
  drivers/gpu/drm/nouveau/nouveau_acpi.c      |   38 +-
  drivers/gpu/drm/nouveau/nouveau_bios.c      |  910 ++++++--
  drivers/gpu/drm/nouveau/nouveau_bios.h      |    6 +-
- drivers/gpu/drm/nouveau/nouveau_bo.c        |  223 ++-
+ drivers/gpu/drm/nouveau/nouveau_bo.c        |  228 ++-
  drivers/gpu/drm/nouveau/nouveau_calc.c      |   10 +-
- drivers/gpu/drm/nouveau/nouveau_channel.c   |    6 +-
+ drivers/gpu/drm/nouveau/nouveau_channel.c   |   18 +-
  drivers/gpu/drm/nouveau/nouveau_connector.c |  417 ++--
  drivers/gpu/drm/nouveau/nouveau_connector.h |    7 +-
- drivers/gpu/drm/nouveau/nouveau_dma.c       |    7 -
- drivers/gpu/drm/nouveau/nouveau_dp.c        |  128 +-
- drivers/gpu/drm/nouveau/nouveau_drv.c       |   39 +-
- drivers/gpu/drm/nouveau/nouveau_drv.h       |  203 +-
+ drivers/gpu/drm/nouveau/nouveau_dma.c       |   21 +-
+ drivers/gpu/drm/nouveau/nouveau_dp.c        |  131 +-
+ drivers/gpu/drm/nouveau/nouveau_drv.c       |   45 +-
+ drivers/gpu/drm/nouveau/nouveau_drv.h       |  309 ++--
  drivers/gpu/drm/nouveau/nouveau_encoder.h   |   16 +-
  drivers/gpu/drm/nouveau/nouveau_fbcon.c     |    4 +-
  drivers/gpu/drm/nouveau/nouveau_fence.c     |   35 +-
@@ -869,52 +983,57 @@ Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
  drivers/gpu/drm/nouveau/nouveau_hw.c        |   13 +-
  drivers/gpu/drm/nouveau/nouveau_i2c.c       |   83 +-
  drivers/gpu/drm/nouveau/nouveau_i2c.h       |   11 +-
- drivers/gpu/drm/nouveau/nouveau_irq.c       |   70 +-
- drivers/gpu/drm/nouveau/nouveau_mem.c       |  404 ++---
- drivers/gpu/drm/nouveau/nouveau_notifier.c  |   30 +-
- drivers/gpu/drm/nouveau/nouveau_object.c    |  325 +--
- drivers/gpu/drm/nouveau/nouveau_ramht.c     |  160 ++
- drivers/gpu/drm/nouveau/nouveau_ramht.h     |   31 +
- drivers/gpu/drm/nouveau/nouveau_reg.h       |  109 +-
- drivers/gpu/drm/nouveau/nouveau_sgdma.c     |  108 +-
- drivers/gpu/drm/nouveau/nouveau_state.c     |  340 ++-
+ drivers/gpu/drm/nouveau/nouveau_irq.c       |  129 +-
+ drivers/gpu/drm/nouveau/nouveau_mem.c       |  529 ++---
+ drivers/gpu/drm/nouveau/nouveau_notifier.c  |   37 +-
+ drivers/gpu/drm/nouveau/nouveau_object.c    |  853 +++-----
+ drivers/gpu/drm/nouveau/nouveau_ramht.c     |  289 +++
+ drivers/gpu/drm/nouveau/nouveau_ramht.h     |   55 +
+ drivers/gpu/drm/nouveau/nouveau_reg.h       |  118 +-
+ drivers/gpu/drm/nouveau/nouveau_sgdma.c     |  117 +-
+ drivers/gpu/drm/nouveau/nouveau_state.c     |  398 ++--
  drivers/gpu/drm/nouveau/nv04_crtc.c         |   11 +-
  drivers/gpu/drm/nouveau/nv04_dac.c          |   60 +-
  drivers/gpu/drm/nouveau/nv04_dfp.c          |  145 +-
  drivers/gpu/drm/nouveau/nv04_display.c      |   90 +-
- drivers/gpu/drm/nouveau/nv04_fifo.c         |   28 +-
+ drivers/gpu/drm/nouveau/nv04_fbcon.c        |    9 +-
+ drivers/gpu/drm/nouveau/nv04_fifo.c         |   88 +-
  drivers/gpu/drm/nouveau/nv04_graph.c        |    5 +-
- drivers/gpu/drm/nouveau/nv04_instmem.c      |   21 +-
+ drivers/gpu/drm/nouveau/nv04_instmem.c      |  167 +-
  drivers/gpu/drm/nouveau/nv04_mc.c           |    4 +
  drivers/gpu/drm/nouveau/nv04_tv.c           |  133 +-
- drivers/gpu/drm/nouveau/nv10_fifo.c         |   10 -
+ drivers/gpu/drm/nouveau/nv10_fifo.c         |   29 +-
  drivers/gpu/drm/nouveau/nv10_gpio.c         |   92 +
  drivers/gpu/drm/nouveau/nv10_graph.c        |  175 +-
  drivers/gpu/drm/nouveau/nv17_gpio.c         |   92 -
- drivers/gpu/drm/nouveau/nv17_tv.c           |   82 +-
- drivers/gpu/drm/nouveau/nv20_graph.c        |  564 +++---
+ drivers/gpu/drm/nouveau/nv17_tv.c           |  181 +-
+ drivers/gpu/drm/nouveau/nv17_tv.h           |   15 +-
+ drivers/gpu/drm/nouveau/nv17_tv_modes.c     |   48 +-
+ drivers/gpu/drm/nouveau/nv20_graph.c        |  576 +++---
  drivers/gpu/drm/nouveau/nv30_fb.c           |   95 +
- drivers/gpu/drm/nouveau/nv40_fifo.c         |    8 -
- drivers/gpu/drm/nouveau/nv40_graph.c        |   62 +-
+ drivers/gpu/drm/nouveau/nv40_fifo.c         |   28 +-
+ drivers/gpu/drm/nouveau/nv40_graph.c        |   72 +-
  drivers/gpu/drm/nouveau/nv40_grctx.c        |    6 +-
  drivers/gpu/drm/nouveau/nv40_mc.c           |    2 +-
  drivers/gpu/drm/nouveau/nv50_crtc.c         |   67 +-
- drivers/gpu/drm/nouveau/nv50_dac.c          |   43 +-
- drivers/gpu/drm/nouveau/nv50_display.c      |  435 +++--
+ drivers/gpu/drm/nouveau/nv50_cursor.c       |    2 +-
+ drivers/gpu/drm/nouveau/nv50_dac.c          |   47 +-
+ drivers/gpu/drm/nouveau/nv50_display.c      |  496 +++--
  drivers/gpu/drm/nouveau/nv50_display.h      |    6 +-
  drivers/gpu/drm/nouveau/nv50_fb.c           |   39 +
- drivers/gpu/drm/nouveau/nv50_fifo.c         |  335 ++--
+ drivers/gpu/drm/nouveau/nv50_fbcon.c        |    4 +-
+ drivers/gpu/drm/nouveau/nv50_fifo.c         |  396 ++--
  drivers/gpu/drm/nouveau/nv50_gpio.c         |   35 +
- drivers/gpu/drm/nouveau/nv50_graph.c        |  104 +-
+ drivers/gpu/drm/nouveau/nv50_graph.c        |  131 +-
  drivers/gpu/drm/nouveau/nv50_grctx.c        | 3305 +++++++++++++++++----------
- drivers/gpu/drm/nouveau/nv50_instmem.c      |   81 +-
- drivers/gpu/drm/nouveau/nv50_sor.c          |  105 +-
+ drivers/gpu/drm/nouveau/nv50_instmem.c      |  473 ++---
+ drivers/gpu/drm/nouveau/nv50_sor.c          |  109 +-
  drivers/gpu/drm/nouveau/nvc0_fb.c           |   38 +
- drivers/gpu/drm/nouveau/nvc0_fifo.c         |   95 +
+ drivers/gpu/drm/nouveau/nvc0_fifo.c         |   89 +
  drivers/gpu/drm/nouveau/nvc0_graph.c        |   74 +
- drivers/gpu/drm/nouveau/nvc0_instmem.c      |  234 ++
+ drivers/gpu/drm/nouveau/nvc0_instmem.c      |  229 ++
  drivers/gpu/drm/nouveau/nvreg.h             |   22 -
- 70 files changed, 6456 insertions(+), 4215 deletions(-)
+ 75 files changed, 7469 insertions(+), 5278 deletions(-)
  delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c
  create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.c
  create mode 100644 drivers/gpu/drm/nouveau/nouveau_ramht.h
@@ -2713,7 +2832,7 @@ index adf4ec2..c1de2f3 100644
  
  	struct {
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
-index 6f3c195..553a01d 100644
+index 6f3c195..22a2038 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
 @@ -43,17 +43,12 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
@@ -2754,7 +2873,19 @@ index 6f3c195..553a01d 100644
  }
  
  u16
-@@ -461,18 +454,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
+@@ -395,7 +388,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ 		man->available_caching = TTM_PL_FLAG_UNCACHED |
+ 					 TTM_PL_FLAG_WC;
+ 		man->default_caching = TTM_PL_FLAG_WC;
+-		man->gpu_offset = dev_priv->vm_vram_base;
++		if (dev_priv->card_type == NV_50)
++			man->gpu_offset = 0x40000000;
++		else
++			man->gpu_offset = 0;
+ 		break;
+ 	case TTM_PL_TT:
+ 		switch (dev_priv->gart_info.type) {
+@@ -461,18 +457,20 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
  		return ret;
  
  	ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
@@ -2781,7 +2912,7 @@ index 6f3c195..553a01d 100644
  		if (mem->mem_type == TTM_PL_TT)
  			return NvDmaGART;
  		return NvDmaVRAM;
-@@ -484,86 +479,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
+@@ -484,86 +482,181 @@ nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
  }
  
  static int
@@ -3008,7 +3139,7 @@ index 6f3c195..553a01d 100644
  	return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
  }
  
-@@ -710,13 +800,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
+@@ -710,13 +803,6 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
  	if (ret)
  		return ret;
  
@@ -3022,7 +3153,7 @@ index 6f3c195..553a01d 100644
  	/* Fake bo copy. */
  	if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
  		BUG_ON(bo->mem.mm_node != NULL);
-@@ -725,6 +808,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
+@@ -725,6 +811,12 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
  		goto out;
  	}
  
@@ -3084,10 +3215,27 @@ index 88f9bc0..23d9896 100644
  
  static int
 diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
-index 1fc57ef..9a31023 100644
+index 1fc57ef..53c2a6f 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
-@@ -257,9 +257,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
+@@ -69,14 +69,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
+ 		chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+ 	}
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
+-	if (ret) {
+-		NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret);
+-		if (pushbuf != dev_priv->gart_info.sg_ctxdma)
+-			nouveau_gpuobj_del(dev, &pushbuf);
+-		return ret;
+-	}
+-
++	nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
++	nouveau_gpuobj_ref(NULL, &pushbuf);
+ 	return 0;
+ }
+ 
+@@ -257,9 +251,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
  	nouveau_debugfs_channel_fini(chan);
  
  	/* Give outstanding push buffers a chance to complete */
@@ -3097,15 +3245,18 @@ index 1fc57ef..9a31023 100644
  	if (chan->fence.sequence != chan->fence.sequence_ack) {
  		struct nouveau_fence *fence = NULL;
  
-@@ -311,6 +309,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
+@@ -309,8 +301,9 @@ nouveau_channel_free(struct nouveau_channel *chan)
+ 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ 
  	/* Release the channel's resources */
- 	nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
+-	nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
++	nouveau_gpuobj_ref(NULL, &chan->pushbuf);
  	if (chan->pushbuf_bo) {
 +		nouveau_bo_unmap(chan->pushbuf_bo);
  		nouveau_bo_unpin(chan->pushbuf_bo);
  		nouveau_bo_ref(NULL, &chan->pushbuf_bo);
  	}
-@@ -368,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
+@@ -368,8 +361,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
  	struct nouveau_channel *chan;
  	int ret;
  
@@ -3114,7 +3265,7 @@ index 1fc57ef..9a31023 100644
  	if (dev_priv->engine.graph.accel_blocked)
  		return -ENODEV;
  
-@@ -418,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
+@@ -418,7 +409,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
  	struct drm_nouveau_channel_free *cfree = data;
  	struct nouveau_channel *chan;
  
@@ -3762,10 +3913,52 @@ index 4ef38ab..0d2e668 100644
  
  #endif /* __NOUVEAU_CONNECTOR_H__ */
 diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
-index 65c441a..2d00699 100644
+index 65c441a..9d27acd 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
-@@ -91,13 +91,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
+@@ -28,6 +28,7 @@
+ #include "drm.h"
+ #include "nouveau_drv.h"
+ #include "nouveau_dma.h"
++#include "nouveau_ramht.h"
+ 
+ void
+ nouveau_dma_pre_init(struct nouveau_channel *chan)
+@@ -58,26 +59,27 @@ nouveau_dma_init(struct nouveau_channel *chan)
+ {
+ 	struct drm_device *dev = chan->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *m2mf = NULL;
+-	struct nouveau_gpuobj *nvsw = NULL;
++	struct nouveau_gpuobj *obj = NULL;
+ 	int ret, i;
+ 
+ 	/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
+ 	ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
+-				    0x0039 : 0x5039, &m2mf);
++				    0x0039 : 0x5039, &obj);
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
++	ret = nouveau_ramht_insert(chan, NvM2MF, obj);
++	nouveau_gpuobj_ref(NULL, &obj);
+ 	if (ret)
+ 		return ret;
+ 
+ 	/* Create an NV_SW object for various sync purposes */
+-	ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
++	ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
++	ret = nouveau_ramht_insert(chan, NvSw, obj);
++	nouveau_gpuobj_ref(NULL, &obj);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -91,13 +93,6 @@ nouveau_dma_init(struct nouveau_channel *chan)
  	if (ret)
  		return ret;
  
@@ -3780,7 +3973,7 @@ index 65c441a..2d00699 100644
  	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
  	if (ret)
 diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
-index deeb21c..8a1b188 100644
+index deeb21c..89ca1f6 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
 @@ -23,8 +23,10 @@
@@ -3852,7 +4045,17 @@ index deeb21c..8a1b188 100644
  	return eq_done;
  }
  
-@@ -535,47 +572,64 @@ out:
+@@ -487,7 +524,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
+ 		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
+ 		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
+ 		nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000);
+-		if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
++		if (!nv_wait(dev, NV50_AUXCH_CTRL(index),
++			     0x00010000, 0x00000000)) {
+ 			NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
+ 				 nv_rd32(dev, NV50_AUXCH_CTRL(index)));
+ 			ret = -EBUSY;
+@@ -535,47 +573,64 @@ out:
  	return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
  }
  
@@ -3953,10 +4156,10 @@ index deeb21c..8a1b188 100644
 +	.functionality = nouveau_dp_i2c_func
 +};
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
-index 2737704..a8d3d17 100644
+index 2737704..946748a 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
-@@ -35,10 +35,6 @@
+@@ -35,13 +35,9 @@
  
  #include "drm_pciids.h"
  
@@ -3964,9 +4167,15 @@ index 2737704..a8d3d17 100644
 -int nouveau_ctxfw = 0;
 -module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
 -
- MODULE_PARM_DESC(noagp, "Disable AGP");
- int nouveau_noagp;
- module_param_named(noagp, nouveau_noagp, int, 0400);
+-MODULE_PARM_DESC(noagp, "Disable AGP");
+-int nouveau_noagp;
+-module_param_named(noagp, nouveau_noagp, int, 0400);
++MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
++int nouveau_agpmode = -1;
++module_param_named(agpmode, nouveau_agpmode, int, 0400);
+ 
+ MODULE_PARM_DESC(modeset, "Enable kernel modesetting");
+ static int nouveau_modeset = -1; /* kms */
 @@ -56,7 +52,7 @@ int nouveau_vram_pushbuf;
  module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
  
@@ -4065,7 +4274,7 @@ index 2737704..a8d3d17 100644
  	nouveau_unregister_dsm_handler();
  }
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
-index c697191..2eb622b 100644
+index c697191..228c8cd 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
 @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
@@ -4083,20 +4292,55 @@ index c697191..2eb622b 100644
  enum nouveau_flags {
  	NV_NFORCE   = 0x10000000,
  	NV_NFORCE2  = 0x20000000
-@@ -146,10 +138,11 @@ enum nouveau_flags {
+@@ -141,22 +133,24 @@ enum nouveau_flags {
+ #define NVOBJ_ENGINE_DISPLAY	2
+ #define NVOBJ_ENGINE_INT	0xdeadbeef
+ 
+-#define NVOBJ_FLAG_ALLOW_NO_REFS	(1 << 0)
+ #define NVOBJ_FLAG_ZERO_ALLOC		(1 << 1)
  #define NVOBJ_FLAG_ZERO_FREE		(1 << 2)
- #define NVOBJ_FLAG_FAKE			(1 << 3)
+-#define NVOBJ_FLAG_FAKE			(1 << 3)
  struct nouveau_gpuobj {
 +	struct drm_device *dev;
++	struct kref refcount;
  	struct list_head list;
  
- 	struct nouveau_channel *im_channel;
+-	struct nouveau_channel *im_channel;
 -	struct mem_block *im_pramin;
 +	struct drm_mm_node *im_pramin;
  	struct nouveau_bo *im_backing;
- 	uint32_t im_backing_start;
+-	uint32_t im_backing_start;
  	uint32_t *im_backing_suspend;
-@@ -196,7 +189,7 @@ struct nouveau_channel {
+ 	int im_bound;
+ 
+ 	uint32_t flags;
+-	int refcount;
++
++	u32 size;
++	u32 pinst;
++	u32 cinst;
++	u64 vinst;
+ 
+ 	uint32_t engine;
+ 	uint32_t class;
+@@ -165,16 +159,6 @@ struct nouveau_gpuobj {
+ 	void *priv;
+ };
+ 
+-struct nouveau_gpuobj_ref {
+-	struct list_head list;
+-
+-	struct nouveau_gpuobj *gpuobj;
+-	uint32_t instance;
+-
+-	struct nouveau_channel *channel;
+-	int handle;
+-};
+-
+ struct nouveau_channel {
+ 	struct drm_device *dev;
+ 	int id;
+@@ -196,37 +180,36 @@ struct nouveau_channel {
  		struct list_head pending;
  		uint32_t sequence;
  		uint32_t sequence_ack;
@@ -4105,7 +4349,12 @@ index c697191..2eb622b 100644
  	} fence;
  
  	/* DMA push buffer */
-@@ -206,7 +199,7 @@ struct nouveau_channel {
+-	struct nouveau_gpuobj_ref *pushbuf;
+-	struct nouveau_bo         *pushbuf_bo;
+-	uint32_t                   pushbuf_base;
++	struct nouveau_gpuobj *pushbuf;
++	struct nouveau_bo     *pushbuf_bo;
++	uint32_t               pushbuf_base;
  
  	/* Notifier memory */
  	struct nouveau_bo *notifier_bo;
@@ -4113,17 +4362,37 @@ index c697191..2eb622b 100644
 +	struct drm_mm notifier_heap;
  
  	/* PFIFO context */
- 	struct nouveau_gpuobj_ref *ramfc;
-@@ -224,7 +217,7 @@ struct nouveau_channel {
+-	struct nouveau_gpuobj_ref *ramfc;
+-	struct nouveau_gpuobj_ref *cache;
++	struct nouveau_gpuobj *ramfc;
++	struct nouveau_gpuobj *cache;
+ 
+ 	/* PGRAPH context */
+ 	/* XXX may be merge 2 pointers as private data ??? */
+-	struct nouveau_gpuobj_ref *ramin_grctx;
++	struct nouveau_gpuobj *ramin_grctx;
+ 	void *pgraph_ctx;
+ 
+ 	/* NV50 VM */
+-	struct nouveau_gpuobj     *vm_pd;
+-	struct nouveau_gpuobj_ref *vm_gart_pt;
+-	struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR];
++	struct nouveau_gpuobj *vm_pd;
++	struct nouveau_gpuobj *vm_gart_pt;
++	struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
  
  	/* Objects */
- 	struct nouveau_gpuobj_ref *ramin; /* Private instmem */
+-	struct nouveau_gpuobj_ref *ramin; /* Private instmem */
 -	struct mem_block          *ramin_heap; /* Private PRAMIN heap */
-+	struct drm_mm              ramin_heap; /* Private PRAMIN heap */
- 	struct nouveau_gpuobj_ref *ramht; /* Hash table */
- 	struct list_head           ramht_refs; /* Objects referenced by RAMHT */
- 
-@@ -277,8 +270,7 @@ struct nouveau_instmem_engine {
+-	struct nouveau_gpuobj_ref *ramht; /* Hash table */
+-	struct list_head           ramht_refs; /* Objects referenced by RAMHT */
++	struct nouveau_gpuobj *ramin; /* Private instmem */
++	struct drm_mm          ramin_heap; /* Private PRAMIN heap */
++	struct nouveau_ramht  *ramht; /* Hash table */
+ 
+ 	/* GPU object info for stuff used in-kernel (mm_enabled) */
+ 	uint32_t m2mf_ntfy;
+@@ -277,8 +260,7 @@ struct nouveau_instmem_engine {
  	void	(*clear)(struct drm_device *, struct nouveau_gpuobj *);
  	int	(*bind)(struct drm_device *, struct nouveau_gpuobj *);
  	int	(*unbind)(struct drm_device *, struct nouveau_gpuobj *);
@@ -4133,7 +4402,7 @@ index c697191..2eb622b 100644
  };
  
  struct nouveau_mc_engine {
-@@ -303,10 +295,11 @@ struct nouveau_fb_engine {
+@@ -303,17 +285,17 @@ struct nouveau_fb_engine {
  };
  
  struct nouveau_fifo_engine {
@@ -4141,13 +4410,20 @@ index c697191..2eb622b 100644
 -
  	int  channels;
  
-+	struct nouveau_gpuobj_ref *playlist[2];
++	struct nouveau_gpuobj *playlist[2];
 +	int cur_playlist;
 +
  	int  (*init)(struct drm_device *);
  	void (*takedown)(struct drm_device *);
  
-@@ -339,10 +332,11 @@ struct nouveau_pgraph_object_class {
+ 	void (*disable)(struct drm_device *);
+ 	void (*enable)(struct drm_device *);
+ 	bool (*reassign)(struct drm_device *, bool enable);
+-	bool (*cache_flush)(struct drm_device *dev);
+ 	bool (*cache_pull)(struct drm_device *dev, bool enable);
+ 
+ 	int  (*channel_id)(struct drm_device *);
+@@ -339,10 +321,11 @@ struct nouveau_pgraph_object_class {
  struct nouveau_pgraph_engine {
  	struct nouveau_pgraph_object_class *grclass;
  	bool accel_blocked;
@@ -4156,12 +4432,12 @@ index c697191..2eb622b 100644
  	int grctx_size;
  
 +	/* NV2x/NV3x context table (0x400780) */
-+	struct nouveau_gpuobj_ref *ctx_table;
++	struct nouveau_gpuobj *ctx_table;
 +
  	int  (*init)(struct drm_device *);
  	void (*takedown)(struct drm_device *);
  
-@@ -358,6 +352,24 @@ struct nouveau_pgraph_engine {
+@@ -358,6 +341,24 @@ struct nouveau_pgraph_engine {
  				  uint32_t size, uint32_t pitch);
  };
  
@@ -4186,7 +4462,7 @@ index c697191..2eb622b 100644
  struct nouveau_engine {
  	struct nouveau_instmem_engine instmem;
  	struct nouveau_mc_engine      mc;
-@@ -365,6 +377,8 @@ struct nouveau_engine {
+@@ -365,6 +366,8 @@ struct nouveau_engine {
  	struct nouveau_fb_engine      fb;
  	struct nouveau_pgraph_engine  graph;
  	struct nouveau_fifo_engine    fifo;
@@ -4195,7 +4471,7 @@ index c697191..2eb622b 100644
  };
  
  struct nouveau_pll_vals {
-@@ -397,7 +411,7 @@ enum nv04_fp_display_regs {
+@@ -397,7 +400,7 @@ enum nv04_fp_display_regs {
  
  struct nv04_crtc_reg {
  	unsigned char MiscOutReg;     /* */
@@ -4204,7 +4480,7 @@ index c697191..2eb622b 100644
  	uint8_t CR58[0x10];
  	uint8_t Sequencer[5];
  	uint8_t Graphics[9];
-@@ -496,15 +510,11 @@ enum nouveau_card_type {
+@@ -496,15 +499,11 @@ enum nouveau_card_type {
  	NV_30      = 0x30,
  	NV_40      = 0x40,
  	NV_50      = 0x50,
@@ -4221,7 +4497,23 @@ index c697191..2eb622b 100644
  
  	/* the card type, takes NV_* as values */
  	enum nouveau_card_type card_type;
-@@ -528,13 +538,9 @@ struct drm_nouveau_private {
+@@ -513,8 +512,14 @@ struct drm_nouveau_private {
+ 	int flags;
+ 
+ 	void __iomem *mmio;
++
++	spinlock_t ramin_lock;
+ 	void __iomem *ramin;
+-	uint32_t ramin_size;
++	u32 ramin_size;
++	u32 ramin_base;
++	bool ramin_available;
++	struct drm_mm ramin_heap;
++	struct list_head gpuobj_list;
+ 
+ 	struct nouveau_bo *vga_ram;
+ 
+@@ -528,13 +533,9 @@ struct drm_nouveau_private {
  		struct ttm_global_reference mem_global_ref;
  		struct ttm_bo_global_ref bo_global_ref;
  		struct ttm_bo_device bdev;
@@ -4235,7 +4527,36 @@ index c697191..2eb622b 100644
  	int fifo_alloc_count;
  	struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
  
-@@ -579,6 +585,7 @@ struct drm_nouveau_private {
+@@ -545,15 +546,11 @@ struct drm_nouveau_private {
+ 	spinlock_t context_switch_lock;
+ 
+ 	/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
+-	struct nouveau_gpuobj *ramht;
++	struct nouveau_ramht  *ramht;
++	struct nouveau_gpuobj *ramfc;
++	struct nouveau_gpuobj *ramro;
++
+ 	uint32_t ramin_rsvd_vram;
+-	uint32_t ramht_offset;
+-	uint32_t ramht_size;
+-	uint32_t ramht_bits;
+-	uint32_t ramfc_offset;
+-	uint32_t ramfc_size;
+-	uint32_t ramro_offset;
+-	uint32_t ramro_size;
+ 
+ 	struct {
+ 		enum {
+@@ -571,14 +568,12 @@ struct drm_nouveau_private {
+ 	} gart_info;
+ 
+ 	/* nv10-nv40 tiling regions */
+-	struct {
+-		struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
+-		spinlock_t lock;
+-	} tile;
++	struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR];
+ 
  	/* VRAM/fb configuration */
  	uint64_t vram_size;
  	uint64_t vram_sys_base;
@@ -4243,7 +4564,7 @@ index c697191..2eb622b 100644
  
  	uint64_t fb_phys;
  	uint64_t fb_available_size;
-@@ -595,11 +602,7 @@ struct drm_nouveau_private {
+@@ -595,14 +590,6 @@ struct drm_nouveau_private {
  	struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
  	int vm_vram_pt_nr;
  
@@ -4252,11 +4573,13 @@ index c697191..2eb622b 100644
 -	/* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
 -	uint32_t ctx_table_size;
 -	struct nouveau_gpuobj_ref *ctx_table;
-+	struct drm_mm ramin_heap;
- 
- 	struct list_head gpuobj_list;
+-
+-	struct list_head gpuobj_list;
+-
+ 	struct nvbios vbios;
  
-@@ -618,6 +621,11 @@ struct drm_nouveau_private {
+ 	struct nv04_mode_state mode_reg;
+@@ -618,6 +605,11 @@ struct drm_nouveau_private {
  	struct backlight_device *backlight;
  
  	struct nouveau_channel *evo;
@@ -4268,7 +4591,7 @@ index c697191..2eb622b 100644
  
  	struct {
  		struct dentry *channel_root;
-@@ -652,14 +660,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
+@@ -652,14 +644,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
  	return 0;
  }
  
@@ -4283,7 +4606,16 @@ index c697191..2eb622b 100644
  #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do {    \
  	struct drm_nouveau_private *nv = dev->dev_private;       \
  	if (!nouveau_channel_owner(dev, (cl), (id))) {           \
-@@ -682,7 +682,6 @@ extern int nouveau_tv_disable;
+@@ -671,7 +655,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
+ } while (0)
+ 
+ /* nouveau_drv.c */
+-extern int nouveau_noagp;
++extern int nouveau_agpmode;
+ extern int nouveau_duallink;
+ extern int nouveau_uscript_lvds;
+ extern int nouveau_uscript_tmds;
+@@ -682,7 +666,6 @@ extern int nouveau_tv_disable;
  extern char *nouveau_tv_norm;
  extern int nouveau_reg_debug;
  extern char *nouveau_vbios;
@@ -4291,7 +4623,7 @@ index c697191..2eb622b 100644
  extern int nouveau_ignorelid;
  extern int nouveau_nofbaccel;
  extern int nouveau_noaccel;
-@@ -707,17 +706,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
+@@ -707,17 +690,12 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
  extern int  nouveau_card_init(struct drm_device *);
  
  /* nouveau_mem.c */
@@ -4302,15 +4634,57 @@ index c697191..2eb622b 100644
 -						 struct drm_file *, int tail);
 -extern void nouveau_mem_takedown(struct mem_block **heap);
 -extern void nouveau_mem_free_block(struct mem_block *);
- extern int  nouveau_mem_detect(struct drm_device *dev);
+-extern int  nouveau_mem_detect(struct drm_device *dev);
 -extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
- extern int  nouveau_mem_init(struct drm_device *);
+-extern int  nouveau_mem_init(struct drm_device *);
++extern int  nouveau_mem_vram_init(struct drm_device *);
++extern void nouveau_mem_vram_fini(struct drm_device *);
++extern int  nouveau_mem_gart_init(struct drm_device *);
++extern void nouveau_mem_gart_fini(struct drm_device *);
  extern int  nouveau_mem_init_agp(struct drm_device *);
 +extern int  nouveau_mem_reset_agp(struct drm_device *);
  extern void nouveau_mem_close(struct drm_device *);
  extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
  						    uint32_t addr,
-@@ -857,11 +849,13 @@ void nouveau_register_dsm_handler(void);
+@@ -759,7 +737,6 @@ extern void nouveau_channel_free(struct nouveau_channel *);
+ extern int  nouveau_gpuobj_early_init(struct drm_device *);
+ extern int  nouveau_gpuobj_init(struct drm_device *);
+ extern void nouveau_gpuobj_takedown(struct drm_device *);
+-extern void nouveau_gpuobj_late_takedown(struct drm_device *);
+ extern int  nouveau_gpuobj_suspend(struct drm_device *dev);
+ extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev);
+ extern void nouveau_gpuobj_resume(struct drm_device *dev);
+@@ -769,24 +746,11 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
+ extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *,
+ 			      uint32_t size, int align, uint32_t flags,
+ 			      struct nouveau_gpuobj **);
+-extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **);
+-extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
+-				  uint32_t handle, struct nouveau_gpuobj *,
+-				  struct nouveau_gpuobj_ref **);
+-extern int nouveau_gpuobj_ref_del(struct drm_device *,
+-				  struct nouveau_gpuobj_ref **);
+-extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
+-				   struct nouveau_gpuobj_ref **ref_ret);
+-extern int nouveau_gpuobj_new_ref(struct drm_device *,
+-				  struct nouveau_channel *alloc_chan,
+-				  struct nouveau_channel *ref_chan,
+-				  uint32_t handle, uint32_t size, int align,
+-				  uint32_t flags, struct nouveau_gpuobj_ref **);
+-extern int nouveau_gpuobj_new_fake(struct drm_device *,
+-				   uint32_t p_offset, uint32_t b_offset,
+-				   uint32_t size, uint32_t flags,
+-				   struct nouveau_gpuobj **,
+-				   struct nouveau_gpuobj_ref**);
++extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *,
++			       struct nouveau_gpuobj **);
++extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
++				   u32 size, u32 flags,
++				   struct nouveau_gpuobj **);
+ extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
+ 				  uint64_t offset, uint64_t size, int access,
+ 				  int target, struct nouveau_gpuobj **);
+@@ -857,11 +821,13 @@ void nouveau_register_dsm_handler(void);
  void nouveau_unregister_dsm_handler(void);
  int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
  bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
@@ -4324,7 +4698,7 @@ index c697191..2eb622b 100644
  #endif
  
  /* nouveau_backlight.c */
-@@ -924,15 +918,23 @@ extern void nv10_fb_takedown(struct drm_device *);
+@@ -924,22 +890,29 @@ extern void nv10_fb_takedown(struct drm_device *);
  extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
  				      uint32_t, uint32_t);
  
@@ -4349,7 +4723,14 @@ index c697191..2eb622b 100644
  
  /* nv04_fifo.c */
  extern int  nv04_fifo_init(struct drm_device *);
-@@ -971,6 +973,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
+ extern void nv04_fifo_disable(struct drm_device *);
+ extern void nv04_fifo_enable(struct drm_device *);
+ extern bool nv04_fifo_reassign(struct drm_device *, bool);
+-extern bool nv04_fifo_cache_flush(struct drm_device *);
+ extern bool nv04_fifo_cache_pull(struct drm_device *, bool);
+ extern int  nv04_fifo_channel_id(struct drm_device *);
+ extern int  nv04_fifo_create_context(struct nouveau_channel *);
+@@ -971,6 +944,19 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
  extern int  nv50_fifo_load_context(struct nouveau_channel *);
  extern int  nv50_fifo_unload_context(struct drm_device *);
  
@@ -4359,7 +4740,6 @@ index c697191..2eb622b 100644
 +extern void nvc0_fifo_disable(struct drm_device *);
 +extern void nvc0_fifo_enable(struct drm_device *);
 +extern bool nvc0_fifo_reassign(struct drm_device *, bool);
-+extern bool nvc0_fifo_cache_flush(struct drm_device *);
 +extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
 +extern int  nvc0_fifo_channel_id(struct drm_device *);
 +extern int  nvc0_fifo_create_context(struct nouveau_channel *);
@@ -4370,7 +4750,7 @@ index c697191..2eb622b 100644
  /* nv04_graph.c */
  extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
  extern int  nv04_graph_init(struct drm_device *);
-@@ -1035,11 +1051,15 @@ extern int  nv50_graph_unload_context(struct drm_device *);
+@@ -1035,11 +1021,15 @@ extern int  nv50_graph_unload_context(struct drm_device *);
  extern void nv50_graph_context_switch(struct drm_device *);
  extern int  nv50_grctx_init(struct nouveau_grctx *);
  
@@ -4391,7 +4771,7 @@ index c697191..2eb622b 100644
  
  /* nv04_instmem.c */
  extern int  nv04_instmem_init(struct drm_device *);
-@@ -1051,8 +1071,7 @@ extern int  nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+@@ -1051,8 +1041,7 @@ extern int  nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
  extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
  extern int  nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
  extern int  nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
@@ -4401,7 +4781,7 @@ index c697191..2eb622b 100644
  
  /* nv50_instmem.c */
  extern int  nv50_instmem_init(struct drm_device *);
-@@ -1064,8 +1083,21 @@ extern int  nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+@@ -1064,8 +1053,21 @@ extern int  nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
  extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
  extern int  nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
  extern int  nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
@@ -4425,7 +4805,7 @@ index c697191..2eb622b 100644
  
  /* nv04_mc.c */
  extern int  nv04_mc_init(struct drm_device *);
-@@ -1088,13 +1120,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
+@@ -1088,13 +1090,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
  				 unsigned long arg);
  
  /* nv04_dac.c */
@@ -4442,7 +4822,7 @@ index c697191..2eb622b 100644
  extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent);
  extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
  			       int head, bool dl);
-@@ -1103,15 +1136,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
+@@ -1103,15 +1106,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
  
  /* nv04_tv.c */
  extern int nv04_tv_identify(struct drm_device *dev, int i2c_index);
@@ -4463,7 +4843,7 @@ index c697191..2eb622b 100644
  
  /* nv04_crtc.c */
  extern int nv04_crtc_create(struct drm_device *, int index);
-@@ -1147,7 +1182,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+@@ -1147,7 +1152,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
  extern int nouveau_fence_flush(void *obj, void *arg);
  extern void nouveau_fence_unref(void **obj);
  extern void *nouveau_fence_ref(void *obj);
@@ -4471,7 +4851,7 @@ index c697191..2eb622b 100644
  
  /* nouveau_gem.c */
  extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
-@@ -1167,13 +1201,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
+@@ -1167,13 +1171,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
  extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
  				  struct drm_file *);
  
@@ -4490,7 +4870,7 @@ index c697191..2eb622b 100644
  
  /* nv50_calc. */
  int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
-@@ -1220,6 +1256,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
+@@ -1220,6 +1226,13 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
  	iowrite32_native(val, dev_priv->mmio + reg);
  }
  
@@ -4504,7 +4884,16 @@ index c697191..2eb622b 100644
  static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
-@@ -1249,17 +1292,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val)
+@@ -1232,7 +1245,7 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val)
+ 	iowrite8(val, dev_priv->mmio + reg);
+ }
+ 
+-#define nv_wait(reg, mask, val) \
++#define nv_wait(dev, reg, mask, val) \
+ 	nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val))
+ 
+ /* PRAMIN access */
+@@ -1249,17 +1262,8 @@ static inline void nv_wi32(struct drm_device *dev, unsigned offset, u32 val)
  }
  
  /* object access */
@@ -4524,7 +4913,7 @@ index c697191..2eb622b 100644
  
  /*
   * Logging
-@@ -1346,6 +1380,15 @@ nv_two_reg_pll(struct drm_device *dev)
+@@ -1346,6 +1350,15 @@ nv_two_reg_pll(struct drm_device *dev)
  	return false;
  }
  
@@ -5157,10 +5546,18 @@ index c8eaf7a..f71cb32 100644
  
  #endif /* __NOUVEAU_I2C_H__ */
 diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
-index 53360f1..b8658a0 100644
+index 53360f1..6fd51a5 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
-@@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
+@@ -35,6 +35,7 @@
+ #include "nouveau_drm.h"
+ #include "nouveau_drv.h"
+ #include "nouveau_reg.h"
++#include "nouveau_ramht.h"
+ #include <linux/ratelimit.h>
+ 
+ /* needed for hotplug irq */
+@@ -49,7 +50,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
  	/* Master disable */
  	nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
  
@@ -5169,7 +5566,82 @@ index 53360f1..b8658a0 100644
  		INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
  		INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
  		INIT_LIST_HEAD(&dev_priv->vbl_waiting);
-@@ -226,6 +226,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
+@@ -106,15 +107,16 @@ nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
+ 	const int mthd = addr & 0x1ffc;
+ 
+ 	if (mthd == 0x0000) {
+-		struct nouveau_gpuobj_ref *ref = NULL;
++		struct nouveau_gpuobj *gpuobj;
+ 
+-		if (nouveau_gpuobj_ref_find(chan, data, &ref))
++		gpuobj = nouveau_ramht_find(chan, data);
++		if (!gpuobj)
+ 			return false;
+ 
+-		if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
++		if (gpuobj->engine != NVOBJ_ENGINE_SW)
+ 			return false;
+ 
+-		chan->sw_subchannel[subc] = ref->gpuobj->class;
++		chan->sw_subchannel[subc] = gpuobj->class;
+ 		nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
+ 			NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
+ 		return true;
+@@ -200,16 +202,45 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
+ 		}
+ 
+ 		if (status & NV_PFIFO_INTR_DMA_PUSHER) {
+-			NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid);
++			u32 get = nv_rd32(dev, 0x003244);
++			u32 put = nv_rd32(dev, 0x003240);
++			u32 push = nv_rd32(dev, 0x003220);
++			u32 state = nv_rd32(dev, 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);
++
++				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 Push 0x%08x\n",
++					chid, ho_get, get, ho_put, put, ib_get, ib_put,
++					state, push);
++
++				/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
++				nv_wr32(dev, 0x003364, 0x00000000);
++				if (get != put || ho_get != ho_put) {
++					nv_wr32(dev, 0x003244, put);
++					nv_wr32(dev, 0x003328, ho_put);
++				} else
++				if (ib_get != ib_put) {
++					nv_wr32(dev, 0x003334, ib_put);
++				}
++			} else {
++				NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
++					     "Put 0x%08x State 0x%08x Push 0x%08x\n",
++					chid, get, put, state, push);
+ 
+-			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
+-			nv_wr32(dev, NV03_PFIFO_INTR_0,
+-						NV_PFIFO_INTR_DMA_PUSHER);
++				if (get != put)
++					nv_wr32(dev, 0x003244, put);
++			}
+ 
+-			nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
+-			if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get)
+-				nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET,
+-								get + 4);
++			nv_wr32(dev, 0x003228, 0x00000000);
++			nv_wr32(dev, 0x003220, 0x00000001);
++			nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
++			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
+ 		}
+ 
+ 		if (status & NV_PFIFO_INTR_SEMAPHORE) {
+@@ -226,6 +257,14 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
  			nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
  		}
  
@@ -5184,7 +5656,25 @@ index 53360f1..b8658a0 100644
  		if (status) {
  			NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
  				status, chid);
-@@ -586,11 +594,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
+@@ -357,7 +396,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
+ 			if (!chan || !chan->ramin_grctx)
+ 				continue;
+ 
+-			if (inst == chan->ramin_grctx->instance)
++			if (inst == chan->ramin_grctx->pinst)
+ 				break;
+ 		}
+ 	} else {
+@@ -369,7 +408,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
+ 			if (!chan || !chan->ramin)
+ 				continue;
+ 
+-			if (inst == chan->ramin->instance)
++			if (inst == chan->ramin->vinst)
+ 				break;
+ 		}
+ 	}
+@@ -586,11 +625,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
  		}
  
  		if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
@@ -5198,7 +5688,7 @@ index 53360f1..b8658a0 100644
  		}
  
  		if (status) {
-@@ -605,40 +613,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
+@@ -605,40 +644,6 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
  	nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
  }
  
@@ -5239,7 +5729,7 @@ index 53360f1..b8658a0 100644
  static struct nouveau_enum_names nv50_mp_exec_error_names[] =
  {
  	{ 3, "STACK_UNDERFLOW" },
-@@ -711,7 +685,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
+@@ -711,7 +716,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
  		tps++;
  		switch (type) {
  		case 6: /* texture error... unknown for now */
@@ -5248,7 +5738,7 @@ index 53360f1..b8658a0 100644
  			if (display) {
  				NV_ERROR(dev, "magic set %d:\n", i);
  				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
-@@ -734,7 +708,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
+@@ -734,7 +739,7 @@ nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
  			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);
@@ -5257,7 +5747,7 @@ index 53360f1..b8658a0 100644
  			/* 2d engine destination */
  			if (ustatus & 0x00000010) {
  				if (display) {
-@@ -817,7 +791,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -817,7 +822,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  
  		/* Known to be triggered by screwed up NOTIFY and COND... */
  		if (ustatus & 0x00000001) {
@@ -5266,7 +5756,7 @@ index 53360f1..b8658a0 100644
  			nv_wr32(dev, 0x400500, 0);
  			if (nv_rd32(dev, 0x400808) & 0x80000000) {
  				if (display) {
-@@ -842,7 +816,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -842,7 +847,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  			ustatus &= ~0x00000001;
  		}
  		if (ustatus & 0x00000002) {
@@ -5275,7 +5765,7 @@ index 53360f1..b8658a0 100644
  			nv_wr32(dev, 0x400500, 0);
  			if (nv_rd32(dev, 0x40084c) & 0x80000000) {
  				if (display) {
-@@ -884,15 +858,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -884,15 +889,15 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  			NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
  		}
  		if (ustatus & 0x00000001) {
@@ -5294,7 +5784,7 @@ index 53360f1..b8658a0 100644
  			ustatus &= ~0x00000004;
  		}
  		NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
-@@ -917,7 +891,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -917,7 +922,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  			NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
  		}
  		if (ustatus & 0x00000001) {
@@ -5303,7 +5793,7 @@ index 53360f1..b8658a0 100644
  			NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
  					nv_rd32(dev, 0x400c00),
  					nv_rd32(dev, 0x400c08),
-@@ -939,7 +913,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -939,7 +944,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  			NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
  		}
  		if (ustatus & 0x00000001) {
@@ -5312,7 +5802,7 @@ index 53360f1..b8658a0 100644
  			NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
  					nv_rd32(dev, 0x401804),
  					nv_rd32(dev, 0x401808),
-@@ -964,7 +938,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -964,7 +969,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  			NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
  		}
  		if (ustatus & 0x00000001) {
@@ -5321,7 +5811,7 @@ index 53360f1..b8658a0 100644
  			NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
  					nv_rd32(dev, 0x405800),
  					nv_rd32(dev, 0x405804),
-@@ -986,7 +960,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
+@@ -986,7 +991,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev)
  	 * remaining, so try to handle it anyway. Perhaps related to that
  	 * unknown DMA slot on tesla? */
  	if (status & 0x20) {
@@ -5331,7 +5821,7 @@ index 53360f1..b8658a0 100644
  		if (display)
  			NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
-index c1fd42b..ee799c2 100644
+index c1fd42b..4f0ae39 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
 @@ -35,162 +35,6 @@
@@ -5497,7 +5987,74 @@ index c1fd42b..ee799c2 100644
  /*
   * NV10-NV40 tiling helpers
   */
-@@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
+@@ -203,18 +47,14 @@ nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+ 	struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+-	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
++	struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+ 
+ 	tile->addr = addr;
+ 	tile->size = size;
+ 	tile->used = !!pitch;
+ 	nouveau_fence_unref((void **)&tile->fence);
+ 
+-	if (!pfifo->cache_flush(dev))
+-		return;
+-
+ 	pfifo->reassign(dev, false);
+-	pfifo->cache_flush(dev);
+ 	pfifo->cache_pull(dev, false);
+ 
+ 	nouveau_wait_for_idle(dev);
+@@ -232,34 +72,36 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+-	struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL;
+-	int i;
++	struct nouveau_tile_reg *found = NULL;
++	unsigned long i, flags;
+ 
+-	spin_lock(&dev_priv->tile.lock);
++	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ 
+ 	for (i = 0; i < pfb->num_tiles; i++) {
+-		if (tile[i].used)
++		struct nouveau_tile_reg *tile = &dev_priv->tile[i];
++
++		if (tile->used)
+ 			/* Tile region in use. */
+ 			continue;
+ 
+-		if (tile[i].fence &&
+-		    !nouveau_fence_signalled(tile[i].fence, NULL))
++		if (tile->fence &&
++		    !nouveau_fence_signalled(tile->fence, NULL))
+ 			/* Pending tile region. */
+ 			continue;
+ 
+-		if (max(tile[i].addr, addr) <
+-		    min(tile[i].addr + tile[i].size, addr + size))
++		if (max(tile->addr, addr) <
++		    min(tile->addr + tile->size, addr + size))
+ 			/* Kill an intersecting tile region. */
+ 			nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
+ 
+ 		if (pitch && !found) {
+ 			/* Free tile region. */
+ 			nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
+-			found = &tile[i];
++			found = tile;
+ 		}
+ 	}
+ 
+-	spin_unlock(&dev_priv->tile.lock);
++	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ 
+ 	return found;
+ }
+@@ -299,7 +141,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
  		phys |= 0x30;
  	}
  
@@ -5505,7 +6062,7 @@ index c1fd42b..ee799c2 100644
  	while (size) {
  		unsigned offset_h = upper_32_bits(phys);
  		unsigned offset_l = lower_32_bits(phys);
-@@ -326,41 +169,18 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
+@@ -326,41 +167,18 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
  			virt  += (end - pte);
  
  			while (pte < end) {
@@ -5555,7 +6112,7 @@ index c1fd42b..ee799c2 100644
  	return 0;
  }
  
-@@ -374,7 +194,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
+@@ -374,7 +192,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
  	virt -= dev_priv->vm_vram_base;
  	pages = (size >> 16) << 1;
  
@@ -5563,7 +6120,7 @@ index c1fd42b..ee799c2 100644
  	while (pages) {
  		pgt = dev_priv->vm_vram_pt[virt >> 29];
  		pte = (virt & 0x1ffe0000ULL) >> 15;
-@@ -385,60 +204,24 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
+@@ -385,60 +202,24 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
  		pages -= (end - pte);
  		virt  += (end - pte) << 15;
  
@@ -5631,31 +6188,43 @@ index c1fd42b..ee799c2 100644
 -
 -void nouveau_mem_close(struct drm_device *dev)
 +void
-+nouveau_mem_close(struct drm_device *dev)
++nouveau_mem_vram_fini(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  
-@@ -449,8 +232,7 @@ void nouveau_mem_close(struct drm_device *dev)
+@@ -449,8 +230,20 @@ void nouveau_mem_close(struct drm_device *dev)
  
  	nouveau_ttm_global_release(dev_priv);
  
 -	if (drm_core_has_AGP(dev) && dev->agp &&
 -	    drm_core_check_feature(dev, DRIVER_MODESET)) {
++	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);
++
 +	if (drm_core_has_AGP(dev) && dev->agp) {
  		struct drm_agp_mem *entry, *tempe;
  
  		/* Remove AGP resources, but leave dev->agp
-@@ -470,29 +252,29 @@ void nouveau_mem_close(struct drm_device *dev)
+@@ -469,30 +262,24 @@ void nouveau_mem_close(struct drm_device *dev)
+ 		dev->agp->acquired = 0;
  		dev->agp->enabled = 0;
  	}
- 
+-
 -	if (dev_priv->fb_mtrr) {
-+	if (dev_priv->fb_mtrr >= 0) {
- 		drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),
- 			     drm_get_resource_len(dev, 1), DRM_MTRR_WC);
+-		drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),
+-			     drm_get_resource_len(dev, 1), DRM_MTRR_WC);
 -		dev_priv->fb_mtrr = 0;
-+		dev_priv->fb_mtrr = -1;
- 	}
+-	}
  }
  
  static uint32_t
@@ -5683,11 +6252,12 @@ index c1fd42b..ee799c2 100644
  		return 4 * 1024 * 1024;
  	}
  
-@@ -525,7 +307,61 @@ nouveau_mem_detect_nforce(struct drm_device *dev)
+@@ -525,8 +312,62 @@ nouveau_mem_detect_nforce(struct drm_device *dev)
  	return 0;
  }
  
 -/* returns the amount of FB ram in bytes */
+-int
 +static void
 +nv50_vram_preinit(struct drm_device *dev)
 +{
@@ -5743,10 +6313,11 @@ index c1fd42b..ee799c2 100644
 +	dev_priv->vram_rblock_size = 1;
 +}
 +
- int
++static int
  nouveau_mem_detect(struct drm_device *dev)
  {
-@@ -536,12 +372,31 @@ nouveau_mem_detect(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+@@ -536,12 +377,31 @@ nouveau_mem_detect(struct drm_device *dev)
  	} else
  	if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
  		dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
@@ -5782,16 +6353,41 @@ index c1fd42b..ee799c2 100644
  	}
  
  	NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
-@@ -555,18 +410,37 @@ nouveau_mem_detect(struct drm_device *dev)
- 	return -ENOMEM;
+@@ -556,17 +416,63 @@ nouveau_mem_detect(struct drm_device *dev)
  }
  
--#if __OS_HAS_AGP
+ #if __OS_HAS_AGP
 -static void nouveau_mem_reset_agp(struct drm_device *dev)
-+int
-+nouveau_mem_reset_agp(struct drm_device *dev)
++static unsigned long
++get_agp_mode(struct drm_device *dev, unsigned long mode)
  {
 -	uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	/*
++	 * FW seems to be broken on nv18, it makes the card lock up
++	 * randomly.
++	 */
++	if (dev_priv->chipset == 0x18)
++		mode &= ~PCI_AGP_COMMAND_FW;
++
++	/*
++	 * AGP mode set in the command line.
++	 */
++	if (nouveau_agpmode > 0) {
++		bool agpv3 = mode & 0x8;
++		int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
++
++		mode = (mode & ~0x7) | (rate & 0x7);
++	}
++
++	return mode;
++}
++#endif
++
++int
++nouveau_mem_reset_agp(struct drm_device *dev)
++{
 +#if __OS_HAS_AGP
 +	uint32_t saved_pci_nv_1, pmc_enable;
 +	int ret;
@@ -5808,7 +6404,7 @@ index c1fd42b..ee799c2 100644
 +		if (ret)
 +			return ret;
 +
-+		mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
++		mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW;
 +		ret = drm_agp_enable(dev, mode);
 +		if (ret)
 +			return ret;
@@ -5826,7 +6422,7 @@ index c1fd42b..ee799c2 100644
  
  	/* power cycle pgraph, if enabled */
  	pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
-@@ -578,11 +452,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
+@@ -578,11 +484,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
  	}
  
  	/* and restore (gives effect of resetting AGP) */
@@ -5841,7 +6437,7 @@ index c1fd42b..ee799c2 100644
  int
  nouveau_mem_init_agp(struct drm_device *dev)
  {
-@@ -592,11 +467,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
+@@ -592,11 +499,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
  	struct drm_agp_mode mode;
  	int ret;
  
@@ -5853,7 +6449,7 @@ index c1fd42b..ee799c2 100644
  	if (!dev->agp->acquired) {
  		ret = drm_agp_acquire(dev);
  		if (ret) {
-@@ -605,6 +475,8 @@ nouveau_mem_init_agp(struct drm_device *dev)
+@@ -605,6 +507,8 @@ nouveau_mem_init_agp(struct drm_device *dev)
  		}
  	}
  
@@ -5862,38 +6458,139 @@ index c1fd42b..ee799c2 100644
  	ret = drm_agp_info(dev, &info);
  	if (ret) {
  		NV_ERROR(dev, "Unable to get AGP info: %d\n", ret);
-@@ -659,8 +531,6 @@ nouveau_mem_init(struct drm_device *dev)
- 		return ret;
+@@ -612,7 +516,7 @@ nouveau_mem_init_agp(struct drm_device *dev)
  	}
  
--	INIT_LIST_HEAD(&dev_priv->ttm.bo_list);
--	spin_lock_init(&dev_priv->ttm.bo_list_lock);
- 	spin_lock_init(&dev_priv->tile.lock);
+ 	/* see agp.h for the AGPSTAT_* modes available */
+-	mode.mode = info.mode;
++	mode.mode = get_agp_mode(dev, info.mode);
+ 	ret = drm_agp_enable(dev, mode);
+ 	if (ret) {
+ 		NV_ERROR(dev, "Unable to enable AGP: %d\n", ret);
+@@ -627,24 +531,27 @@ nouveau_mem_init_agp(struct drm_device *dev)
+ }
  
- 	dev_priv->fb_available_size = dev_priv->vram_size;
-@@ -692,7 +562,7 @@ nouveau_mem_init(struct drm_device *dev)
+ int
+-nouveau_mem_init(struct drm_device *dev)
++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 = 32;
+-
+-	dev_priv->fb_phys = drm_get_resource_start(dev, 1);
+-	dev_priv->gart_info.type = NOUVEAU_GART_NONE;
++	int ret, dma_bits;
  
- 	/* GART */
- #if !defined(__powerpc__) && !defined(__ia64__)
--	if (drm_device_is_agp(dev) && dev->agp) {
-+	if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
- 		ret = nouveau_mem_init_agp(dev);
- 		if (ret)
- 			NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
-diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
-index 9537f3e..3ec181f 100644
---- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
-@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
- 	if (ret)
- 		goto out_err;
+ 	if (dev_priv->card_type >= NV_50 &&
+ 	    pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
+ 		dma_bits = 40;
++	else
++		dma_bits = 32;
  
--	ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
-+	ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
+ 	ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
+-	if (ret) {
+-		NV_ERROR(dev, "Error setting DMA mask: %d\n", ret);
++	if (ret)
+ 		return ret;
+-	}
++
++	ret = nouveau_mem_detect(dev);
++	if (ret)
++		return ret;
++
++	dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
+ 
+ 	ret = nouveau_ttm_global_init(dev_priv);
+ 	if (ret)
+@@ -659,17 +566,22 @@ nouveau_mem_init(struct drm_device *dev)
+ 		return ret;
+ 	}
+ 
+-	INIT_LIST_HEAD(&dev_priv->ttm.bo_list);
+-	spin_lock_init(&dev_priv->ttm.bo_list_lock);
+-	spin_lock_init(&dev_priv->tile.lock);
+-
+ 	dev_priv->fb_available_size = dev_priv->vram_size;
+ 	dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
+ 	if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1))
+ 		dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1);
+ 	dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
+ 
+-	/* remove reserved space at end of vram from available amount */
++	/* reserve space at end of VRAM for PRAMIN */
++	if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 ||
++	    dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b)
++		dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
++	else
++	if (dev_priv->card_type >= NV_40)
++		dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
++	else
++		dev_priv->ramin_rsvd_vram = (512 * 1024);
++
+ 	dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
+ 	dev_priv->fb_aper_free = dev_priv->fb_available_size;
+ 
+@@ -690,9 +602,23 @@ nouveau_mem_init(struct drm_device *dev)
+ 		nouveau_bo_ref(NULL, &dev_priv->vga_ram);
+ 	}
+ 
+-	/* GART */
++	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;
++
++	dev_priv->gart_info.type = NOUVEAU_GART_NONE;
++
+ #if !defined(__powerpc__) && !defined(__ia64__)
+-	if (drm_device_is_agp(dev) && dev->agp) {
++	if (drm_device_is_agp(dev) && dev->agp && nouveau_agpmode) {
+ 		ret = nouveau_mem_init_agp(dev);
+ 		if (ret)
+ 			NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
+@@ -718,11 +644,6 @@ nouveau_mem_init(struct drm_device *dev)
+ 		return ret;
+ 	}
+ 
+-	dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
+-					 drm_get_resource_len(dev, 1),
+-					 DRM_MTRR_WC);
+-
+ 	return 0;
+ }
+ 
+-
+diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
+index 9537f3e..22b8618 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
++++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
+@@ -28,6 +28,7 @@
+ #include "drmP.h"
+ #include "drm.h"
+ #include "nouveau_drv.h"
++#include "nouveau_ramht.h"
+ 
+ int
+ nouveau_notifier_init_channel(struct nouveau_channel *chan)
+@@ -55,7 +56,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
  	if (ret)
  		goto out_err;
  
-@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
+-	ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
++	ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
+ 	if (ret)
+ 		goto out_err;
+ 
+@@ -80,7 +81,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
  	nouveau_bo_unpin(chan->notifier_bo);
  	mutex_unlock(&dev->struct_mutex);
  	drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
@@ -5902,7 +6599,7 @@ index 9537f3e..3ec181f 100644
  }
  
  static void
-@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
+@@ -90,7 +91,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
  	NV_DEBUG(dev, "\n");
  
  	if (gpuobj->priv)
@@ -5911,7 +6608,7 @@ index 9537f3e..3ec181f 100644
  }
  
  int
-@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
+@@ -100,18 +101,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_gpuobj *nobj = NULL;
@@ -5934,7 +6631,7 @@ index 9537f3e..3ec181f 100644
  	if (!mem) {
  		NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
  		return -ENOMEM;
-@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
+@@ -144,18 +140,18 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
  				     mem->size, NV_DMA_ACCESS_RW, target,
  				     &nobj);
  	if (ret) {
@@ -5948,15 +6645,19 @@ index 9537f3e..3ec181f 100644
 +	nobj->dtor = nouveau_notifier_gpuobj_dtor;
 +	nobj->priv = mem;
  
- 	ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
+-	ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
++	ret = nouveau_ramht_insert(chan, handle, nobj);
++	nouveau_gpuobj_ref(NULL, &nobj);
  	if (ret) {
- 		nouveau_gpuobj_del(dev, &nobj);
+-		nouveau_gpuobj_del(dev, &nobj);
 -		nouveau_mem_free_block(mem);
+-		NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
 +		drm_mm_put_block(mem);
- 		NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
++		NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
  		return ret;
  	}
-@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
+ 
+@@ -170,7 +166,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
  		return -EINVAL;
  
  	if (poffset) {
@@ -5965,7 +6666,7 @@ index 9537f3e..3ec181f 100644
  
  		if (*poffset >= mem->size)
  			return false;
-@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
+@@ -189,7 +185,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
  	struct nouveau_channel *chan;
  	int ret;
  
@@ -5974,7 +6675,7 @@ index 9537f3e..3ec181f 100644
  
  	ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
-index e7c100b..6aedc3b 100644
+index e7c100b..115904d 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_object.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_object.c
 @@ -34,6 +34,7 @@
@@ -6132,21 +6833,29 @@ index e7c100b..6aedc3b 100644
  	struct nouveau_engine *engine = &dev_priv->engine;
  	struct nouveau_gpuobj *gpuobj;
 -	struct mem_block *pramin = NULL;
-+	struct drm_mm *pramin = NULL;
++	struct drm_mm_node *ramin = NULL;
  	int ret;
  
  	NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
-@@ -222,6 +88,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
+@@ -222,82 +88,102 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
  	if (!gpuobj)
  		return -ENOMEM;
  	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
 +	gpuobj->dev = dev;
  	gpuobj->flags = flags;
- 	gpuobj->im_channel = chan;
+-	gpuobj->im_channel = chan;
++	kref_init(&gpuobj->refcount);
++	gpuobj->size = size;
  
-@@ -233,25 +100,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
- 	 * available.
- 	 */
++	spin_lock(&dev_priv->ramin_lock);
+ 	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
++	spin_unlock(&dev_priv->ramin_lock);
+ 
+-	/* Choose between global instmem heap, and per-channel private
+-	 * instmem heap.  On <NV50 allow requests for private instmem
+-	 * to be satisfied from global heap if no per-channel area
+-	 * available.
+-	 */
  	if (chan) {
 -		if (chan->ramin_heap) {
 -			NV_DEBUG(dev, "private heap\n");
@@ -6155,14 +6864,20 @@ index e7c100b..6aedc3b 100644
 -		if (dev_priv->card_type < NV_50) {
 -			NV_DEBUG(dev, "global heap fallback\n");
 -			pramin = dev_priv->ramin_heap;
--		}
 +		NV_DEBUG(dev, "channel heap\n");
-+		pramin = &chan->ramin_heap;
++
++		ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
++		if (ramin)
++			ramin = drm_mm_get_block(ramin, size, align);
++
++		if (!ramin) {
++			nouveau_gpuobj_ref(NULL, &gpuobj);
++			return -ENOMEM;
+ 		}
  	} else {
  		NV_DEBUG(dev, "global heap\n");
 -		pramin = dev_priv->ramin_heap;
 -	}
-+		pramin = &dev_priv->ramin_heap;
  
 -	if (!pramin) {
 -		NV_ERROR(dev, "No PRAMIN heap!\n");
@@ -6170,88 +6885,472 @@ index e7c100b..6aedc3b 100644
 -	}
 -
 -	if (!chan) {
++		/* allocate backing pages, sets vinst */
  		ret = engine->instmem.populate(dev, gpuobj, &size);
  		if (ret) {
- 			nouveau_gpuobj_del(dev, &gpuobj);
-@@ -260,9 +114,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
- 	}
+-			nouveau_gpuobj_del(dev, &gpuobj);
++			nouveau_gpuobj_ref(NULL, &gpuobj);
+ 			return ret;
+ 		}
+-	}
  
- 	/* Allocate a chunk of the PRAMIN aperture */
+-	/* Allocate a chunk of the PRAMIN aperture */
 -	gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
 -						    drm_order(align),
 -						    (struct drm_file *)-2, 0);
-+	gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
-+	if (gpuobj->im_pramin)
-+		gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+-	if (!gpuobj->im_pramin) {
+-		nouveau_gpuobj_del(dev, &gpuobj);
+-		return -ENOMEM;
++		/* try and get aperture space */
++		do {
++			if (drm_mm_pre_get(&dev_priv->ramin_heap))
++				return -ENOMEM;
++
++			spin_lock(&dev_priv->ramin_lock);
++			ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
++						   align, 0);
++			if (ramin == NULL) {
++				spin_unlock(&dev_priv->ramin_lock);
++				nouveau_gpuobj_ref(NULL, &gpuobj);
++				return ret;
++			}
 +
- 	if (!gpuobj->im_pramin) {
- 		nouveau_gpuobj_del(dev, &gpuobj);
- 		return -ENOMEM;
-@@ -279,10 +134,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
- 	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
- 		int i;
++			ramin = drm_mm_get_block_atomic(ramin, size, align);
++			spin_unlock(&dev_priv->ramin_lock);
++		} while (ramin == NULL);
++
++		/* on nv50 it's ok to fail, we have a fallback path */
++		if (!ramin && dev_priv->card_type < NV_50) {
++			nouveau_gpuobj_ref(NULL, &gpuobj);
++			return -ENOMEM;
++		}
+ 	}
+ 
+-	if (!chan) {
++	/* if we got a chunk of the aperture, map pages into it */
++	gpuobj->im_pramin = ramin;
++	if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) {
+ 		ret = engine->instmem.bind(dev, gpuobj);
+ 		if (ret) {
+-			nouveau_gpuobj_del(dev, &gpuobj);
++			nouveau_gpuobj_ref(NULL, &gpuobj);
+ 			return ret;
+ 		}
+ 	}
+ 
+-	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
+-		int i;
++	/* calculate the various different addresses for the object */
++	if (chan) {
++		gpuobj->pinst = chan->ramin->pinst;
++		if (gpuobj->pinst != ~0)
++			gpuobj->pinst += gpuobj->im_pramin->start;
  
 -		engine->instmem.prepare_access(dev, true);
- 		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
+-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
 -			nv_wo32(dev, gpuobj, i/4, 0);
 -		engine->instmem.finish_access(dev);
++		if (dev_priv->card_type < NV_50) {
++			gpuobj->cinst = gpuobj->pinst;
++		} else {
++			gpuobj->cinst = gpuobj->im_pramin->start;
++			gpuobj->vinst = gpuobj->im_pramin->start +
++					chan->ramin->vinst;
++		}
++	} else {
++		if (gpuobj->im_pramin)
++			gpuobj->pinst = gpuobj->im_pramin->start;
++		else
++			gpuobj->pinst = ~0;
++		gpuobj->cinst = 0xdeadbeef;
+ 	}
+ 
+-	*gpuobj_ret = gpuobj;
+-	return 0;
+-}
+-
+-int
+-nouveau_gpuobj_early_init(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
++		int i;
+ 
+-	NV_DEBUG(dev, "\n");
++		for (i = 0; i < gpuobj->size; i += 4)
 +			nv_wo32(gpuobj, i, 0);
 +		engine->instmem.flush(dev);
- 	}
++	}
  
- 	*gpuobj_ret = gpuobj;
-@@ -370,10 +224,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
- 	}
+-	INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+ 
++	*gpuobj_ret = gpuobj;
+ 	return 0;
+ }
+ 
+@@ -305,18 +191,12 @@ int
+ nouveau_gpuobj_init(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	int ret;
+ 
+ 	NV_DEBUG(dev, "\n");
+ 
+-	if (dev_priv->card_type < NV_50) {
+-		ret = nouveau_gpuobj_new_fake(dev,
+-			dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
+-			NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
+-						&dev_priv->ramht, NULL);
+-		if (ret)
+-			return ret;
+-	}
++	INIT_LIST_HEAD(&dev_priv->gpuobj_list);
++	spin_lock_init(&dev_priv->ramin_lock);
++	dev_priv->ramin_base = ~0;
+ 
+ 	return 0;
+ }
+@@ -328,299 +208,89 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
+ 
+ 	NV_DEBUG(dev, "\n");
+ 
+-	nouveau_gpuobj_del(dev, &dev_priv->ramht);
++	BUG_ON(!list_empty(&dev_priv->gpuobj_list));
+ }
+ 
+-void
+-nouveau_gpuobj_late_takedown(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *gpuobj = NULL;
+-	struct list_head *entry, *tmp;
+-
+-	NV_DEBUG(dev, "\n");
+-
+-	list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
+-		gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
+ 
+-		NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
+-			 gpuobj, gpuobj->refcount);
+-		gpuobj->refcount = 0;
+-		nouveau_gpuobj_del(dev, &gpuobj);
+-	}
+-}
+-
+-int
+-nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
++static void
++nouveau_gpuobj_del(struct kref *ref)
+ {
++	struct nouveau_gpuobj *gpuobj =
++		container_of(ref, struct nouveau_gpuobj, refcount);
++	struct drm_device *dev = gpuobj->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_engine *engine = &dev_priv->engine;
+-	struct nouveau_gpuobj *gpuobj;
+ 	int i;
+ 
+-	NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
+-
+-	if (!dev_priv || !pgpuobj || !(*pgpuobj))
+-		return -EINVAL;
+-	gpuobj = *pgpuobj;
+-
+-	if (gpuobj->refcount != 0) {
+-		NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
+-		return -EINVAL;
+-	}
++	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
  
  	if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
 -		engine->instmem.prepare_access(dev, true);
- 		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
+-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
 -			nv_wo32(dev, gpuobj, i/4, 0);
 -		engine->instmem.finish_access(dev);
++		for (i = 0; i < gpuobj->size; i += 4)
 +			nv_wo32(gpuobj, i, 0);
 +		engine->instmem.flush(dev);
  	}
  
  	if (gpuobj->dtor)
-@@ -386,7 +239,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
- 		if (gpuobj->flags & NVOBJ_FLAG_FAKE)
- 			kfree(gpuobj->im_pramin);
- 		else
--			nouveau_mem_free_block(gpuobj->im_pramin);
-+			drm_mm_put_block(gpuobj->im_pramin);
- 	}
+ 		gpuobj->dtor(dev, gpuobj);
  
+-	if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
++	if (gpuobj->im_backing)
+ 		engine->instmem.clear(dev, gpuobj);
+ 
+-	if (gpuobj->im_pramin) {
+-		if (gpuobj->flags & NVOBJ_FLAG_FAKE)
+-			kfree(gpuobj->im_pramin);
+-		else
+-			nouveau_mem_free_block(gpuobj->im_pramin);
+-	}
+-
++	spin_lock(&dev_priv->ramin_lock);
++	if (gpuobj->im_pramin)
++		drm_mm_put_block(gpuobj->im_pramin);
  	list_del(&gpuobj->list);
-@@ -583,13 +436,14 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
++	spin_unlock(&dev_priv->ramin_lock);
+ 
+-	*pgpuobj = NULL;
+ 	kfree(gpuobj);
+-	return 0;
+-}
+-
+-static int
+-nouveau_gpuobj_instance_get(struct drm_device *dev,
+-			    struct nouveau_channel *chan,
+-			    struct nouveau_gpuobj *gpuobj, uint32_t *inst)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *cpramin;
+-
+-	/* <NV50 use PRAMIN address everywhere */
+-	if (dev_priv->card_type < NV_50) {
+-		*inst = gpuobj->im_pramin->start;
+-		return 0;
+-	}
+-
+-	if (chan && gpuobj->im_channel != chan) {
+-		NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
+-			 gpuobj->im_channel->id, chan->id);
+-		return -EINVAL;
+-	}
+-
+-	/* NV50 channel-local instance */
+-	if (chan) {
+-		cpramin = chan->ramin->gpuobj;
+-		*inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
+-		return 0;
+-	}
+-
+-	/* NV50 global (VRAM) instance */
+-	if (!gpuobj->im_channel) {
+-		/* ...from global heap */
+-		if (!gpuobj->im_backing) {
+-			NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
+-			return -EINVAL;
+-		}
+-		*inst = gpuobj->im_backing_start;
+-		return 0;
+-	} else {
+-		/* ...from local heap */
+-		cpramin = gpuobj->im_channel->ramin->gpuobj;
+-		*inst = cpramin->im_backing_start +
+-			(gpuobj->im_pramin->start - cpramin->im_pramin->start);
+-		return 0;
+-	}
+-
+-	return -EINVAL;
+-}
+-
+-int
+-nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
+-		       uint32_t handle, struct nouveau_gpuobj *gpuobj,
+-		       struct nouveau_gpuobj_ref **ref_ret)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj_ref *ref;
+-	uint32_t instance;
+-	int ret;
+-
+-	NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
+-		 chan ? chan->id : -1, handle, gpuobj);
+-
+-	if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
+-		return -EINVAL;
+-
+-	if (!chan && !ref_ret)
+-		return -EINVAL;
+-
+-	if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
+-		/* sw object */
+-		instance = 0x40;
+-	} else {
+-		ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+-	if (!ref)
+-		return -ENOMEM;
+-	INIT_LIST_HEAD(&ref->list);
+-	ref->gpuobj   = gpuobj;
+-	ref->channel  = chan;
+-	ref->instance = instance;
+-
+-	if (!ref_ret) {
+-		ref->handle = handle;
+-
+-		ret = nouveau_ramht_insert(dev, ref);
+-		if (ret) {
+-			kfree(ref);
+-			return ret;
+-		}
+-	} else {
+-		ref->handle = ~0;
+-		*ref_ret = ref;
+-	}
+-
+-	ref->gpuobj->refcount++;
+-	return 0;
+ }
+ 
+-int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
+-{
+-	struct nouveau_gpuobj_ref *ref;
+-
+-	NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
+-
+-	if (!dev || !pref || *pref == NULL)
+-		return -EINVAL;
+-	ref = *pref;
+-
+-	if (ref->handle != ~0)
+-		nouveau_ramht_remove(dev, ref);
+-
+-	if (ref->gpuobj) {
+-		ref->gpuobj->refcount--;
+-
+-		if (ref->gpuobj->refcount == 0) {
+-			if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
+-				nouveau_gpuobj_del(dev, &ref->gpuobj);
+-		}
+-	}
+-
+-	*pref = NULL;
+-	kfree(ref);
+-	return 0;
+-}
+-
+-int
+-nouveau_gpuobj_new_ref(struct drm_device *dev,
+-		       struct nouveau_channel *oc, struct nouveau_channel *rc,
+-		       uint32_t handle, uint32_t size, int align,
+-		       uint32_t flags, struct nouveau_gpuobj_ref **ref)
+-{
+-	struct nouveau_gpuobj *gpuobj = NULL;
+-	int ret;
+-
+-	ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
+-	if (ret)
+-		return ret;
+-
+-	ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
+-	if (ret) {
+-		nouveau_gpuobj_del(dev, &gpuobj);
+-		return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-int
+-nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
+-			struct nouveau_gpuobj_ref **ref_ret)
++void
++nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
+ {
+-	struct nouveau_gpuobj_ref *ref;
+-	struct list_head *entry, *tmp;
++	if (ref)
++		kref_get(&ref->refcount);
+ 
+-	list_for_each_safe(entry, tmp, &chan->ramht_refs) {
+-		ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
++	if (*ptr)
++		kref_put(&(*ptr)->refcount, nouveau_gpuobj_del);
+ 
+-		if (ref->handle == handle) {
+-			if (ref_ret)
+-				*ref_ret = ref;
+-			return 0;
+-		}
+-	}
+-
+-	return -EINVAL;
++	*ptr = ref;
+ }
+ 
+ int
+-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
+-			uint32_t b_offset, uint32_t size,
+-			uint32_t flags, struct nouveau_gpuobj **pgpuobj,
+-			struct nouveau_gpuobj_ref **pref)
++nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
++			u32 size, u32 flags, struct nouveau_gpuobj **pgpuobj)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_gpuobj *gpuobj = NULL;
+ 	int i;
+ 
+ 	NV_DEBUG(dev,
+-		 "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
+-		 p_offset, b_offset, size, flags);
++		 "pinst=0x%08x vinst=0x%010llx size=0x%08x flags=0x%08x\n",
++		 pinst, vinst, size, flags);
+ 
+ 	gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
  	if (!gpuobj)
  		return -ENOMEM;
  	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
-+	gpuobj->dev = dev;
- 	gpuobj->im_channel = NULL;
- 	gpuobj->flags      = flags | NVOBJ_FLAG_FAKE;
- 
- 	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
- 
- 	if (p_offset != ~0) {
+-	gpuobj->im_channel = NULL;
+-	gpuobj->flags      = flags | NVOBJ_FLAG_FAKE;
+-
+-	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+-
+-	if (p_offset != ~0) {
 -		gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
-+		gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
- 					    GFP_KERNEL);
- 		if (!gpuobj->im_pramin) {
- 			nouveau_gpuobj_del(dev, &gpuobj);
-@@ -605,10 +459,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
- 	}
+-					    GFP_KERNEL);
+-		if (!gpuobj->im_pramin) {
+-			nouveau_gpuobj_del(dev, &gpuobj);
+-			return -ENOMEM;
+-		}
+-		gpuobj->im_pramin->start = p_offset;
+-		gpuobj->im_pramin->size  = size;
+-	}
+-
+-	if (b_offset != ~0) {
+-		gpuobj->im_backing = (struct nouveau_bo *)-1;
+-		gpuobj->im_backing_start = b_offset;
+-	}
++	gpuobj->dev = dev;
++	gpuobj->flags = flags;
++	kref_init(&gpuobj->refcount);
++	gpuobj->size  = size;
++	gpuobj->pinst = pinst;
++	gpuobj->cinst = 0xdeadbeef;
++	gpuobj->vinst = vinst;
  
  	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
 -		dev_priv->engine.instmem.prepare_access(dev, true);
- 		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
+-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
 -			nv_wo32(dev, gpuobj, i/4, 0);
 -		dev_priv->engine.instmem.finish_access(dev);
++		for (i = 0; i < gpuobj->size; i += 4)
 +			nv_wo32(gpuobj, i, 0);
 +		dev_priv->engine.instmem.flush(dev);
  	}
  
- 	if (pref) {
-@@ -696,8 +549,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
+-	if (pref) {
+-		i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
+-		if (i) {
+-			nouveau_gpuobj_del(dev, &gpuobj);
+-			return i;
+-		}
+-	}
+-
+-	if (pgpuobj)
+-		*pgpuobj = gpuobj;
++	spin_lock(&dev_priv->ramin_lock);
++	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
++	spin_unlock(&dev_priv->ramin_lock);
++	*pgpuobj = gpuobj;
+ 	return 0;
+ }
+ 
+@@ -696,8 +366,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
  		return ret;
  	}
  
@@ -6260,7 +7359,7 @@ index e7c100b..6aedc3b 100644
  	if (dev_priv->card_type < NV_50) {
  		uint32_t frame, adjust, pte_flags = 0;
  
-@@ -706,14 +557,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
+@@ -706,14 +374,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
  		adjust = offset &  0x00000fff;
  		frame  = offset & ~0x00000fff;
  
@@ -6281,7 +7380,7 @@ index e7c100b..6aedc3b 100644
  	} else {
  		uint64_t limit = offset + size - 1;
  		uint32_t flags0, flags5;
-@@ -726,15 +575,15 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
+@@ -726,15 +392,15 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
  			flags5 = 0x00080000;
  		}
  
@@ -6304,7 +7403,16 @@ index e7c100b..6aedc3b 100644
  
  	(*gpuobj)->engine = NVOBJ_ENGINE_SW;
  	(*gpuobj)->class  = class;
-@@ -849,32 +698,31 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
+@@ -762,7 +428,7 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
+ 			*o_ret = 0;
+ 	} else
+ 	if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
+-		*gpuobj = dev_priv->gart_info.sg_ctxdma;
++		nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
+ 		if (offset & ~0xffffffffULL) {
+ 			NV_ERROR(dev, "obj offset exceeds 32-bits\n");
+ 			return -EINVAL;
+@@ -849,32 +515,31 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
  		return ret;
  	}
  
@@ -6346,7 +7454,31 @@ index e7c100b..6aedc3b 100644
  
  	(*gpuobj)->engine = NVOBJ_ENGINE_GR;
  	(*gpuobj)->class  = class;
-@@ -920,6 +768,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
+@@ -895,10 +560,15 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
+ 	gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
+ 	if (!gpuobj)
+ 		return -ENOMEM;
++	gpuobj->dev = chan->dev;
+ 	gpuobj->engine = NVOBJ_ENGINE_SW;
+ 	gpuobj->class = class;
++	kref_init(&gpuobj->refcount);
++	gpuobj->cinst = 0x40;
+ 
++	spin_lock(&dev_priv->ramin_lock);
+ 	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
++	spin_unlock(&dev_priv->ramin_lock);
+ 	*gpuobj_ret = gpuobj;
+ 	return 0;
+ }
+@@ -908,7 +578,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
+ {
+ 	struct drm_device *dev = chan->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *pramin = NULL;
+ 	uint32_t size;
+ 	uint32_t base;
+ 	int ret;
+@@ -920,6 +589,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
  	base = 0;
  
  	/* PGRAPH context */
@@ -6354,7 +7486,7 @@ index e7c100b..6aedc3b 100644
  
  	if (dev_priv->card_type == NV_50) {
  		/* Various fixed table thingos */
-@@ -930,12 +779,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
+@@ -930,25 +600,18 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
  		size += 0x8000;
  		/* RAMFC */
  		size += 0x1000;
@@ -6364,21 +7496,31 @@ index e7c100b..6aedc3b 100644
  
 -	NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
 -		 chan->id, size, base);
- 	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
- 				     &chan->ramin);
+-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
+-				     &chan->ramin);
++	ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
  	if (ret) {
-@@ -944,8 +789,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
+ 		NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret);
+ 		return ret;
  	}
- 	pramin = chan->ramin->gpuobj;
+-	pramin = chan->ramin->gpuobj;
  
 -	ret = nouveau_mem_init_heap(&chan->ramin_heap,
 -				    pramin->im_pramin->start + base, size);
-+	ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
++	ret = drm_mm_init(&chan->ramin_heap, base, size);
  	if (ret) {
  		NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
- 		nouveau_gpuobj_ref_del(dev, &chan->ramin);
-@@ -969,15 +813,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
++		nouveau_gpuobj_ref(NULL, &chan->ramin);
+ 		return ret;
+ 	}
  
+@@ -965,19 +628,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 	struct nouveau_gpuobj *vram = NULL, *tt = NULL;
+ 	int ret, i;
+ 
+-	INIT_LIST_HEAD(&chan->ramht_refs);
+-
  	NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
  
 -	/* Reserve a block of PRAMIN for the channel
@@ -6398,19 +7540,29 @@ index e7c100b..6aedc3b 100644
  	}
  
  	/* NV50 VM
-@@ -988,50 +828,42 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+@@ -986,65 +643,56 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 	 *    locations determined during init.
+ 	 */
  	if (dev_priv->card_type >= NV_50) {
- 		uint32_t vm_offset, pde;
- 
--		instmem->prepare_access(dev, true);
+-		uint32_t vm_offset, pde;
 -
- 		vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
- 		vm_offset += chan->ramin->gpuobj->im_pramin->start;
- 
- 		ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
- 							0, &chan->vm_pd, NULL);
+-		instmem->prepare_access(dev, true);
++		u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
++		u64 vm_vinst = chan->ramin->vinst + pgd_offs;
++		u32 vm_pinst = chan->ramin->pinst;
++		u32 pde;
+ 
+-		vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
+-		vm_offset += chan->ramin->gpuobj->im_pramin->start;
++		if (vm_pinst != ~0)
++			vm_pinst += pgd_offs;
+ 
+-		ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
+-							0, &chan->vm_pd, NULL);
 -		if (ret) {
 -			instmem->finish_access(dev);
++		ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000,
++					      0, &chan->vm_pd);
 +		if (ret)
  			return ret;
 -		}
@@ -6422,38 +7574,40 @@ index e7c100b..6aedc3b 100644
  		}
  
 -		pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2;
-+		pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
- 		ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
- 					     dev_priv->gart_info.sg_ctxdma,
- 					     &chan->vm_gart_pt);
+-		ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
+-					     dev_priv->gart_info.sg_ctxdma,
+-					     &chan->vm_gart_pt);
 -		if (ret) {
 -			instmem->finish_access(dev);
-+		if (ret)
- 			return ret;
+-			return ret;
 -		}
 -		nv_wo32(dev, chan->vm_pd, pde++,
 -			    chan->vm_gart_pt->instance | 0x03);
 -		nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
-+		nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->instance | 3);
++		nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma,
++				   &chan->vm_gart_pt);
++		pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
++		nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3);
 +		nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
  
 -		pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2;
 +		pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
  		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
- 			ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
- 						     dev_priv->vm_vram_pt[i],
- 						     &chan->vm_vram_pt[i]);
+-			ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
+-						     dev_priv->vm_vram_pt[i],
+-						     &chan->vm_vram_pt[i]);
 -			if (ret) {
 -				instmem->finish_access(dev);
-+			if (ret)
- 				return ret;
+-				return ret;
 -			}
++			nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i],
++					   &chan->vm_vram_pt[i]);
  
 -			nv_wo32(dev, chan->vm_pd, pde++,
 -				    chan->vm_vram_pt[i]->instance | 0x61);
 -			nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
 +			nv_wo32(chan->vm_pd, pde + 0,
-+				chan->vm_vram_pt[i]->instance | 0x61);
++				chan->vm_vram_pt[i]->vinst | 0x61);
 +			nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
 +			pde += 8;
  		}
@@ -6463,18 +7617,134 @@ index e7c100b..6aedc3b 100644
  	}
  
  	/* RAMHT */
-@@ -1130,8 +962,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
- 	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
- 		nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+ 	if (dev_priv->card_type < NV_50) {
+-		ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
+-					     &chan->ramht);
++		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;
+-	} else {
+-		ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
+-					     0x8000, 16,
+-					     NVOBJ_FLAG_ZERO_ALLOC,
+-					     &chan->ramht);
++
++		ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
++		nouveau_gpuobj_ref(NULL, &ramht);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -1061,24 +709,32 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 		}
+ 	} else {
+ 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+-						0, dev_priv->fb_available_size,
+-						NV_DMA_ACCESS_RW,
+-						NV_DMA_TARGET_VIDMEM, &vram);
++					     0, dev_priv->fb_available_size,
++					     NV_DMA_ACCESS_RW,
++					     NV_DMA_TARGET_VIDMEM, &vram);
+ 		if (ret) {
+ 			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
+ 			return ret;
+ 		}
+ 	}
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL);
++	ret = nouveau_ramht_insert(chan, vram_h, vram);
++	nouveau_gpuobj_ref(NULL, &vram);
+ 	if (ret) {
+-		NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", 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) {
+-		tt = vram;
++		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
++					     0, dev_priv->vm_end,
++					     NV_DMA_ACCESS_RW,
++					     NV_DMA_TARGET_AGP, &tt);
++		if (ret) {
++			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
++			return ret;
++		}
+ 	} else
+ 	if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
+ 		ret = nouveau_gpuobj_gart_dma_new(chan, 0,
+@@ -1094,9 +750,10 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
+ 		return ret;
+ 	}
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
++	ret = nouveau_ramht_insert(chan, tt_h, tt);
++	nouveau_gpuobj_ref(NULL, &tt);
+ 	if (ret) {
+-		NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret);
++		NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret);
+ 		return ret;
+ 	}
+ 
+@@ -1108,33 +765,23 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
+ {
+ 	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ 	struct drm_device *dev = chan->dev;
+-	struct list_head *entry, *tmp;
+-	struct nouveau_gpuobj_ref *ref;
+ 	int i;
  
+ 	NV_DEBUG(dev, "ch%d\n", chan->id);
+ 
+-	if (!chan->ramht_refs.next)
++	if (!chan->ramht)
+ 		return;
+ 
+-	list_for_each_safe(entry, tmp, &chan->ramht_refs) {
+-		ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
++	nouveau_ramht_ref(NULL, &chan->ramht, chan);
+ 
+-		nouveau_gpuobj_ref_del(dev, &ref);
+-	}
+-
+-	nouveau_gpuobj_ref_del(dev, &chan->ramht);
+-
+-	nouveau_gpuobj_del(dev, &chan->vm_pd);
+-	nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt);
++	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
++	nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt);
+ 	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
+-		nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+-
 -	if (chan->ramin_heap)
 -		nouveau_mem_takedown(&chan->ramin_heap);
+-	if (chan->ramin)
+-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
++		nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
+ 
 +	if (chan->ramin_heap.fl_entry.next)
 +		drm_mm_takedown(&chan->ramin_heap);
- 	if (chan->ramin)
- 		nouveau_gpuobj_ref_del(dev, &chan->ramin);
++	nouveau_gpuobj_ref(NULL, &chan->ramin);
+ }
+ 
+ int
+@@ -1155,19 +802,17 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
+ 	}
+ 
+ 	list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
+-		if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE))
++		if (!gpuobj->im_backing)
+ 			continue;
  
-@@ -1164,10 +996,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
+-		gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size);
++		gpuobj->im_backing_suspend = vmalloc(gpuobj->size);
+ 		if (!gpuobj->im_backing_suspend) {
+ 			nouveau_gpuobj_resume(dev);
  			return -ENOMEM;
  		}
  
@@ -6482,12 +7752,12 @@ index e7c100b..6aedc3b 100644
 -		for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
 -			gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
 -		dev_priv->engine.instmem.finish_access(dev);
-+		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
++		for (i = 0; i < gpuobj->size; i += 4)
 +			gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
  	}
  
  	return 0;
-@@ -1212,10 +1042,9 @@ nouveau_gpuobj_resume(struct drm_device *dev)
+@@ -1212,10 +857,9 @@ nouveau_gpuobj_resume(struct drm_device *dev)
  		if (!gpuobj->im_backing_suspend)
  			continue;
  
@@ -6495,13 +7765,13 @@ index e7c100b..6aedc3b 100644
 -		for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
 -			nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
 -		dev_priv->engine.instmem.finish_access(dev);
-+		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
++		for (i = 0; i < gpuobj->size; i += 4)
 +			nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
 +		dev_priv->engine.instmem.flush(dev);
  	}
  
  	nouveau_gpuobj_suspend_cleanup(dev);
-@@ -1232,7 +1061,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
+@@ -1232,7 +876,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
  	struct nouveau_channel *chan;
  	int ret;
  
@@ -6509,38 +7779,111 @@ index e7c100b..6aedc3b 100644
  	NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
  
  	if (init->handle == ~0)
-@@ -1283,7 +1111,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
+@@ -1250,25 +893,24 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
+ 		return -EPERM;
+ 	}
+ 
+-	if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
++	if (nouveau_ramht_find(chan, init->handle))
+ 		return -EEXIST;
+ 
+ 	if (!grc->software)
+ 		ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
+ 	else
+ 		ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
+-
+ 	if (ret) {
+ 		NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
+ 			 ret, init->channel, init->handle);
+ 		return ret;
+ 	}
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL);
++	ret = nouveau_ramht_insert(chan, init->handle, gr);
++	nouveau_gpuobj_ref(NULL, &gr);
+ 	if (ret) {
+ 		NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
+ 			 ret, init->channel, init->handle);
+-		nouveau_gpuobj_del(dev, &gr);
+ 		return ret;
+ 	}
+ 
+@@ -1279,17 +921,62 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
+ 			      struct drm_file *file_priv)
+ {
+ 	struct drm_nouveau_gpuobj_free *objfree = data;
+-	struct nouveau_gpuobj_ref *ref;
++	struct nouveau_gpuobj *gpuobj;
  	struct nouveau_channel *chan;
- 	int ret;
+-	int ret;
  
 -	NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
  	NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
  
- 	ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
-@@ -1293,3 +1120,17 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
+-	ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
+-	if (ret)
+-		return ret;
+-	nouveau_gpuobj_ref_del(dev, &ref);
++	gpuobj = nouveau_ramht_find(chan, objfree->handle);
++	if (!gpuobj)
++		return -ENOENT;
  
++	nouveau_ramht_remove(chan, objfree->handle);
  	return 0;
  }
 +
 +u32
 +nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
 +{
++	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 +	struct drm_device *dev = gpuobj->dev;
-+	return nv_ri32(dev, gpuobj->im_pramin->start + offset);
++
++	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
++		u64  ptr = gpuobj->vinst + offset;
++		u32 base = ptr >> 16;
++		u32  val;
++
++		spin_lock(&dev_priv->ramin_lock);
++		if (dev_priv->ramin_base != base) {
++			dev_priv->ramin_base = base;
++			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
++		}
++		val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
++		spin_unlock(&dev_priv->ramin_lock);
++		return val;
++	}
++
++	return nv_ri32(dev, gpuobj->pinst + offset);
 +}
 +
 +void
 +nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
 +{
++	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
 +	struct drm_device *dev = gpuobj->dev;
-+	nv_wi32(dev, gpuobj->im_pramin->start + offset, val);
++
++	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
++		u64  ptr = gpuobj->vinst + offset;
++		u32 base = ptr >> 16;
++
++		spin_lock(&dev_priv->ramin_lock);
++		if (dev_priv->ramin_base != base) {
++			dev_priv->ramin_base = base;
++			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
++		}
++		nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
++		spin_unlock(&dev_priv->ramin_lock);
++		return;
++	}
++
++	nv_wi32(dev, gpuobj->pinst + offset, val);
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c
 new file mode 100644
-index 0000000..e5cc93c
+index 0000000..7f16697
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c
-@@ -0,0 +1,160 @@
+@@ -0,0 +1,289 @@
 +/*
 + * Copyright 2010 Red Hat Inc.
 + *
@@ -6570,22 +7913,24 @@ index 0000000..e5cc93c
 +#include "nouveau_drv.h"
 +#include "nouveau_ramht.h"
 +
-+static uint32_t
-+nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
++static u32
++nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
 +{
++	struct drm_device *dev = chan->dev;
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
-+	uint32_t hash = 0;
++	struct nouveau_ramht *ramht = chan->ramht;
++	u32 hash = 0;
 +	int i;
 +
-+	NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle);
++	NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
 +
-+	for (i = 32; i > 0; i -= dev_priv->ramht_bits) {
-+		hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
-+		handle >>= dev_priv->ramht_bits;
++	for (i = 32; i > 0; i -= ramht->bits) {
++		hash ^= (handle & ((1 << ramht->bits) - 1));
++		handle >>= ramht->bits;
 +	}
 +
 +	if (dev_priv->card_type < NV_50)
-+		hash ^= channel << (dev_priv->ramht_bits - 4);
++		hash ^= chan->id << (ramht->bits - 4);
 +	hash <<= 3;
 +
 +	NV_DEBUG(dev, "hash=0x%08x\n", hash);
@@ -6594,59 +7939,88 @@ index 0000000..e5cc93c
 +
 +static int
 +nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
-+			  uint32_t offset)
++			  u32 offset)
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
-+	uint32_t ctx = nv_ro32(ramht, offset + 4);
++	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 drm_device *dev, struct nouveau_gpuobj_ref *ref)
++nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
++		     struct nouveau_gpuobj *gpuobj)
 +{
++	struct drm_device *dev = chan->dev;
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-+	struct nouveau_channel *chan = ref->channel;
-+	struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-+	uint32_t ctx, co, ho;
++	struct nouveau_ramht_entry *entry;
++	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
++	unsigned long flags;
++	u32 ctx, co, ho;
 +
-+	if (!ramht) {
-+		NV_ERROR(dev, "No hash table!\n");
-+		return -EINVAL;
-+	}
++	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 | (ref->instance >> 4) |
++		ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
 +		      (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-+		      (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
++		      (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
 +	} else
 +	if (dev_priv->card_type < NV_50) {
-+		ctx = (ref->instance >> 4) |
++		ctx = (gpuobj->cinst >> 4) |
 +		      (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-+		      (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
++		      (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
 +	} else {
-+		if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
-+			ctx = (ref->instance << 10) | 2;
++		if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
++			ctx = (gpuobj->cinst << 10) | 2;
 +		} else {
-+			ctx = (ref->instance >> 4) |
-+			      ((ref->gpuobj->engine <<
++			ctx = (gpuobj->cinst >> 4) |
++			      ((gpuobj->engine <<
 +				NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
 +		}
 +	}
 +
-+	co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
++	spin_lock_irqsave(&chan->ramht->lock, flags);
++	list_add(&entry->head, &chan->ramht->entries);
++
++	co = ho = nouveau_ramht_hash_handle(chan, 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, ref->handle, ctx);
-+			nv_wo32(ramht, co + 0, ref->handle);
++				 chan->id, co, handle, ctx);
++			nv_wo32(ramht, co + 0, handle);
 +			nv_wo32(ramht, co + 4, ctx);
 +
-+			list_add_tail(&ref->list, &chan->ramht_refs);
++			spin_unlock_irqrestore(&chan->ramht->lock, flags);
 +			instmem->flush(dev);
 +			return 0;
 +		}
@@ -6654,59 +8028,157 @@ index 0000000..e5cc93c
 +			 chan->id, co, nv_ro32(ramht, co));
 +
 +		co += 8;
-+		if (co >= dev_priv->ramht_size)
++		if (co >= 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;
 +}
 +
-+void
-+nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
++static void
++nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
 +{
++	struct drm_device *dev = chan->dev;
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-+	struct nouveau_channel *chan = ref->channel;
-+	struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-+	uint32_t co, ho;
++	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
++	struct nouveau_ramht_entry *entry, *tmp;
++	u32 co, ho;
 +
-+	if (!ramht) {
-+		NV_ERROR(dev, "No hash table!\n");
-+		return;
++	list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
++		if (entry->channel != chan || entry->handle != handle)
++			continue;
++
++		nouveau_gpuobj_ref(NULL, &entry->gpuobj);
++		list_del(&entry->head);
++		kfree(entry);
++		break;
 +	}
 +
-+	co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
++	co = ho = nouveau_ramht_hash_handle(chan, handle);
 +	do {
 +		if (nouveau_ramht_entry_valid(dev, ramht, co) &&
-+		    (ref->handle == nv_ro32(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, ref->handle,
-+				 nv_ro32(ramht, co + 4));
++				 chan->id, co, handle, nv_ro32(ramht, co + 4));
 +			nv_wo32(ramht, co + 0, 0x00000000);
 +			nv_wo32(ramht, co + 4, 0x00000000);
-+
-+			list_del(&ref->list);
 +			instmem->flush(dev);
 +			return;
 +		}
 +
 +		co += 8;
-+		if (co >= dev_priv->ramht_size)
++		if (co >= ramht->size)
 +			co = 0;
 +	} while (co != ho);
-+	list_del(&ref->list);
 +
 +	NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
-+		 chan->id, ref->handle);
++		 chan->id, handle);
++}
++
++void
++nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
++{
++	struct nouveau_ramht *ramht = chan->ramht;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ramht->lock, flags);
++	nouveau_ramht_remove_locked(chan, handle);
++	spin_unlock_irqrestore(&ramht->lock, flags);
++}
++
++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)
++{
++	struct nouveau_ramht_entry *entry, *tmp;
++	struct nouveau_ramht *ramht;
++	unsigned long flags;
++
++	if (ref)
++		kref_get(&ref->refcount);
++
++	ramht = *ptr;
++	if (ramht) {
++		spin_lock_irqsave(&ramht->lock, flags);
++		list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
++			if (entry->channel != chan)
++				continue;
++
++			nouveau_ramht_remove_locked(chan, entry->handle);
++		}
++		spin_unlock_irqrestore(&ramht->lock, flags);
++
++		kref_put(&ramht->refcount, nouveau_ramht_del);
++	}
++	*ptr = ref;
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h
 new file mode 100644
-index 0000000..e10455c
+index 0000000..b79cb5e
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,55 @@
 +/*
 + * Copyright 2010 Red Hat Inc.
 + *
@@ -6734,12 +8206,36 @@ index 0000000..e10455c
 +#ifndef __NOUVEAU_RAMHT_H__
 +#define __NOUVEAU_RAMHT_H__
 +
-+extern int nouveau_ramht_insert(struct drm_device *, struct nouveau_gpuobj_ref *);
-+extern void nouveau_ramht_remove(struct drm_device *, struct nouveau_gpuobj_ref *);
++struct nouveau_ramht_entry {
++	struct list_head head;
++	struct nouveau_channel *channel;
++	struct nouveau_gpuobj *gpuobj;
++	u32 handle;
++};
++
++struct nouveau_ramht {
++	struct drm_device *dev;
++	struct kref refcount;
++	spinlock_t lock;
++	struct nouveau_gpuobj *gpuobj;
++	struct list_head entries;
++	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);
++
++extern int  nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
++				 struct nouveau_gpuobj *);
++extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
++extern struct nouveau_gpuobj *
++nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
 +
 +#endif
 diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
-index 6ca80a3..21a6e45 100644
+index 6ca80a3..1b42541 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
 @@ -1,19 +1,64 @@
@@ -6891,7 +8387,34 @@ index 6ca80a3..21a6e45 100644
  #define NV10_PGRAPH_DMA_PITCH                              0x00400770
  #define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
  #define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
-@@ -814,6 +838,7 @@
+@@ -527,6 +551,8 @@
+ #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
+@@ -761,15 +787,12 @@
+ #define NV50_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
+ #define NV50_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610b70 + (i) * 0x8)
+ #define NV50_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610b74 + (i) * 0x8)
++#define NV50_PDISPLAY_EXT_MODE_CTRL_P(i)                (0x00610b80 + (i) * 0x8)
++#define NV50_PDISPLAY_EXT_MODE_CTRL_C(i)                (0x00610b84 + (i) * 0x8)
+ #define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610bdc + (i) * 0x8)
+ #define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610be0 + (i) * 0x8)
+-
+ #define NV90_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610794 + (i) * 0x8)
+ #define NV90_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610798 + (i) * 0x8)
+-#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i)                (0x00610b58 + (i) * 0x8)
+-#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
+-#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610b80 + (i) * 0x8)
+-#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610b84 + (i) * 0x8)
+ 
+ #define NV50_PDISPLAY_CRTC_CLK                                       0x00614000
+ #define NV50_PDISPLAY_CRTC_CLK_CTRL1(i)                 ((i) * 0x800 + 0x614100)
+@@ -814,6 +837,7 @@
  #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
  #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
  #define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
@@ -6900,7 +8423,7 @@ index 6ca80a3..21a6e45 100644
  #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
  #define NV50_SOR_DP_CTRL_LANE_0_ENABLED                              0x00010000
 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-index 1d6ee8b..630988a 100644
+index 1d6ee8b..5a66a7a 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
 @@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
@@ -7015,12 +8538,20 @@ index 1d6ee8b..630988a 100644
  	struct nouveau_gpuobj *gpuobj = NULL;
  	uint32_t aper_size, obj_size;
  	int i, ret;
-@@ -267,34 +244,42 @@ nouveau_sgdma_init(struct drm_device *dev)
+@@ -257,7 +234,6 @@ nouveau_sgdma_init(struct drm_device *dev)
+ 	}
+ 
+ 	ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
+-				      NVOBJ_FLAG_ALLOW_NO_REFS |
+ 				      NVOBJ_FLAG_ZERO_ALLOC |
+ 				      NVOBJ_FLAG_ZERO_FREE, &gpuobj);
+ 	if (ret) {
+@@ -267,34 +243,48 @@ nouveau_sgdma_init(struct drm_device *dev)
  
  	dev_priv->gart_info.sg_dummy_page =
  		alloc_page(GFP_KERNEL|__GFP_DMA32);
 +	if (!dev_priv->gart_info.sg_dummy_page) {
-+		nouveau_gpuobj_del(dev, &gpuobj);
++		nouveau_gpuobj_ref(NULL, &gpuobj);
 +		return -ENOMEM;
 +	}
 +
@@ -7030,12 +8561,18 @@ index 1d6ee8b..630988a 100644
 +		pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
  			     PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 +	if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
-+		nouveau_gpuobj_del(dev, &gpuobj);
++		nouveau_gpuobj_ref(NULL, &gpuobj);
 +		return -EFAULT;
 +	}
  
 -	dev_priv->engine.instmem.prepare_access(dev, true);
  	if (dev_priv->card_type < NV_50) {
++		/* special case, allocated from global instmem heap so
++		 * cinst is invalid, we use it on all channels though so
++		 * cinst needs to be valid, set it the same as pinst
++		 */
++		gpuobj->cinst = gpuobj->pinst;
++
  		/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
  		 * confirmed to work on c51.  Perhaps means NV_DMA_TARGET_PCIE
  		 * on those cards? */
@@ -7072,7 +8609,16 @@ index 1d6ee8b..630988a 100644
  
  	dev_priv->gart_info.type      = NOUVEAU_GART_SGDMA;
  	dev_priv->gart_info.aper_base = 0;
-@@ -325,14 +310,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
+@@ -317,7 +307,7 @@ nouveau_sgdma_takedown(struct drm_device *dev)
+ 		dev_priv->gart_info.sg_dummy_bus = 0;
+ 	}
+ 
+-	nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma);
++	nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
+ }
+ 
+ int
+@@ -325,14 +315,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
@@ -7090,10 +8636,14 @@ index 1d6ee8b..630988a 100644
  	}
  
 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
-index b02a231..989322b 100644
+index b02a231..be85960 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_state.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_state.c
-@@ -38,6 +38,7 @@
+@@ -35,9 +35,11 @@
+ #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
+ #include "nouveau_fbcon.h"
++#include "nouveau_ramht.h"
  #include "nv50_display.h"
  
  static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -7101,7 +8651,7 @@ index b02a231..989322b 100644
  
  static int nouveau_init_engine_ptrs(struct drm_device *dev)
  {
-@@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -54,8 +56,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->instmem.clear		= nv04_instmem_clear;
  		engine->instmem.bind		= nv04_instmem_bind;
  		engine->instmem.unbind		= nv04_instmem_unbind;
@@ -7111,7 +8661,14 @@ index b02a231..989322b 100644
  		engine->mc.init			= nv04_mc_init;
  		engine->mc.takedown		= nv04_mc_takedown;
  		engine->timer.init		= nv04_timer_init;
-@@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -78,13 +79,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->fifo.disable		= nv04_fifo_disable;
+ 		engine->fifo.enable		= nv04_fifo_enable;
+ 		engine->fifo.reassign		= nv04_fifo_reassign;
+-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
+ 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
+ 		engine->fifo.channel_id		= nv04_fifo_channel_id;
+ 		engine->fifo.create_context	= nv04_fifo_create_context;
  		engine->fifo.destroy_context	= nv04_fifo_destroy_context;
  		engine->fifo.load_context	= nv04_fifo_load_context;
  		engine->fifo.unload_context	= nv04_fifo_unload_context;
@@ -7138,7 +8695,14 @@ index b02a231..989322b 100644
  		engine->mc.init			= nv04_mc_init;
  		engine->mc.takedown		= nv04_mc_takedown;
  		engine->timer.init		= nv04_timer_init;
-@@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -121,13 +130,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->fifo.disable		= nv04_fifo_disable;
+ 		engine->fifo.enable		= nv04_fifo_enable;
+ 		engine->fifo.reassign		= nv04_fifo_reassign;
+-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
+ 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
+ 		engine->fifo.channel_id		= nv10_fifo_channel_id;
+ 		engine->fifo.create_context	= nv10_fifo_create_context;
  		engine->fifo.destroy_context	= nv10_fifo_destroy_context;
  		engine->fifo.load_context	= nv10_fifo_load_context;
  		engine->fifo.unload_context	= nv10_fifo_unload_context;
@@ -7155,7 +8719,7 @@ index b02a231..989322b 100644
  		break;
  	case 0x20:
  		engine->instmem.init		= nv04_instmem_init;
-@@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -138,8 +156,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->instmem.clear		= nv04_instmem_clear;
  		engine->instmem.bind		= nv04_instmem_bind;
  		engine->instmem.unbind		= nv04_instmem_unbind;
@@ -7165,7 +8729,14 @@ index b02a231..989322b 100644
  		engine->mc.init			= nv04_mc_init;
  		engine->mc.takedown		= nv04_mc_takedown;
  		engine->timer.init		= nv04_timer_init;
-@@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -164,13 +181,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->fifo.disable		= nv04_fifo_disable;
+ 		engine->fifo.enable		= nv04_fifo_enable;
+ 		engine->fifo.reassign		= nv04_fifo_reassign;
+-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
+ 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
+ 		engine->fifo.channel_id		= nv10_fifo_channel_id;
+ 		engine->fifo.create_context	= nv10_fifo_create_context;
  		engine->fifo.destroy_context	= nv10_fifo_destroy_context;
  		engine->fifo.load_context	= nv10_fifo_load_context;
  		engine->fifo.unload_context	= nv10_fifo_unload_context;
@@ -7182,7 +8753,7 @@ index b02a231..989322b 100644
  		break;
  	case 0x30:
  		engine->instmem.init		= nv04_instmem_init;
-@@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -181,15 +207,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->instmem.clear		= nv04_instmem_clear;
  		engine->instmem.bind		= nv04_instmem_bind;
  		engine->instmem.unbind		= nv04_instmem_unbind;
@@ -7201,7 +8772,14 @@ index b02a231..989322b 100644
  		engine->fb.set_region_tiling	= nv10_fb_set_region_tiling;
  		engine->graph.grclass		= nv30_graph_grclass;
  		engine->graph.init		= nv30_graph_init;
-@@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -207,13 +232,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->fifo.disable		= nv04_fifo_disable;
+ 		engine->fifo.enable		= nv04_fifo_enable;
+ 		engine->fifo.reassign		= nv04_fifo_reassign;
+-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
+ 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
+ 		engine->fifo.channel_id		= nv10_fifo_channel_id;
+ 		engine->fifo.create_context	= nv10_fifo_create_context;
  		engine->fifo.destroy_context	= nv10_fifo_destroy_context;
  		engine->fifo.load_context	= nv10_fifo_load_context;
  		engine->fifo.unload_context	= nv10_fifo_unload_context;
@@ -7218,7 +8796,7 @@ index b02a231..989322b 100644
  		break;
  	case 0x40:
  	case 0x60:
-@@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -225,8 +259,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->instmem.clear		= nv04_instmem_clear;
  		engine->instmem.bind		= nv04_instmem_bind;
  		engine->instmem.unbind		= nv04_instmem_unbind;
@@ -7228,7 +8806,14 @@ index b02a231..989322b 100644
  		engine->mc.init			= nv40_mc_init;
  		engine->mc.takedown		= nv40_mc_takedown;
  		engine->timer.init		= nv04_timer_init;
-@@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -251,13 +284,22 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->fifo.disable		= nv04_fifo_disable;
+ 		engine->fifo.enable		= nv04_fifo_enable;
+ 		engine->fifo.reassign		= nv04_fifo_reassign;
+-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
+ 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
+ 		engine->fifo.channel_id		= nv10_fifo_channel_id;
+ 		engine->fifo.create_context	= nv40_fifo_create_context;
  		engine->fifo.destroy_context	= nv40_fifo_destroy_context;
  		engine->fifo.load_context	= nv40_fifo_load_context;
  		engine->fifo.unload_context	= nv40_fifo_unload_context;
@@ -7245,7 +8830,7 @@ index b02a231..989322b 100644
  		break;
  	case 0x50:
  	case 0x80: /* gotta love NVIDIA's consistency.. */
-@@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -271,8 +313,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->instmem.clear		= nv50_instmem_clear;
  		engine->instmem.bind		= nv50_instmem_bind;
  		engine->instmem.unbind		= nv50_instmem_unbind;
@@ -7258,7 +8843,7 @@ index b02a231..989322b 100644
  		engine->mc.init			= nv50_mc_init;
  		engine->mc.takedown		= nv50_mc_takedown;
  		engine->timer.init		= nv04_timer_init;
-@@ -300,6 +348,64 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -300,6 +344,64 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
  		engine->fifo.destroy_context	= nv50_fifo_destroy_context;
  		engine->fifo.load_context	= nv50_fifo_load_context;
  		engine->fifo.unload_context	= nv50_fifo_unload_context;
@@ -7323,7 +8908,58 @@ index b02a231..989322b 100644
  		break;
  	default:
  		NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
-@@ -407,11 +513,6 @@ nouveau_card_init(struct drm_device *dev)
+@@ -331,16 +433,14 @@ static int
+ nouveau_card_init_channel(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *gpuobj;
++	struct nouveau_gpuobj *gpuobj = NULL;
+ 	int ret;
+ 
+ 	ret = nouveau_channel_alloc(dev, &dev_priv->channel,
+-				    (struct drm_file *)-2,
+-				    NvDmaFB, NvDmaTT);
++				    (struct drm_file *)-2, NvDmaFB, NvDmaTT);
+ 	if (ret)
+ 		return ret;
+ 
+-	gpuobj = NULL;
+ 	ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
+ 				     0, dev_priv->vram_size,
+ 				     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
+@@ -348,26 +448,25 @@ nouveau_card_init_channel(struct drm_device *dev)
+ 	if (ret)
+ 		goto out_err;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
+-				     gpuobj, NULL);
++	ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj);
++	nouveau_gpuobj_ref(NULL, &gpuobj);
+ 	if (ret)
+ 		goto out_err;
+ 
+-	gpuobj = NULL;
+ 	ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
+ 					  dev_priv->gart_info.aper_size,
+ 					  NV_DMA_ACCESS_RW, &gpuobj, NULL);
+ 	if (ret)
+ 		goto out_err;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
+-				     gpuobj, NULL);
++	ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj);
++	nouveau_gpuobj_ref(NULL, &gpuobj);
+ 	if (ret)
+ 		goto out_err;
+ 
+ 	return 0;
++
+ out_err:
+-	nouveau_gpuobj_del(dev, &gpuobj);
+ 	nouveau_channel_free(dev_priv->channel);
+ 	dev_priv->channel = NULL;
+ 	return ret;
+@@ -407,11 +506,6 @@ nouveau_card_init(struct drm_device *dev)
  	struct nouveau_engine *engine;
  	int ret;
  
@@ -7335,7 +8971,7 @@ index b02a231..989322b 100644
  	vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
  	vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
  				       nouveau_switcheroo_can_switch);
-@@ -421,15 +522,17 @@ nouveau_card_init(struct drm_device *dev)
+@@ -421,50 +515,48 @@ nouveau_card_init(struct drm_device *dev)
  	if (ret)
  		goto out;
  	engine = &dev_priv->engine;
@@ -7357,17 +8993,47 @@ index b02a231..989322b 100644
 +	if (ret)
 +		goto out_display_early;
  
- 	ret = nouveau_mem_detect(dev);
+-	ret = nouveau_mem_detect(dev);
++	ret = nouveau_mem_vram_init(dev);
+ 	if (ret)
+ 		goto out_bios;
+ 
+-	ret = nouveau_gpuobj_early_init(dev);
++	ret = nouveau_gpuobj_init(dev);
  	if (ret)
-@@ -461,10 +564,15 @@ nouveau_card_init(struct drm_device *dev)
+-		goto out_bios;
++		goto out_vram;
+ 
+-	/* Initialise instance memory, must happen before mem_init so we
+-	 * know exactly how much VRAM we're able to use for "normal"
+-	 * purposes.
+-	 */
+ 	ret = engine->instmem.init(dev);
+ 	if (ret)
+-		goto out_gpuobj_early;
++		goto out_gpuobj;
+ 
+-	/* Setup the memory manager */
+-	ret = nouveau_mem_init(dev);
++	ret = nouveau_mem_gart_init(dev);
  	if (ret)
- 		goto out_gpuobj;
+ 		goto out_instmem;
  
+-	ret = nouveau_gpuobj_init(dev);
+-	if (ret)
+-		goto out_mem;
+-
+ 	/* PMC */
+ 	ret = engine->mc.init(dev);
+ 	if (ret)
+-		goto out_gpuobj;
++		goto out_gart;
++
 +	/* PGPIO */
 +	ret = engine->gpio.init(dev);
 +	if (ret)
 +		goto out_mc;
-+
+ 
  	/* PTIMER */
  	ret = engine->timer.init(dev);
  	if (ret)
@@ -7376,7 +9042,7 @@ index b02a231..989322b 100644
  
  	/* PFB */
  	ret = engine->fb.init(dev);
-@@ -485,12 +593,16 @@ nouveau_card_init(struct drm_device *dev)
+@@ -485,12 +577,16 @@ nouveau_card_init(struct drm_device *dev)
  			goto out_graph;
  	}
  
@@ -7394,7 +9060,7 @@ index b02a231..989322b 100644
  
  	ret = drm_vblank_init(dev, 0);
  	if (ret)
-@@ -504,35 +616,18 @@ nouveau_card_init(struct drm_device *dev)
+@@ -504,35 +600,18 @@ nouveau_card_init(struct drm_device *dev)
  			goto out_irq;
  	}
  
@@ -7434,7 +9100,7 @@ index b02a231..989322b 100644
  out_fifo:
  	if (!nouveau_noaccel)
  		engine->fifo.takedown(dev);
-@@ -543,6 +638,8 @@ out_fb:
+@@ -543,19 +622,22 @@ out_fb:
  	engine->fb.takedown(dev);
  out_timer:
  	engine->timer.takedown(dev);
@@ -7442,9 +9108,21 @@ index b02a231..989322b 100644
 +	engine->gpio.takedown(dev);
  out_mc:
  	engine->mc.takedown(dev);
- out_gpuobj:
-@@ -556,6 +653,8 @@ out_gpuobj_early:
- 	nouveau_gpuobj_late_takedown(dev);
+-out_gpuobj:
+-	nouveau_gpuobj_takedown(dev);
+-out_mem:
+-	nouveau_sgdma_takedown(dev);
+-	nouveau_mem_close(dev);
++out_gart:
++	nouveau_mem_gart_fini(dev);
+ out_instmem:
+ 	engine->instmem.takedown(dev);
+-out_gpuobj_early:
+-	nouveau_gpuobj_late_takedown(dev);
++out_gpuobj:
++	nouveau_gpuobj_takedown(dev);
++out_vram:
++	nouveau_mem_vram_fini(dev);
  out_bios:
  	nouveau_bios_takedown(dev);
 +out_display_early:
@@ -7452,22 +9130,22 @@ index b02a231..989322b 100644
  out:
  	vga_client_register(dev->pdev, NULL, NULL, NULL);
  	return ret;
-@@ -566,45 +665,39 @@ static void nouveau_card_takedown(struct drm_device *dev)
+@@ -566,45 +648,38 @@ static void nouveau_card_takedown(struct drm_device *dev)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_engine *engine = &dev_priv->engine;
  
 -	NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
 -
 -	if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
--
++	nouveau_backlight_exit(dev);
+ 
 -		nouveau_backlight_exit(dev);
 -
 -		if (dev_priv->channel) {
 -			nouveau_channel_free(dev_priv->channel);
 -			dev_priv->channel = NULL;
 -		}
-+	nouveau_backlight_exit(dev);
- 
+-
 -		if (!nouveau_noaccel) {
 -			engine->fifo.takedown(dev);
 -			engine->graph.takedown(dev);
@@ -7502,20 +9180,19 @@ index b02a231..989322b 100644
 +	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_sgdma_takedown(dev);
++	nouveau_mem_gart_fini(dev);
  
 -		if (drm_core_check_feature(dev, DRIVER_MODESET))
 -			drm_irq_uninstall(dev);
-+	nouveau_gpuobj_takedown(dev);
-+	nouveau_mem_close(dev);
 +	engine->instmem.takedown(dev);
++	nouveau_gpuobj_takedown(dev);
++	nouveau_mem_vram_fini(dev);
  
 -		nouveau_gpuobj_late_takedown(dev);
 -		nouveau_bios_takedown(dev);
 +	drm_irq_uninstall(dev);
  
 -		vga_client_register(dev->pdev, NULL, NULL, NULL);
-+	nouveau_gpuobj_late_takedown(dev);
 +	nouveau_bios_takedown(dev);
  
 -		dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
@@ -7524,7 +9201,7 @@ index b02a231..989322b 100644
  }
  
  /* here a client dies, release the stuff that was allocated for its
-@@ -691,22 +784,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -691,22 +766,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  	struct drm_nouveau_private *dev_priv;
  	uint32_t reg0;
  	resource_size_t mmio_start_offs;
@@ -7556,7 +9233,7 @@ index b02a231..989322b 100644
  
  	/* resource 0 is mmio regs */
  	/* resource 1 is linear FB */
-@@ -719,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -719,7 +798,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  	if (!dev_priv->mmio) {
  		NV_ERROR(dev, "Unable to initialize the mmio mapping. "
  			 "Please report your setup to " DRIVER_EMAIL "\n");
@@ -7566,7 +9243,7 @@ index b02a231..989322b 100644
  	}
  	NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
  					(unsigned long long)mmio_start_offs);
-@@ -765,19 +863,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -765,19 +845,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  	case 0xa0:
  		dev_priv->card_type = NV_50;
  		break;
@@ -7594,7 +9271,7 @@ index b02a231..989322b 100644
  
  	/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
  	if (dev_priv->card_type >= NV_40) {
-@@ -791,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -791,7 +873,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  				dev_priv->ramin_size);
  		if (!dev_priv->ramin) {
  			NV_ERROR(dev, "Failed to PRAMIN BAR");
@@ -7604,7 +9281,7 @@ index b02a231..989322b 100644
  		}
  	} else {
  		dev_priv->ramin_size = 1 * 1024 * 1024;
-@@ -799,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -799,7 +882,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  					  dev_priv->ramin_size);
  		if (!dev_priv->ramin) {
  			NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
@@ -7614,7 +9291,7 @@ index b02a231..989322b 100644
  		}
  	}
  
-@@ -812,46 +914,38 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+@@ -812,46 +896,38 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
  		dev_priv->flags |= NV_NFORCE2;
  
  	/* For kernel modesetting, init card now and bring up fbcon */
@@ -7680,7 +9357,7 @@ index b02a231..989322b 100644
  
  	iounmap(dev_priv->mmio);
  	iounmap(dev_priv->ramin);
-@@ -867,8 +961,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
+@@ -867,8 +943,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct drm_nouveau_getparam *getparam = data;
  
@@ -7689,7 +9366,7 @@ index b02a231..989322b 100644
  	switch (getparam->param) {
  	case NOUVEAU_GETPARAM_CHIPSET_ID:
  		getparam->value = dev_priv->chipset;
-@@ -937,8 +1029,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
+@@ -937,8 +1011,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
  {
  	struct drm_nouveau_setparam *setparam = data;
  
@@ -7698,6 +9375,15 @@ index b02a231..989322b 100644
  	switch (setparam->param) {
  	default:
  		NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
+@@ -967,7 +1039,7 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout,
+ /* Waits for PGRAPH to go completely idle */
+ bool nouveau_wait_for_idle(struct drm_device *dev)
+ {
+-	if (!nv_wait(NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
++	if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
+ 		NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
+ 			 nv_rd32(dev, NV04_PGRAPH_STATUS));
+ 		return false;
 diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
 index eba687f..291a4cb 100644
 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -8324,11 +10010,49 @@ index c7898b4..9e28cf7 100644
 +	return 0;
  }
  
+diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
+index 1eeac4f..33e4c93 100644
+--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
++++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
+@@ -25,6 +25,7 @@
+ #include "drmP.h"
+ #include "nouveau_drv.h"
+ #include "nouveau_dma.h"
++#include "nouveau_ramht.h"
+ #include "nouveau_fbcon.h"
+ 
+ void
+@@ -169,11 +170,9 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, handle, obj, NULL);
+-	if (ret)
+-		return ret;
+-
+-	return 0;
++	ret = nouveau_ramht_insert(dev_priv->channel, handle, obj);
++	nouveau_gpuobj_ref(NULL, &obj);
++	return ret;
+ }
+ 
+ int
 diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
-index 66fe559..bbb87ef 100644
+index 66fe559..708293b 100644
 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c
 +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
-@@ -38,10 +38,10 @@
+@@ -27,8 +27,9 @@
+ #include "drmP.h"
+ #include "drm.h"
+ #include "nouveau_drv.h"
++#include "nouveau_ramht.h"
+ 
+-#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
++#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
+ #define NV04_RAMFC__SIZE 32
+ #define NV04_RAMFC_DMA_PUT                                       0x00
+ #define NV04_RAMFC_DMA_GET                                       0x04
+@@ -38,10 +39,8 @@
  #define NV04_RAMFC_ENGINE                                        0x14
  #define NV04_RAMFC_PULL1_ENGINE                                  0x18
  
@@ -8336,14 +10060,70 @@ index 66fe559..bbb87ef 100644
 -					 NV04_RAMFC_##offset/4, (val))
 -#define RAMFC_RD(offset)      nv_ro32(dev, chan->ramfc->gpuobj, \
 -					 NV04_RAMFC_##offset/4)
-+#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc->gpuobj, \
-+				      NV04_RAMFC_##offset, (val))
-+#define RAMFC_RD(offset)      nv_ro32(chan->ramfc->gpuobj, \
-+				      NV04_RAMFC_##offset)
++#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val))
++#define RAMFC_RD(offset)      nv_ro32(chan->ramfc, NV04_RAMFC_##offset)
  
  void
  nv04_fifo_disable(struct drm_device *dev)
-@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
+@@ -72,37 +71,32 @@ nv04_fifo_reassign(struct drm_device *dev, bool enable)
+ }
+ 
+ bool
+-nv04_fifo_cache_flush(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+-	uint64_t start = ptimer->read(dev);
+-
+-	do {
+-		if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) ==
+-		    nv_rd32(dev, NV03_PFIFO_CACHE1_PUT))
+-			return true;
+-
+-	} while (ptimer->read(dev) - start < 100000000);
+-
+-	NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n");
+-
+-	return false;
+-}
+-
+-bool
+ nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
+ {
+-	uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0);
++	int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
++
++	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_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
++		    NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
++			nv_wr32(dev, NV03_PFIFO_INTR_0,
++				NV_PFIFO_INTR_CACHE_ERROR);
+ 
+-	if (enable) {
+-		nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1);
+-	} else {
+-		nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1);
+ 		nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
+ 	}
+ 
+-	return !!(pull & 1);
++	return pull & 1;
+ }
+ 
+ int
+@@ -112,6 +106,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
  			NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
  }
  
@@ -8356,14 +10136,23 @@ index 66fe559..bbb87ef 100644
  int
  nv04_fifo_create_context(struct nouveau_channel *chan)
  {
-@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
+@@ -124,25 +124,20 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
+ 						NV04_RAMFC__SIZE,
+ 						NVOBJ_FLAG_ZERO_ALLOC |
+ 						NVOBJ_FLAG_ZERO_FREE,
+-						NULL, &chan->ramfc);
++						&chan->ramfc);
+ 	if (ret)
+ 		return ret;
+ 
  	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
  
  	/* Setup initial state */
 -	dev_priv->engine.instmem.prepare_access(dev, true);
  	RAMFC_WR(DMA_PUT, chan->pushbuf_base);
  	RAMFC_WR(DMA_GET, chan->pushbuf_base);
- 	RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
+-	RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
++	RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4);
  	RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
  			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
  			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -8376,7 +10165,16 @@ index 66fe559..bbb87ef 100644
  
  	/* enable the fifo dma operation */
  	nv_wr32(dev, NV04_PFIFO_MODE,
-@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
+@@ -160,7 +155,7 @@ nv04_fifo_destroy_context(struct nouveau_channel *chan)
+ 	nv_wr32(dev, NV04_PFIFO_MODE,
+ 		nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
+ 
+-	nouveau_gpuobj_ref_del(dev, &chan->ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->ramfc);
+ }
+ 
+ static void
+@@ -169,8 +164,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	uint32_t fc = NV04_RAMFC(chid), tmp;
  
@@ -8385,7 +10183,7 @@ index 66fe559..bbb87ef 100644
  	nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
  	nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
  	tmp = nv_ri32(dev, fc + 8);
-@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
+@@ -181,8 +174,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
  	nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
  	nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
  
@@ -8394,7 +10192,7 @@ index 66fe559..bbb87ef 100644
  	nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
  }
-@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
+@@ -223,7 +214,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
  		return -EINVAL;
  	}
  
@@ -8402,7 +10200,7 @@ index 66fe559..bbb87ef 100644
  	RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
  	RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
  	tmp  = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
-@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
+@@ -233,7 +223,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
  	RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
  	RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
  	RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
@@ -8410,7 +10208,22 @@ index 66fe559..bbb87ef 100644
  
  	nv04_fifo_do_load_context(dev, pfifo->channels - 1);
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
-@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev)
+@@ -269,10 +258,10 @@ nv04_fifo_init_ramxx(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 
+ 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+-				       ((dev_priv->ramht_bits - 9) << 16) |
+-				       (dev_priv->ramht_offset >> 8));
+-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+-	nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
++				       ((dev_priv->ramht->bits - 9) << 16) |
++				       (dev_priv->ramht->gpuobj->pinst >> 8));
++	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
++	nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
+ }
+ 
+ static void
+@@ -297,6 +286,7 @@ nv04_fifo_init(struct drm_device *dev)
  
  	nv04_fifo_init_intr(dev);
  	pfifo->enable(dev);
@@ -8442,30 +10255,158 @@ index 618355e..c897342 100644
  }
  
 diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
-index a3b9563..4408232 100644
+index a3b9563..0b5ae29 100644
 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c
 +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
-@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev)
- 	NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
+@@ -1,6 +1,7 @@
+ #include "drmP.h"
+ #include "drm.h"
+ #include "nouveau_drv.h"
++#include "nouveau_ramht.h"
+ 
+ /* returns the size of fifo context */
+ static int
+@@ -17,104 +18,51 @@ nouveau_fifo_ctx_size(struct drm_device *dev)
+ 	return 32;
+ }
  
- 	/* Clear all of it, except the BIOS image that's in the first 64KiB */
+-static void
+-nv04_instmem_determine_amount(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	int i;
+-
+-	/* Figure out how much instance memory we need */
+-	if (dev_priv->card_type >= NV_40) {
+-		/* We'll want more instance memory than this on some NV4x cards.
+-		 * There's a 16MB aperture to play with that maps onto the end
+-		 * of vram.  For now, only reserve a small piece until we know
+-		 * more about what each chipset requires.
+-		 */
+-		switch (dev_priv->chipset) {
+-		case 0x40:
+-		case 0x47:
+-		case 0x49:
+-		case 0x4b:
+-			dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
+-			break;
+-		default:
+-			dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
+-			break;
+-		}
+-	} else {
+-		/*XXX: what *are* the limits on <NV40 cards?
+-		 */
+-		dev_priv->ramin_rsvd_vram = (512 * 1024);
+-	}
+-	NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
+-
+-	/* Clear all of it, except the BIOS image that's in the first 64KiB */
 -	dev_priv->engine.instmem.prepare_access(dev, true);
- 	for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
- 		nv_wi32(dev, i, 0x00000000);
+-	for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
+-		nv_wi32(dev, i, 0x00000000);
 -	dev_priv->engine.instmem.finish_access(dev);
- }
+-}
+-
+-static void
+-nv04_instmem_configure_fixed_tables(struct drm_device *dev)
++int nv04_instmem_init(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_engine *engine = &dev_priv->engine;
+-
+-	/* FIFO hash table (RAMHT)
+-	 *   use 4k hash table at RAMIN+0x10000
+-	 *   TODO: extend the hash table
+-	 */
+-	dev_priv->ramht_offset = 0x10000;
+-	dev_priv->ramht_bits   = 9;
+-	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits); /* nr entries */
+-	dev_priv->ramht_size  *= 8; /* 2 32-bit values per entry in RAMHT */
+-	NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
+-						      dev_priv->ramht_size);
+-
+-	/* FIFO runout table (RAMRO) - 512k at 0x11200 */
+-	dev_priv->ramro_offset = 0x11200;
+-	dev_priv->ramro_size   = 512;
+-	NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
+-						      dev_priv->ramro_size);
+-
+-	/* FIFO context table (RAMFC)
+-	 *   NV40  : Not sure exactly how to position RAMFC on some cards,
+-	 *           0x30002 seems to position it at RAMIN+0x20000 on these
+-	 *           cards.  RAMFC is 4kb (32 fifos, 128byte entries).
+-	 *   Others: Position RAMFC at RAMIN+0x11400
+-	 */
+-	dev_priv->ramfc_size = engine->fifo.channels *
+-						nouveau_fifo_ctx_size(dev);
++	struct nouveau_gpuobj *ramht = NULL;
++	u32 offset, length;
++	int ret;
++
++	/* RAMIN always available */
++	dev_priv->ramin_available = true;
++
++	/* Setup shared RAMHT */
++	ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096,
++				      NVOBJ_FLAG_ZERO_ALLOC, &ramht);
++	if (ret)
++		return ret;
++
++	ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht);
++	nouveau_gpuobj_ref(NULL, &ramht);
++	if (ret)
++		return ret;
++
++	/* And RAMRO */
++	ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512,
++				      NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro);
++	if (ret)
++		return ret;
++
++	/* And RAMFC */
++	length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev);
+ 	switch (dev_priv->card_type) {
+ 	case NV_40:
+-		dev_priv->ramfc_offset = 0x20000;
++		offset = 0x20000;
+ 		break;
+-	case NV_30:
+-	case NV_20:
+-	case NV_10:
+-	case NV_04:
+ 	default:
+-		dev_priv->ramfc_offset = 0x11400;
++		offset = 0x11400;
+ 		break;
+ 	}
+-	NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
+-						      dev_priv->ramfc_size);
+-}
  
- static void
-@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev)
- {
- 	struct drm_nouveau_private *dev_priv = dev->dev_private;
- 	uint32_t offset;
+-int nv04_instmem_init(struct drm_device *dev)
+-{
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	uint32_t offset;
 -	int ret = 0;
-+	int ret;
++	ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length,
++				      NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc);
++	if (ret)
++		return ret;
+ 
+-	nv04_instmem_determine_amount(dev);
+-	nv04_instmem_configure_fixed_tables(dev);
+-
+-	/* Create a heap to manage RAMIN allocations, we don't allocate
+-	 * the space that was reserved for RAMHT/FC/RO.
+-	 */
+-	offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
++	/* Only allow space after RAMFC to be used for object allocation */
++	offset += length;
  
- 	nv04_instmem_determine_amount(dev);
- 	nv04_instmem_configure_fixed_tables(dev);
-@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev)
+ 	/* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
+ 	 * on certain NV4x chipsets as well as RAMFC.  When 0x2230 == 0
+@@ -129,69 +77,52 @@ int nv04_instmem_init(struct drm_device *dev)
  			offset = 0x40000;
  	}
  
@@ -8485,7 +10426,56 @@ index a3b9563..4408232 100644
  }
  
  void
-@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ nv04_instmem_takedown(struct drm_device *dev)
+ {
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
++	nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
++	nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+ }
+ 
+ int
+-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
++nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
++		      uint32_t *sz)
+ {
+-	if (gpuobj->im_backing)
+-		return -EINVAL;
+-
+ 	return 0;
+ }
+ 
+ void
+ nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ {
+-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-
+-	if (gpuobj && gpuobj->im_backing) {
+-		if (gpuobj->im_bound)
+-			dev_priv->engine.instmem.unbind(dev, gpuobj);
+-		gpuobj->im_backing = NULL;
+-	}
+ }
+ 
+ int
+ nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ {
+-	if (!gpuobj->im_pramin || gpuobj->im_bound)
+-		return -EINVAL;
+-
+-	gpuobj->im_bound = 1;
+ 	return 0;
+ }
+ 
+ int
+ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ {
+-	if (gpuobj->im_bound == 0)
+-		return -EINVAL;
+-
+-	gpuobj->im_bound = 0;
+ 	return 0;
  }
  
  void
@@ -8734,18 +10724,41 @@ index c4e3404..0b5d012 100644
  	return ret;
  }
 diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
-index 7aeabf2..7a4069c 100644
+index 7aeabf2..f1b03ad 100644
 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c
 +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
-@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
+@@ -27,8 +27,9 @@
+ #include "drmP.h"
+ #include "drm.h"
+ #include "nouveau_drv.h"
++#include "nouveau_ramht.h"
+ 
+-#define NV10_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE))
++#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE))
+ #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
+ 
+ int
+@@ -48,17 +49,16 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
+ 
+ 	ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0,
+ 				      NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
+-				      NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
++				      NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
+ 	if (ret)
+ 		return ret;
+ 
  	/* Fill entries that are seen filled in dumps of nvidia driver just
  	 * after channel's is put into DMA mode
  	 */
 -	dev_priv->engine.instmem.prepare_access(dev, true);
  	nv_wi32(dev, fc +  0, chan->pushbuf_base);
  	nv_wi32(dev, fc +  4, chan->pushbuf_base);
- 	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
-@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
+-	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
++	nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
+ 	nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ 			      NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+ 			      NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+@@ -66,7 +66,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
  			      NV_PFIFO_CACHE1_BIG_ENDIAN |
  #endif
  			      0);
@@ -8753,7 +10766,16 @@ index 7aeabf2..7a4069c 100644
  
  	/* enable the fifo dma operation */
  	nv_wr32(dev, NV04_PFIFO_MODE,
-@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
+@@ -82,7 +81,7 @@ nv10_fifo_destroy_context(struct nouveau_channel *chan)
+ 	nv_wr32(dev, NV04_PFIFO_MODE,
+ 			nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
+ 
+-	nouveau_gpuobj_ref_del(dev, &chan->ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->ramfc);
+ }
+ 
+ static void
+@@ -91,8 +90,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	uint32_t fc = NV10_RAMFC(chid), tmp;
  
@@ -8762,7 +10784,7 @@ index 7aeabf2..7a4069c 100644
  	nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
  	nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
  	nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
-@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
+@@ -117,8 +114,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
  	nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
  
  out:
@@ -8771,7 +10793,7 @@ index 7aeabf2..7a4069c 100644
  	nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
  }
-@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
+@@ -155,8 +150,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
  		return 0;
  	fc = NV10_RAMFC(chid);
  
@@ -8780,7 +10802,7 @@ index 7aeabf2..7a4069c 100644
  	nv_wi32(dev, fc +  0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
  	nv_wi32(dev, fc +  4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
  	nv_wi32(dev, fc +  8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
-@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
+@@ -179,8 +172,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
  	nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
  
  out:
@@ -8789,6 +10811,26 @@ index 7aeabf2..7a4069c 100644
  	nv10_fifo_do_load_context(dev, pfifo->channels - 1);
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
  	return 0;
+@@ -212,14 +203,14 @@ nv10_fifo_init_ramxx(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 
+ 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+-				       ((dev_priv->ramht_bits - 9) << 16) |
+-				       (dev_priv->ramht_offset >> 8));
+-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
++				       ((dev_priv->ramht->bits - 9) << 16) |
++				       (dev_priv->ramht->gpuobj->pinst >> 8));
++	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+ 
+ 	if (dev_priv->chipset < 0x17) {
+-		nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
++		nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
+ 	} else {
+-		nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc_offset >> 8) |
++		nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) |
+ 					       (1 << 16) /* 64 Bytes entry*/);
+ 		/* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */
+ 	}
 diff --git a/drivers/gpu/drm/nouveau/nv10_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c
 new file mode 100644
 index 0000000..007fc29
@@ -9193,7 +11235,7 @@ index 2e58c33..0000000
 -	return 0;
 -}
 diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
-index 74c8803..703c188 100644
+index 74c8803..a3b8861 100644
 --- a/drivers/gpu/drm/nouveau/nv17_tv.c
 +++ b/drivers/gpu/drm/nouveau/nv17_tv.c
 @@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
@@ -9297,7 +11339,149 @@ index 74c8803..703c188 100644
  		NV_INFO(dev, "Load detected on output %c\n",
  			'@' + ffs(dcb->or));
  		return connector_status_connected;
-@@ -296,6 +326,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
+@@ -163,55 +193,56 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
+ 	}
+ }
+ 
+-static const struct {
+-	int hdisplay;
+-	int vdisplay;
+-} modes[] = {
+-	{ 640, 400 },
+-	{ 640, 480 },
+-	{ 720, 480 },
+-	{ 720, 576 },
+-	{ 800, 600 },
+-	{ 1024, 768 },
+-	{ 1280, 720 },
+-	{ 1280, 1024 },
+-	{ 1920, 1080 }
+-};
+-
+-static int nv17_tv_get_modes(struct drm_encoder *encoder,
+-			     struct drm_connector *connector)
++static int nv17_tv_get_ld_modes(struct drm_encoder *encoder,
++				struct drm_connector *connector)
+ {
+ 	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+-	struct drm_display_mode *mode;
+-	struct drm_display_mode *output_mode;
++	struct drm_display_mode *mode, *tv_mode;
+ 	int n = 0;
+-	int i;
+ 
+-	if (tv_norm->kind != CTV_ENC_MODE) {
+-		struct drm_display_mode *tv_mode;
++	for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
++		mode = drm_mode_duplicate(encoder->dev, tv_mode);
+ 
+-		for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
+-			mode = drm_mode_duplicate(encoder->dev, tv_mode);
++		mode->clock = tv_norm->tv_enc_mode.vrefresh *
++			mode->htotal / 1000 *
++			mode->vtotal / 1000;
+ 
+-			mode->clock = tv_norm->tv_enc_mode.vrefresh *
+-						mode->htotal / 1000 *
+-						mode->vtotal / 1000;
+-
+-			if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+-				mode->clock *= 2;
++		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
++			mode->clock *= 2;
+ 
+-			if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
+-			    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
+-				mode->type |= DRM_MODE_TYPE_PREFERRED;
++		if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
++		    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
++			mode->type |= DRM_MODE_TYPE_PREFERRED;
+ 
+-			drm_mode_probed_add(connector, mode);
+-			n++;
+-		}
+-		return n;
++		drm_mode_probed_add(connector, mode);
++		n++;
+ 	}
+ 
+-	/* tv_norm->kind == CTV_ENC_MODE */
+-	output_mode = &tv_norm->ctv_enc_mode.mode;
++	return n;
++}
++
++static int nv17_tv_get_hd_modes(struct drm_encoder *encoder,
++				struct drm_connector *connector)
++{
++	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
++	struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;
++	struct drm_display_mode *mode;
++	const struct {
++		int hdisplay;
++		int vdisplay;
++	} modes[] = {
++		{ 640, 400 },
++		{ 640, 480 },
++		{ 720, 480 },
++		{ 720, 576 },
++		{ 800, 600 },
++		{ 1024, 768 },
++		{ 1280, 720 },
++		{ 1280, 1024 },
++		{ 1920, 1080 }
++	};
++	int i, n = 0;
++
+ 	for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ 		if (modes[i].hdisplay > output_mode->hdisplay ||
+ 		    modes[i].vdisplay > output_mode->vdisplay)
+@@ -221,11 +252,12 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
+ 		    modes[i].vdisplay == output_mode->vdisplay) {
+ 			mode = drm_mode_duplicate(encoder->dev, output_mode);
+ 			mode->type |= DRM_MODE_TYPE_PREFERRED;
++
+ 		} else {
+ 			mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,
+-				modes[i].vdisplay, 60, false,
+-				output_mode->flags & DRM_MODE_FLAG_INTERLACE,
+-				false);
++					    modes[i].vdisplay, 60, false,
++					    (output_mode->flags &
++					     DRM_MODE_FLAG_INTERLACE), false);
+ 		}
+ 
+ 		/* CVT modes are sometimes unsuitable... */
+@@ -236,6 +268,7 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
+ 					     - mode->hdisplay) * 9 / 10) & ~7;
+ 			mode->hsync_end = mode->hsync_start + 8;
+ 		}
++
+ 		if (output_mode->vdisplay >= 1024) {
+ 			mode->vtotal = output_mode->vtotal;
+ 			mode->vsync_start = output_mode->vsync_start;
+@@ -246,9 +279,21 @@ static int nv17_tv_get_modes(struct drm_encoder *encoder,
+ 		drm_mode_probed_add(connector, mode);
+ 		n++;
+ 	}
++
+ 	return n;
+ }
+ 
++static int nv17_tv_get_modes(struct drm_encoder *encoder,
++			     struct drm_connector *connector)
++{
++	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
++
++	if (tv_norm->kind == CTV_ENC_MODE)
++		return nv17_tv_get_hd_modes(encoder, connector);
++	else
++		return nv17_tv_get_ld_modes(encoder, connector);
++}
++
+ static int nv17_tv_mode_valid(struct drm_encoder *encoder,
+ 			      struct drm_display_mode *mode)
+ {
+@@ -296,6 +341,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
  {
  	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
  
@@ -9307,7 +11491,7 @@ index 74c8803..703c188 100644
  	if (tv_norm->kind == CTV_ENC_MODE)
  		adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
  	else
-@@ -307,6 +340,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
+@@ -307,6 +355,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
  static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
  {
  	struct drm_device *dev = encoder->dev;
@@ -9316,7 +11500,7 @@ index 74c8803..703c188 100644
  	struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
  	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
  
-@@ -331,8 +366,8 @@ static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
+@@ -331,8 +381,8 @@ static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
  
  	nv_load_ptv(dev, regs, 200);
  
@@ -9327,7 +11511,7 @@ index 74c8803..703c188 100644
  
  	nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
  }
-@@ -373,15 +408,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
+@@ -373,15 +423,10 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
  
  	}
  
@@ -9347,7 +11531,7 @@ index 74c8803..703c188 100644
  
  	/* Set the DACCLK register */
  	dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
-@@ -744,8 +774,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = {
+@@ -744,8 +789,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = {
  	.destroy = nv17_tv_destroy,
  };
  
@@ -9359,7 +11543,7 @@ index 74c8803..703c188 100644
  	struct drm_encoder *encoder;
  	struct nv17_tv_encoder *tv_enc = NULL;
  
-@@ -774,5 +806,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
+@@ -774,5 +821,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
  	encoder->possible_crtcs = entry->heads;
  	encoder->possible_clones = 0;
  
@@ -9367,8 +11551,142 @@ index 74c8803..703c188 100644
 +	drm_mode_connector_attach_encoder(connector, encoder);
  	return 0;
  }
+diff --git a/drivers/gpu/drm/nouveau/nv17_tv.h b/drivers/gpu/drm/nouveau/nv17_tv.h
+index c00977c..6bf0384 100644
+--- a/drivers/gpu/drm/nouveau/nv17_tv.h
++++ b/drivers/gpu/drm/nouveau/nv17_tv.h
+@@ -127,7 +127,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder);
+ 
+ /* TV hardware access functions */
+ 
+-static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val)
++static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg,
++				uint32_t val)
+ {
+ 	nv_wr32(dev, reg, val);
+ }
+@@ -137,7 +138,8 @@ static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg)
+ 	return nv_rd32(dev, reg);
+ }
+ 
+-static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, uint8_t val)
++static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg,
++				   uint8_t val)
+ {
+ 	nv_write_ptv(dev, NV_PTV_TV_INDEX, reg);
+ 	nv_write_ptv(dev, NV_PTV_TV_DATA, val);
+@@ -149,8 +151,11 @@ static inline uint8_t nv_read_tv_enc(struct drm_device *dev, uint8_t reg)
+ 	return nv_read_ptv(dev, NV_PTV_TV_DATA);
+ }
+ 
+-#define nv_load_ptv(dev, state, reg) nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
+-#define nv_save_ptv(dev, state, reg) state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
+-#define nv_load_tv_enc(dev, state, reg) nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
++#define nv_load_ptv(dev, state, reg) \
++	nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
++#define nv_save_ptv(dev, state, reg) \
++	state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
++#define nv_load_tv_enc(dev, state, reg) \
++	nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
+ 
+ #endif
+diff --git a/drivers/gpu/drm/nouveau/nv17_tv_modes.c b/drivers/gpu/drm/nouveau/nv17_tv_modes.c
+index d64683d..9d3893c 100644
+--- a/drivers/gpu/drm/nouveau/nv17_tv_modes.c
++++ b/drivers/gpu/drm/nouveau/nv17_tv_modes.c
+@@ -336,12 +336,17 @@ static void tv_setup_filter(struct drm_encoder *encoder)
+ 			struct filter_params *p = &fparams[k][j];
+ 
+ 			for (i = 0; i < 7; i++) {
+-				int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + p->ki3*i*i*i)
+-					+ (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k]
+-					+ (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker
+-					+ (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k];
+-
+-				(*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9);
++				int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
++					     p->ki3*i*i*i)
++					+ (p->kr + p->kir*i + p->ki2r*i*i +
++					   p->ki3r*i*i*i) * rs[k]
++					+ (p->kf + p->kif*i + p->ki2f*i*i +
++					   p->ki3f*i*i*i) * flicker
++					+ (p->krf + p->kirf*i + p->ki2rf*i*i +
++					   p->ki3rf*i*i*i) * flicker * rs[k];
++
++				(*filters[k])[j][i] = (c + id5/2) >> 39
++					& (0x1 << 31 | 0x7f << 9);
+ 			}
+ 		}
+ 	}
+@@ -349,7 +354,8 @@ static void tv_setup_filter(struct drm_encoder *encoder)
+ 
+ /* Hardware state saving/restoring */
+ 
+-static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
++static void tv_save_filter(struct drm_device *dev, uint32_t base,
++			   uint32_t regs[4][7])
+ {
+ 	int i, j;
+ 	uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
+@@ -360,7 +366,8 @@ static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[
+ 	}
+ }
+ 
+-static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
++static void tv_load_filter(struct drm_device *dev, uint32_t base,
++			   uint32_t regs[4][7])
+ {
+ 	int i, j;
+ 	uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
+@@ -504,10 +511,10 @@ void nv17_tv_update_properties(struct drm_encoder *encoder)
+ 		break;
+ 	}
+ 
+-	regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255,
+-					 tv_enc->saturation);
+-	regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255,
+-					 tv_enc->saturation);
++	regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
++					 255, tv_enc->saturation);
++	regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
++					 255, tv_enc->saturation);
+ 	regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
+ 
+ 	nv_load_ptv(dev, regs, 204);
+@@ -541,7 +548,8 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
+ 	int head = nouveau_crtc(encoder->crtc)->index;
+ 	struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
+ 	struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
+-	struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode;
++	struct drm_display_mode *output_mode =
++		&get_tv_norm(encoder)->ctv_enc_mode.mode;
+ 	int overscan, hmargin, vmargin, hratio, vratio;
+ 
+ 	/* The rescaler doesn't do the right thing for interlaced modes. */
+@@ -553,13 +561,15 @@ void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
+ 	hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
+ 	vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
+ 
+-	hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin,
+-			      overscan);
+-	vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin,
+-			      overscan);
++	hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
++			      hmargin, overscan);
++	vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
++			      vmargin, overscan);
+ 
+-	hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin);
+-	vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3;
++	hratio = crtc_mode->hdisplay * 0x800 /
++		(output_mode->hdisplay - 2*hmargin);
++	vratio = crtc_mode->vdisplay * 0x800 /
++		(output_mode->vdisplay - 2*vmargin) & ~3;
+ 
+ 	regs->fp_horiz_regs[FP_VALID_START] = hmargin;
+ 	regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
 diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
-index d6fc0a8..cc876ef 100644
+index d6fc0a8..93f0d8a 100644
 --- a/drivers/gpu/drm/nouveau/nv20_graph.c
 +++ b/drivers/gpu/drm/nouveau/nv20_graph.c
 @@ -37,49 +37,49 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
@@ -9935,7 +12253,7 @@ index d6fc0a8..cc876ef 100644
  }
  
  int
-@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan)
+@@ -370,68 +370,52 @@ nv20_graph_create_context(struct nouveau_channel *chan)
  {
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -9989,48 +12307,66 @@ index d6fc0a8..cc876ef 100644
 -	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
 -					  NVOBJ_FLAG_ZERO_ALLOC,
 -					  &chan->ramin_grctx);
-+	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-+				     16, NVOBJ_FLAG_ZERO_ALLOC,
-+				     &chan->ramin_grctx);
++	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
++				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
  	if (ret)
  		return ret;
  
  	/* Initialise default context values */
 -	dev_priv->engine.instmem.prepare_access(dev, true);
- 	ctx_init(dev, chan->ramin_grctx->gpuobj);
+-	ctx_init(dev, chan->ramin_grctx->gpuobj);
++	ctx_init(dev, chan->ramin_grctx);
  
  	/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
 -	nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
 -					(chan->id << 24) | 0x1); /* CTX_USER */
-+	nv_wo32(chan->ramin_grctx->gpuobj, idoffs,
++	nv_wo32(chan->ramin_grctx, idoffs,
 +		(chan->id << 24) | 0x1); /* CTX_USER */
  
 -	nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
 -			chan->ramin_grctx->instance >> 4);
 -
 -	dev_priv->engine.instmem.finish_access(dev);
-+	nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4,
-+		chan->ramin_grctx->instance >> 4);
++	nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
  	return 0;
  }
  
-@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
+@@ -440,13 +424,10 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
  {
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
  
- 	if (chan->ramin_grctx)
- 		nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
- 
+-	if (chan->ramin_grctx)
+-		nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+-
 -	dev_priv->engine.instmem.prepare_access(dev, true);
 -	nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
 -	dev_priv->engine.instmem.finish_access(dev);
-+	nv_wo32(pgraph->ctx_table->gpuobj, chan->id * 4, 0);
++	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
++	nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
  }
  
  int
-@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+@@ -457,7 +438,7 @@ nv20_graph_load_context(struct nouveau_channel *chan)
+ 
+ 	if (!chan->ramin_grctx)
+ 		return -EINVAL;
+-	inst = chan->ramin_grctx->instance >> 4;
++	inst = chan->ramin_grctx->pinst >> 4;
+ 
+ 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+@@ -480,7 +461,7 @@ nv20_graph_unload_context(struct drm_device *dev)
+ 	chan = pgraph->channel(dev);
+ 	if (!chan)
+ 		return 0;
+-	inst = chan->ramin_grctx->instance >> 4;
++	inst = chan->ramin_grctx->pinst >> 4;
+ 
+ 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+@@ -538,29 +519,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
  int
  nv20_graph_init(struct drm_device *dev)
  {
@@ -10069,28 +12405,29 @@ index d6fc0a8..cc876ef 100644
 -		dev_priv->ctx_table_size = 32 * 4;
 -		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
 -						  dev_priv->ctx_table_size, 16,
-+		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
- 						  NVOBJ_FLAG_ZERO_ALLOC,
+-						  NVOBJ_FLAG_ZERO_ALLOC,
 -						  &dev_priv->ctx_table);
-+						  &pgraph->ctx_table);
++		ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
++					 NVOBJ_FLAG_ZERO_ALLOC,
++					 &pgraph->ctx_table);
  		if (ret)
  			return ret;
  	}
  
  	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
 -		 dev_priv->ctx_table->instance >> 4);
-+		     pgraph->ctx_table->instance >> 4);
++		     pgraph->ctx_table->pinst >> 4);
  
  	nv20_graph_rdi(dev);
  
-@@ -644,34 +644,52 @@ void
+@@ -644,34 +640,52 @@ void
  nv20_graph_takedown(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
  
 -	nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table);
-+	nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
++	nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
  }
  
  int
@@ -10129,17 +12466,18 @@ index d6fc0a8..cc876ef 100644
 -		dev_priv->ctx_table_size = 32 * 4;
 -		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
 -						  dev_priv->ctx_table_size, 16,
-+		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
- 						  NVOBJ_FLAG_ZERO_ALLOC,
+-						  NVOBJ_FLAG_ZERO_ALLOC,
 -						  &dev_priv->ctx_table);
-+						  &pgraph->ctx_table);
++		ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
++					 NVOBJ_FLAG_ZERO_ALLOC,
++					 &pgraph->ctx_table);
  		if (ret)
  			return ret;
  	}
  
  	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
 -			dev_priv->ctx_table->instance >> 4);
-+		     pgraph->ctx_table->instance >> 4);
++		     pgraph->ctx_table->pinst >> 4);
  
  	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
  	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -10245,25 +12583,60 @@ index 0000000..4a3f2f0
 +{
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
-index 500ccfd..2b67f18 100644
+index 500ccfd..d337b8b 100644
 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c
 +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
-@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
+@@ -27,8 +27,9 @@
+ #include "drmP.h"
+ #include "nouveau_drv.h"
+ #include "nouveau_drm.h"
++#include "nouveau_ramht.h"
+ 
+-#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE))
++#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE))
+ #define NV40_RAMFC__SIZE 128
+ 
+ int
+@@ -42,16 +43,15 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
+ 
+ 	ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
+ 				      NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
+-				      NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
++				      NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
+ 	if (ret)
+ 		return ret;
  
  	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
  
 -	dev_priv->engine.instmem.prepare_access(dev, true);
  	nv_wi32(dev, fc +  0, chan->pushbuf_base);
  	nv_wi32(dev, fc +  4, chan->pushbuf_base);
- 	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
-@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
+-	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
++	nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
+ 	nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ 			      NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+ 			      NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+@@ -59,9 +59,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
+ 			      NV_PFIFO_CACHE1_BIG_ENDIAN |
+ #endif
  			      0x30000000 /* no idea.. */);
- 	nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
+-	nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
++	nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4);
  	nv_wi32(dev, fc + 60, 0x0001FFFF);
 -	dev_priv->engine.instmem.finish_access(dev);
  
  	/* enable the fifo dma operation */
  	nv_wr32(dev, NV04_PFIFO_MODE,
+@@ -79,8 +78,7 @@ nv40_fifo_destroy_context(struct nouveau_channel *chan)
+ 	nv_wr32(dev, NV04_PFIFO_MODE,
+ 		nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
+ 
+-	if (chan->ramfc)
+-		nouveau_gpuobj_ref_del(dev, &chan->ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->ramfc);
+ }
+ 
+ static void
 @@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
@@ -10298,19 +12671,54 @@ index 500ccfd..2b67f18 100644
  
  	nv40_fifo_do_load_context(dev, pfifo->channels - 1);
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
+@@ -249,9 +241,9 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 
+ 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+-				       ((dev_priv->ramht_bits - 9) << 16) |
+-				       (dev_priv->ramht_offset >> 8));
+-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
++				       ((dev_priv->ramht->bits - 9) << 16) |
++				       (dev_priv->ramht->gpuobj->pinst >> 8));
++	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+ 
+ 	switch (dev_priv->chipset) {
+ 	case 0x47:
+@@ -279,7 +271,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
+ 		nv_wr32(dev, 0x2230, 0);
+ 		nv_wr32(dev, NV40_PFIFO_RAMFC,
+ 			((dev_priv->vram_size - 512 * 1024 +
+-			  dev_priv->ramfc_offset) >> 16) | (3 << 16));
++			  dev_priv->ramfc->pinst) >> 16) | (3 << 16));
+ 		break;
+ 	}
+ }
 diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
-index 704a25d..f7b59ad 100644
+index 704a25d..2424289 100644
 --- a/drivers/gpu/drm/nouveau/nv40_graph.c
 +++ b/drivers/gpu/drm/nouveau/nv40_graph.c
-@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
+@@ -45,7 +45,7 @@ nv40_graph_channel(struct drm_device *dev)
+ 		struct nouveau_channel *chan = dev_priv->fifos[i];
+ 
+ 		if (chan && chan->ramin_grctx &&
+-		    chan->ramin_grctx->instance == inst)
++		    chan->ramin_grctx->pinst == inst)
+ 			return chan;
+ 	}
+ 
+@@ -58,36 +58,28 @@ nv40_graph_create_context(struct nouveau_channel *chan)
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 +	struct nouveau_grctx ctx = {};
  	int ret;
  
- 	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan)
+-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+-				     16, NVOBJ_FLAG_ZERO_ALLOC,
+-				     &chan->ramin_grctx);
++	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
++				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+ 	if (ret)
  		return ret;
  
  	/* Initialise default context values */
@@ -10330,15 +12738,31 @@ index 704a25d..f7b59ad 100644
 -	dev_priv->engine.instmem.finish_access(dev);
 +	ctx.dev = chan->dev;
 +	ctx.mode = NOUVEAU_GRCTX_VALS;
-+	ctx.data = chan->ramin_grctx->gpuobj;
++	ctx.data = chan->ramin_grctx;
 +	nv40_grctx_init(&ctx);
 +
-+	nv_wo32(chan->ramin_grctx->gpuobj, 0,
-+		chan->ramin_grctx->gpuobj->im_pramin->start);
++	nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
  	return 0;
  }
  
-@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev)
+ void
+ nv40_graph_destroy_context(struct nouveau_channel *chan)
+ {
+-	nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx);
++	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ }
+ 
+ static int
+@@ -141,7 +133,7 @@ nv40_graph_load_context(struct nouveau_channel *chan)
+ 
+ 	if (!chan->ramin_grctx)
+ 		return -EINVAL;
+-	inst = chan->ramin_grctx->instance >> 4;
++	inst = chan->ramin_grctx->pinst >> 4;
+ 
+ 	ret = nv40_graph_transfer_context(dev, inst, 0);
+ 	if (ret)
+@@ -238,7 +230,8 @@ nv40_graph_init(struct drm_device *dev)
  	struct drm_nouveau_private *dev_priv =
  		(struct drm_nouveau_private *)dev->dev_private;
  	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
@@ -10348,7 +12772,7 @@ index 704a25d..f7b59ad 100644
  	int i, j;
  
  	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev)
+@@ -246,32 +239,22 @@ nv40_graph_init(struct drm_device *dev)
  	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
  			 NV_PMC_ENABLE_PGRAPH);
  
@@ -10394,7 +12818,7 @@ index 704a25d..f7b59ad 100644
  
  	/* No context present currently */
  	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
-@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev)
+@@ -407,7 +390,6 @@ nv40_graph_init(struct drm_device *dev)
  
  void nv40_graph_takedown(struct drm_device *dev)
  {
@@ -10568,8 +12992,21 @@ index b4e4a3b..2423c92 100644
  }
  
  static bool
+diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
+index 03ad7ab..1b9ce30 100644
+--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
++++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
+@@ -147,7 +147,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
+ 	NV_DEBUG_KMS(dev, "\n");
+ 
+ 	nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
+-	if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
++	if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
+ 		     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
+ 		NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+ 		NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
 diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
-index 1fd9537..1bc0859 100644
+index 1fd9537..875414b 100644
 --- a/drivers/gpu/drm/nouveau/nv50_dac.c
 +++ b/drivers/gpu/drm/nouveau/nv50_dac.c
 @@ -37,22 +37,31 @@
@@ -10608,6 +13045,24 @@ index 1fd9537..1bc0859 100644
  }
  
  static enum drm_connector_status
+@@ -70,7 +79,7 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
+ 
+ 	nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ 		0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
+-	if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
++	if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ 		     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
+ 		NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ 		NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
+@@ -121,7 +130,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
+ 	NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+ 
+ 	/* wait for it to be done */
+-	if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
++	if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+ 		     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
+ 		NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ 		NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
 @@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
  	uint32_t mode_ctl = 0, mode_ctl2 = 0;
  	int ret;
@@ -10679,10 +13134,33 @@ index 1fd9537..1bc0859 100644
  }
  
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
-index 580a5d1..435d2b7 100644
+index 580a5d1..11d366a 100644
 --- a/drivers/gpu/drm/nouveau/nv50_display.c
 +++ b/drivers/gpu/drm/nouveau/nv50_display.c
-@@ -42,6 +42,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan)
+@@ -30,8 +30,22 @@
+ #include "nouveau_connector.h"
+ #include "nouveau_fb.h"
+ #include "nouveau_fbcon.h"
++#include "nouveau_ramht.h"
+ #include "drm_crtc_helper.h"
+ 
++static inline int
++nv50_sor_nr(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	if (dev_priv->chipset  < 0x90 ||
++	    dev_priv->chipset == 0x92 ||
++	    dev_priv->chipset == 0xa0)
++		return 2;
++
++	return 4;
++}
++
+ static void
+ nv50_evo_channel_del(struct nouveau_channel **pchan)
+ {
+@@ -42,6 +56,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan)
  	*pchan = NULL;
  
  	nouveau_gpuobj_channel_takedown(chan);
@@ -10690,18 +13168,11 @@ index 580a5d1..435d2b7 100644
  	nouveau_bo_ref(NULL, &chan->pushbuf_bo);
  
  	if (chan->user)
-@@ -71,14 +72,16 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
+@@ -65,21 +80,23 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
  		return ret;
- 	}
+ 	obj->engine = NVOBJ_ENGINE_DISPLAY;
  
--	dev_priv->engine.instmem.prepare_access(dev, true);
--	nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
--	nv_wo32(dev, obj, 1, limit);
--	nv_wo32(dev, obj, 2, offset);
--	nv_wo32(dev, obj, 3, 0x00000000);
--	nv_wo32(dev, obj, 4, 0x00000000);
--	nv_wo32(dev, obj, 5, 0x00010000);
--	dev_priv->engine.instmem.finish_access(dev);
+-	ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL);
 +	nv_wo32(obj,  0, (tile_flags << 22) | (magic_flags << 16) | class);
 +	nv_wo32(obj,  4, limit);
 +	nv_wo32(obj,  8, offset);
@@ -10712,21 +13183,79 @@ index 580a5d1..435d2b7 100644
 +	else
 +		nv_wo32(obj, 20, 0x00020000);
 +	dev_priv->engine.instmem.flush(dev);
++
++	ret = nouveau_ramht_insert(evo, name, obj);
++	nouveau_gpuobj_ref(NULL, &obj);
+ 	if (ret) {
+-		nouveau_gpuobj_del(dev, &obj);
+ 		return ret;
+ 	}
  
+-	dev_priv->engine.instmem.prepare_access(dev, true);
+-	nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
+-	nv_wo32(dev, obj, 1, limit);
+-	nv_wo32(dev, obj, 2, offset);
+-	nv_wo32(dev, obj, 3, 0x00000000);
+-	nv_wo32(dev, obj, 4, 0x00000000);
+-	nv_wo32(dev, obj, 5, 0x00010000);
+-	dev_priv->engine.instmem.finish_access(dev);
+-
  	return 0;
  }
-@@ -110,8 +113,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
+ 
+@@ -87,6 +104,7 @@ static int
+ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nouveau_gpuobj *ramht = NULL;
+ 	struct nouveau_channel *chan;
+ 	int ret;
+ 
+@@ -100,32 +118,35 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
+ 	chan->user_get = 4;
+ 	chan->user_put = 0;
+ 
+-	INIT_LIST_HEAD(&chan->ramht_refs);
+-
+-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000,
+-				     NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
++	ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000,
++				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
+ 	if (ret) {
+ 		NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
+ 		nv50_evo_channel_del(pchan);
  		return ret;
  	}
  
 -	ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj->
 -				    im_pramin->start, 32768);
-+	ret = drm_mm_init(&chan->ramin_heap,
-+			  chan->ramin->gpuobj->im_pramin->start, 32768);
++	ret = drm_mm_init(&chan->ramin_heap, 0, 32768);
  	if (ret) {
  		NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
  		nv50_evo_channel_del(pchan);
-@@ -179,13 +182,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
+ 		return ret;
+ 	}
+ 
+-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16,
+-				     0, &chan->ramht);
++	ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht);
+ 	if (ret) {
+ 		NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
+ 		nv50_evo_channel_del(pchan);
+ 		return ret;
+ 	}
+ 
++	ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
++	nouveau_gpuobj_ref(NULL, &ramht);
++	if (ret) {
++		nv50_evo_channel_del(pchan);
++		return ret;
++	}
++
+ 	if (dev_priv->chipset != 0x50) {
+ 		ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19,
+ 					  0, 0xffffffff);
+@@ -179,13 +200,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
  }
  
  int
@@ -10753,7 +13282,85 @@ index 580a5d1..435d2b7 100644
  	uint64_t start;
  	int ret, i;
  
-@@ -366,26 +381,13 @@ nv50_display_init(struct drm_device *dev)
+@@ -213,11 +246,11 @@ nv50_display_init(struct drm_device *dev)
+ 		nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
+ 	}
+ 	/* SOR */
+-	for (i = 0; i < 4; i++) {
++	for (i = 0; i < nv50_sor_nr(dev); i++) {
+ 		val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
+ 		nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
+ 	}
+-	/* Something not yet in use, tv-out maybe. */
++	/* EXT */
+ 	for (i = 0; i < 3; i++) {
+ 		val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
+ 		nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
+@@ -246,7 +279,7 @@ nv50_display_init(struct drm_device *dev)
+ 	if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
+ 		nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
+ 		nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
+-		if (!nv_wait(0x006194e8, 2, 0)) {
++		if (!nv_wait(dev, 0x006194e8, 2, 0)) {
+ 			NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
+ 			NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
+ 						nv_rd32(dev, 0x6194e8));
+@@ -277,7 +310,8 @@ nv50_display_init(struct drm_device *dev)
+ 
+ 	nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE);
+ 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03);
+-	if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) {
++	if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
++		     0x40000000, 0x40000000)) {
+ 		NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n");
+ 		NV_ERROR(dev, "0x610200 = 0x%08x\n",
+ 			  nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
+@@ -286,7 +320,7 @@ nv50_display_init(struct drm_device *dev)
+ 
+ 	for (i = 0; i < 2; i++) {
+ 		nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
+-		if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
++		if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ 			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
+ 			NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
+ 			NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
+@@ -296,7 +330,7 @@ nv50_display_init(struct drm_device *dev)
+ 
+ 		nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ 			NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
+-		if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
++		if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+ 			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
+ 			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
+ 			NV_ERROR(dev, "timeout: "
+@@ -307,7 +341,7 @@ nv50_display_init(struct drm_device *dev)
+ 		}
+ 	}
+ 
+-	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9);
++	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
+ 
+ 	/* initialise fifo */
+ 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0),
+@@ -316,7 +350,7 @@ nv50_display_init(struct drm_device *dev)
+ 		NV50_PDISPLAY_CHANNEL_DMA_CB_VALID);
+ 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000);
+ 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002);
+-	if (!nv_wait(0x610200, 0x80000000, 0x00000000)) {
++	if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) {
+ 		NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n");
+ 		NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200));
+ 		return -EBUSY;
+@@ -356,7 +390,7 @@ nv50_display_init(struct drm_device *dev)
+ 	BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
+ 	OUT_RING(evo, 0);
+ 	FIRE_RING(evo);
+-	if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2))
++	if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
+ 		NV_ERROR(dev, "evo pushbuf stalled\n");
+ 
+ 	/* enable clock change interrupts. */
+@@ -366,26 +400,13 @@ nv50_display_init(struct drm_device *dev)
  					     NV50_PDISPLAY_INTR_EN_CLK_UNK40));
  
  	/* enable hotplug interrupts */
@@ -10781,7 +13388,33 @@ index 580a5d1..435d2b7 100644
  	}
  
  	return 0;
-@@ -465,6 +467,7 @@ int nv50_display_create(struct drm_device *dev)
+@@ -423,7 +444,7 @@ static int nv50_display_disable(struct drm_device *dev)
+ 			continue;
+ 
+ 		nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
+-		if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) {
++		if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
+ 			NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
+ 				      "0x%08x\n", mask, mask);
+ 			NV_ERROR(dev, "0x610024 = 0x%08x\n",
+@@ -433,14 +454,14 @@ static int nv50_display_disable(struct drm_device *dev)
+ 
+ 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0);
+ 	nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0);
+-	if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
++	if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
+ 		NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n");
+ 		NV_ERROR(dev, "0x610200 = 0x%08x\n",
+ 			  nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
+ 	}
+ 
+ 	for (i = 0; i < 3; i++) {
+-		if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i),
++		if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
+ 			     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
+ 			NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
+ 			NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
+@@ -465,6 +486,7 @@ int nv50_display_create(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct dcb_table *dcb = &dev_priv->vbios.dcb;
@@ -10789,7 +13422,7 @@ index 580a5d1..435d2b7 100644
  	int ret, i;
  
  	NV_DEBUG_KMS(dev, "\n");
-@@ -507,14 +510,18 @@ int nv50_display_create(struct drm_device *dev)
+@@ -507,14 +529,18 @@ int nv50_display_create(struct drm_device *dev)
  			continue;
  		}
  
@@ -10810,7 +13443,7 @@ index 580a5d1..435d2b7 100644
  			break;
  		default:
  			NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
-@@ -522,11 +529,13 @@ int nv50_display_create(struct drm_device *dev)
+@@ -522,11 +548,13 @@ int nv50_display_create(struct drm_device *dev)
  		}
  	}
  
@@ -10829,7 +13462,7 @@ index 580a5d1..435d2b7 100644
  	}
  
  	ret = nv50_display_init(dev);
-@@ -538,7 +547,8 @@ int nv50_display_create(struct drm_device *dev)
+@@ -538,7 +566,8 @@ int nv50_display_create(struct drm_device *dev)
  	return 0;
  }
  
@@ -10839,7 +13472,7 @@ index 580a5d1..435d2b7 100644
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  
-@@ -548,135 +558,30 @@ int nv50_display_destroy(struct drm_device *dev)
+@@ -548,135 +577,30 @@ int nv50_display_destroy(struct drm_device *dev)
  
  	nv50_display_disable(dev);
  	nv50_evo_channel_del(&dev_priv->evo);
@@ -10982,7 +13615,7 @@ index 580a5d1..435d2b7 100644
  	case OUTPUT_LVDS:
  		script = (mc >> 8) & 0xf;
  		if (bios->fp_no_ddc) {
-@@ -767,17 +672,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
+@@ -767,17 +691,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
  static void
  nv50_display_unk10_handler(struct drm_device *dev)
  {
@@ -11012,7 +13645,7 @@ index 580a5d1..435d2b7 100644
 +	crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
 +	if (crtc < 0)
 +		goto ack;
- 
++
 +	/* Find which encoder was connected to the CRTC */
 +	for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
 +		mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
@@ -11031,7 +13664,7 @@ index 580a5d1..435d2b7 100644
 +		or = i;
 +	}
 +
-+	for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
++	for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
 +		if (dev_priv->chipset  < 0x90 ||
 +		    dev_priv->chipset == 0x92 ||
 +		    dev_priv->chipset == 0xa0)
@@ -11072,12 +13705,12 @@ index 580a5d1..435d2b7 100644
 +			goto ack;
 +		}
 +	}
-+
+ 
 +	NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
  ack:
  	nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
  	nv_wr32(dev, 0x610030, 0x80000000);
-@@ -817,33 +793,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
+@@ -817,33 +812,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
  static void
  nv50_display_unk20_handler(struct drm_device *dev)
  {
@@ -11119,17 +13752,14 @@ index 580a5d1..435d2b7 100644
 -	pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
 -	script = nv50_display_script_select(dev, dcbent, pclk);
 +	pclk  = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
- 
--	NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
++
 +	/* Find which encoder is connected to the CRTC */
 +	for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
 +		mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
 +		NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
 +		if (!(mc & (1 << crtc)))
 +			continue;
- 
--	if (dcbent->type != OUTPUT_DP)
--		nouveau_bios_run_display_table(dev, dcbent, 0, -2);
++
 +		switch ((mc & 0x00000f00) >> 8) {
 +		case 0: type = OUTPUT_ANALOG; break;
 +		case 1: type = OUTPUT_TV; break;
@@ -11137,21 +13767,18 @@ index 580a5d1..435d2b7 100644
 +			NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
 +			goto ack;
 +		}
- 
--	nv50_crtc_set_clock(dev, head, pclk);
++
 +		or = i;
 +	}
- 
--	nouveau_bios_run_display_table(dev, dcbent, script, pclk);
-+	for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
++
++	for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
 +		if (dev_priv->chipset  < 0x90 ||
 +		    dev_priv->chipset == 0x92 ||
 +		    dev_priv->chipset == 0xa0)
 +			mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
 +		else
-+			mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
- 
--	nv50_display_unk20_dp_hack(dev, dcbent);
++			mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
++
 +		NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
 +		if (!(mc & (1 << crtc)))
 +			continue;
@@ -11167,39 +13794,45 @@ index 580a5d1..435d2b7 100644
 +			NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
 +			goto ack;
 +		}
-+
+ 
+-	NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
 +		or = i;
 +	}
-+
+ 
+-	if (dcbent->type != OUTPUT_DP)
+-		nouveau_bios_run_display_table(dev, dcbent, 0, -2);
 +	if (type == OUTPUT_ANY)
 +		goto ack;
-+
+ 
+-	nv50_crtc_set_clock(dev, head, pclk);
 +	/* Enable the encoder */
 +	for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
 +		dcb = &dev_priv->vbios.dcb.entry[i];
 +		if (dcb->type == type && (dcb->or & (1 << or)))
 +			break;
 +	}
-+
+ 
+-	nouveau_bios_run_display_table(dev, dcbent, script, pclk);
 +	if (i == dev_priv->vbios.dcb.entries) {
 +		NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
 +		goto ack;
 +	}
  
+-	nv50_display_unk20_dp_hack(dev, dcbent);
++	script = nv50_display_script_select(dev, dcb, mc, pclk);
++	nouveau_bios_run_display_table(dev, dcb, script, pclk);
+ 
 -	tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
 -	tmp &= ~0x000000f;
 -	nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
-+	script = nv50_display_script_select(dev, dcb, mc, pclk);
-+	nouveau_bios_run_display_table(dev, dcb, script, pclk);
++	nv50_display_unk20_dp_hack(dev, dcb);
  
 -	if (dcbent->type != OUTPUT_ANALOG) {
-+	nv50_display_unk20_dp_hack(dev, dcb);
-+
 +	if (dcb->type != OUTPUT_ANALOG) {
  		tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
  		tmp &= ~0x00000f0f;
  		if (script & 0x0100)
-@@ -853,24 +899,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
+@@ -853,24 +918,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
  		nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
  	}
  
@@ -11287,7 +13920,7 @@ index 581d405..c551f0b 100644
  int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
  
 diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
-index 32611bd..ad267c5 100644
+index 32611bd..594720b 100644
 --- a/drivers/gpu/drm/nouveau/nv50_fb.c
 +++ b/drivers/gpu/drm/nouveau/nv50_fb.c
 @@ -36,3 +36,42 @@ void
@@ -11323,7 +13956,7 @@ index 32611bd..ad267c5 100644
 +		if (!chan || !chan->ramin)
 +			continue;
 +
-+		if (chinst == chan->ramin->instance >> 12)
++		if (chinst == chan->ramin->vinst >> 12)
 +			break;
 +	}
 +
@@ -11333,29 +13966,54 @@ index 32611bd..ad267c5 100644
 +		trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
 +		trap[0], ch, chinst);
 +}
+diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
+index 6bf025c..6dcf048 100644
+--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
++++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
+@@ -1,6 +1,7 @@
+ #include "drmP.h"
+ #include "nouveau_drv.h"
+ #include "nouveau_dma.h"
++#include "nouveau_ramht.h"
+ #include "nouveau_fbcon.h"
+ 
+ void
+@@ -193,7 +194,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
++	ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
++	nouveau_gpuobj_ref(NULL, &eng2d);
+ 	if (ret)
+ 		return ret;
+ 
 diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
-index e20c0e2..38dbcda 100644
+index e20c0e2..a46a961 100644
 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c
 +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
-@@ -28,41 +28,35 @@
+@@ -27,42 +27,37 @@
+ #include "drmP.h"
  #include "drm.h"
  #include "nouveau_drv.h"
- 
+-
 -struct nv50_fifo_priv {
 -	struct nouveau_gpuobj_ref *thingo[2];
 -	int cur_thingo;
 -};
 -
 -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
--
++#include "nouveau_ramht.h"
+ 
  static void
 -nv50_fifo_init_thingo(struct drm_device *dev)
 +nv50_fifo_playlist_update(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
 -	struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
+-	struct nouveau_gpuobj_ref *cur;
 +	struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- 	struct nouveau_gpuobj_ref *cur;
++	struct nouveau_gpuobj *cur;
  	int i, nr;
  
  	NV_DEBUG(dev, "\n");
@@ -11371,14 +14029,15 @@ index e20c0e2..38dbcda 100644
 -		if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
 -			nv_wo32(dev, cur->gpuobj, nr++, i);
 +		if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) {
-+			nv_wo32(cur->gpuobj, (nr * 4), i);
++			nv_wo32(cur, (nr * 4), i);
 +			nr++;
 +		}
  	}
 -	dev_priv->engine.instmem.finish_access(dev);
 +	dev_priv->engine.instmem.flush(dev);
  
- 	nv_wr32(dev, 0x32f4, cur->instance >> 12);
+-	nv_wr32(dev, 0x32f4, cur->instance >> 12);
++	nv_wr32(dev, 0x32f4, cur->vinst >> 12);
  	nv_wr32(dev, 0x32ec, nr);
  	nv_wr32(dev, 0x2500, 0x101);
  }
@@ -11390,7 +14049,7 @@ index e20c0e2..38dbcda 100644
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_channel *chan = dev_priv->fifos[channel];
-@@ -70,37 +64,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
+@@ -70,37 +65,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
  
  	NV_DEBUG(dev, "ch%d\n", channel);
  
@@ -11398,12 +14057,14 @@ index e20c0e2..38dbcda 100644
 -		return -EINVAL;
 -
 -	if (IS_G80)
+-		inst = chan->ramfc->instance >> 12;
 +	if (dev_priv->chipset == 0x50)
- 		inst = chan->ramfc->instance >> 12;
++		inst = chan->ramfc->vinst >> 12;
  	else
- 		inst = chan->ramfc->instance >> 8;
+-		inst = chan->ramfc->instance >> 8;
 -	nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel),
 -		 inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
++		inst = chan->ramfc->vinst >> 8;
  
 -	if (!nt)
 -		nv50_fifo_init_thingo(dev);
@@ -11434,7 +14095,7 @@ index e20c0e2..38dbcda 100644
  }
  
  static void
-@@ -133,12 +118,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
+@@ -133,12 +119,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
  
  	for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
  		if (dev_priv->fifos[i])
@@ -11450,7 +14111,7 @@ index e20c0e2..38dbcda 100644
  }
  
  static void
-@@ -162,41 +147,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
+@@ -162,41 +148,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
  	nv_wr32(dev, 0x3270, 0);
  
  	/* Enable dummy channels setup by nv50_instmem.c */
@@ -11483,28 +14144,30 @@ index e20c0e2..38dbcda 100644
 -		return -ENOMEM;
 -	dev_priv->engine.fifo.priv = priv;
 -
- 	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
+-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
 -				     NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]);
-+				     NVOBJ_FLAG_ZERO_ALLOC,
-+				     &pfifo->playlist[0]);
++	ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
++				 NVOBJ_FLAG_ZERO_ALLOC,
++				 &pfifo->playlist[0]);
  	if (ret) {
 -		NV_ERROR(dev, "error creating thingo0: %d\n", ret);
 +		NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
  		return ret;
  	}
  
- 	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
+-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
 -				     NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]);
-+				     NVOBJ_FLAG_ZERO_ALLOC,
-+				     &pfifo->playlist[1]);
++	ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
++				 NVOBJ_FLAG_ZERO_ALLOC,
++				 &pfifo->playlist[1]);
  	if (ret) {
 -		NV_ERROR(dev, "error creating thingo1: %d\n", ret);
-+		nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
++		nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
 +		NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
  		return ret;
  	}
  
-@@ -216,18 +198,15 @@ void
+@@ -216,18 +199,15 @@ void
  nv50_fifo_takedown(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -11522,21 +14185,59 @@ index e20c0e2..38dbcda 100644
 -
 -	dev_priv->engine.fifo.priv = NULL;
 -	kfree(priv);
-+	nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
-+	nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
++	nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
++	nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
  }
  
  int
-@@ -248,7 +227,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
+@@ -248,72 +228,61 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
  
  	NV_DEBUG(dev, "ch%d\n", chan->id);
  
 -	if (IS_G80) {
+-		uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
+-		uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
+-
+-		ret = nouveau_gpuobj_new_fake(dev, ramin_poffset, ramin_voffset,
+-					      0x100, NVOBJ_FLAG_ZERO_ALLOC |
+-					      NVOBJ_FLAG_ZERO_FREE, &ramfc,
 +	if (dev_priv->chipset == 0x50) {
- 		uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
- 		uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
++		ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
++					      chan->ramin->vinst, 0x100,
++					      NVOBJ_FLAG_ZERO_ALLOC |
++					      NVOBJ_FLAG_ZERO_FREE,
+ 					      &chan->ramfc);
+ 		if (ret)
+ 			return ret;
+ 
+-		ret = nouveau_gpuobj_new_fake(dev, ramin_poffset + 0x0400,
+-					      ramin_voffset + 0x0400, 4096,
+-					      0, NULL, &chan->cache);
++		ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400,
++					      chan->ramin->vinst + 0x0400,
++					      4096, 0, &chan->cache);
+ 		if (ret)
+ 			return ret;
+ 	} else {
+-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256,
+-					     NVOBJ_FLAG_ZERO_ALLOC |
+-					     NVOBJ_FLAG_ZERO_FREE,
+-					     &chan->ramfc);
++		ret = nouveau_gpuobj_new(dev, chan, 0x100, 256,
++					 NVOBJ_FLAG_ZERO_ALLOC |
++					 NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
+ 		if (ret)
+ 			return ret;
+-		ramfc = chan->ramfc->gpuobj;
  
-@@ -281,39 +260,31 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
+-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
+-					     0, &chan->cache);
++		ret = nouveau_gpuobj_new(dev, chan, 4096, 1024,
++					 0, &chan->cache);
+ 		if (ret)
+ 			return ret;
+ 	}
++	ramfc = chan->ramfc;
  
  	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
  
@@ -11561,10 +14262,10 @@ index e20c0e2..38dbcda 100644
 -
 -		nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10);
 -		nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
-+	nv_wo32(ramfc, 0x48, chan->pushbuf->instance >> 4);
-+	nv_wo32(ramfc, 0x80, (0 << 27) /* 4KiB */ |
++	nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
++	nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
 +			     (4 << 24) /* SEARCH_FULL */ |
-+			     (chan->ramht->instance >> 4));
++			     (chan->ramht->gpuobj->cinst >> 4));
 +	nv_wo32(ramfc, 0x44, 0x2101ffff);
 +	nv_wo32(ramfc, 0x60, 0x7fffffff);
 +	nv_wo32(ramfc, 0x40, 0x00000000);
@@ -11575,11 +14276,11 @@ index e20c0e2..38dbcda 100644
 +	nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16);
 +
 +	if (dev_priv->chipset != 0x50) {
-+		nv_wo32(chan->ramin->gpuobj, 0, chan->id);
-+		nv_wo32(chan->ramin->gpuobj, 4, chan->ramfc->instance >> 8);
++		nv_wo32(chan->ramin, 0, chan->id);
++		nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8);
 +
-+		nv_wo32(ramfc, 0x88, chan->cache->instance >> 10);
-+		nv_wo32(ramfc, 0x98, chan->ramin->instance >> 12);
++		nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10);
++		nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12);
  	}
  
 -	dev_priv->engine.instmem.finish_access(dev);
@@ -11598,11 +14299,20 @@ index e20c0e2..38dbcda 100644
  	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
  	return 0;
  }
-@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
+@@ -322,20 +291,22 @@ void
+ nv50_fifo_destroy_context(struct nouveau_channel *chan)
+ {
+ 	struct drm_device *dev = chan->dev;
+-	struct nouveau_gpuobj_ref *ramfc = chan->ramfc;
++	struct nouveau_gpuobj *ramfc = NULL;
+ 
+ 	NV_DEBUG(dev, "ch%d\n", chan->id);
  
  	/* This will ensure the channel is seen as disabled. */
- 	chan->ramfc = NULL;
+-	chan->ramfc = NULL;
 -	nv50_fifo_channel_disable(dev, chan->id, false);
++	nouveau_gpuobj_ref(chan->ramfc, &ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->ramfc);
 +	nv50_fifo_channel_disable(dev, chan->id);
  
  	/* Dummy channel, also used on ch 127 */
@@ -11611,9 +14321,22 @@ index e20c0e2..38dbcda 100644
 +		nv50_fifo_channel_disable(dev, 127);
 +	nv50_fifo_playlist_update(dev);
  
- 	nouveau_gpuobj_ref_del(dev, &ramfc);
- 	nouveau_gpuobj_ref_del(dev, &chan->cache);
-@@ -349,63 +321,59 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
+-	nouveau_gpuobj_ref_del(dev, &ramfc);
+-	nouveau_gpuobj_ref_del(dev, &chan->cache);
++	nouveau_gpuobj_ref(NULL, &ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->cache);
+ }
+ 
+ int
+@@ -343,69 +314,65 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
+ {
+ 	struct drm_device *dev = chan->dev;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj;
+-	struct nouveau_gpuobj *cache = chan->cache->gpuobj;
++	struct nouveau_gpuobj *ramfc = chan->ramfc;
++	struct nouveau_gpuobj *cache = chan->cache;
+ 	int ptr, cnt;
  
  	NV_DEBUG(dev, "ch%d\n", chan->id);
  
@@ -11720,10 +14443,13 @@ index e20c0e2..38dbcda 100644
  	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
  	return 0;
  }
-@@ -434,64 +402,63 @@ nv50_fifo_unload_context(struct drm_device *dev)
- 	ramfc = chan->ramfc->gpuobj;
- 	cache = chan->cache->gpuobj;
- 
+@@ -431,67 +398,66 @@ nv50_fifo_unload_context(struct drm_device *dev)
+ 		return -EINVAL;
+ 	}
+ 	NV_DEBUG(dev, "ch%d\n", chan->id);
+-	ramfc = chan->ramfc->gpuobj;
+-	cache = chan->cache->gpuobj;
+-
 -	dev_priv->engine.instmem.prepare_access(dev, true);
 -
 -	nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
@@ -11759,6 +14485,9 @@ index e20c0e2..38dbcda 100644
 -	nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088));
 -	nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058));
 -	nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210));
++	ramfc = chan->ramfc;
++	cache = chan->cache;
++
 +	nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330));
 +	nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334));
 +	nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240));
@@ -11875,11 +14604,15 @@ index bb47ad7..b2fab2b 100644
 +	return 0;
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
-index b203d06..17a8d78 100644
+index b203d06..cbf5ae2 100644
 --- a/drivers/gpu/drm/nouveau/nv50_graph.c
 +++ b/drivers/gpu/drm/nouveau/nv50_graph.c
-@@ -30,8 +30,6 @@
- 
+@@ -27,11 +27,9 @@
+ #include "drmP.h"
+ #include "drm.h"
+ #include "nouveau_drv.h"
+-
++#include "nouveau_ramht.h"
  #include "nouveau_grctx.h"
  
 -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
@@ -11955,19 +14688,43 @@ index b203d06..17a8d78 100644
  }
  
  void
-@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
+@@ -188,7 +181,7 @@ nv50_graph_channel(struct drm_device *dev)
+ 	/* Be sure we're not in the middle of a context switch or bad things
+ 	 * will happen, such as unloading the wrong pgraph context.
+ 	 */
+-	if (!nv_wait(0x400300, 0x00000001, 0x00000000))
++	if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+ 		NV_ERROR(dev, "Ctxprog is still running\n");
+ 
+ 	inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+@@ -199,7 +192,7 @@ nv50_graph_channel(struct drm_device *dev)
+ 	for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ 		struct nouveau_channel *chan = dev_priv->fifos[i];
+ 
+-		if (chan && chan->ramin && chan->ramin->instance == inst)
++		if (chan && chan->ramin && chan->ramin->vinst == inst)
+ 			return chan;
+ 	}
+ 
+@@ -211,44 +204,36 @@ nv50_graph_create_context(struct nouveau_channel *chan)
+ {
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
- 	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
 -	struct nouveau_gpuobj *ctx;
-+	struct nouveau_gpuobj *obj;
++	struct nouveau_gpuobj *ramin = chan->ramin;
  	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 +	struct nouveau_grctx ctx = {};
  	int hdr, ret;
  
  	NV_DEBUG(dev, "ch%d\n", chan->id);
-@@ -223,32 +217,25 @@ nv50_graph_create_context(struct nouveau_channel *chan)
- 				     NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+ 
+-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+-				     0x1000, NVOBJ_FLAG_ZERO_ALLOC |
+-				     NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
++	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000,
++				 NVOBJ_FLAG_ZERO_ALLOC |
++				 NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
  	if (ret)
  		return ret;
 -	ctx = chan->ramin_grctx->gpuobj;
@@ -11995,29 +14752,28 @@ index b203d06..17a8d78 100644
 -	}
 -	nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
 -	dev_priv->engine.instmem.finish_access(dev);
-+	obj = chan->ramin_grctx->gpuobj;
-+
+ 
 +	hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
 +	nv_wo32(ramin, hdr + 0x00, 0x00190002);
-+	nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->instance +
++	nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
 +				   pgraph->grctx_size - 1);
-+	nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->instance);
++	nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
 +	nv_wo32(ramin, hdr + 0x0c, 0);
 +	nv_wo32(ramin, hdr + 0x10, 0);
 +	nv_wo32(ramin, hdr + 0x14, 0x00010000);
 +
 +	ctx.dev = chan->dev;
 +	ctx.mode = NOUVEAU_GRCTX_VALS;
-+	ctx.data = obj;
++	ctx.data = chan->ramin_grctx;
 +	nv50_grctx_init(&ctx);
 +
-+	nv_wo32(obj, 0x00000, chan->ramin->instance >> 12);
- 
++	nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
++
 +	dev_priv->engine.instmem.flush(dev);
  	return 0;
  }
  
-@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
+@@ -257,19 +242,18 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
  {
  	struct drm_device *dev = chan->dev;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -12026,17 +14782,51 @@ index b203d06..17a8d78 100644
  
  	NV_DEBUG(dev, "ch%d\n", chan->id);
  
- 	if (!chan->ramin || !chan->ramin->gpuobj)
+-	if (!chan->ramin || !chan->ramin->gpuobj)
++	if (!chan->ramin)
  		return;
  
 -	dev_priv->engine.instmem.prepare_access(dev, true);
  	for (i = hdr; i < hdr + 24; i += 4)
 -		nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
 -	dev_priv->engine.instmem.finish_access(dev);
-+		nv_wo32(chan->ramin->gpuobj, i, 0);
++		nv_wo32(chan->ramin, i, 0);
 +	dev_priv->engine.instmem.flush(dev);
  
- 	nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+-	nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
++	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ }
+ 
+ static int
+@@ -296,7 +280,7 @@ nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+ int
+ nv50_graph_load_context(struct nouveau_channel *chan)
+ {
+-	uint32_t inst = chan->ramin->instance >> 12;
++	uint32_t inst = chan->ramin->vinst >> 12;
+ 
+ 	NV_DEBUG(chan->dev, "ch%d\n", chan->id);
+ 	return nv50_graph_do_load_context(chan->dev, inst);
+@@ -341,15 +325,16 @@ static int
+ nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
+ 			   int mthd, uint32_t data)
+ {
+-	struct nouveau_gpuobj_ref *ref = NULL;
++	struct nouveau_gpuobj *gpuobj;
+ 
+-	if (nouveau_gpuobj_ref_find(chan, data, &ref))
++	gpuobj = nouveau_ramht_find(chan, data);
++	if (!gpuobj)
+ 		return -ENOENT;
+ 
+-	if (nouveau_notifier_offset(ref->gpuobj, NULL))
++	if (nouveau_notifier_offset(gpuobj, NULL))
+ 		return -EINVAL;
+ 
+-	chan->nvsw.vblsem = ref->gpuobj;
++	chan->nvsw.vblsem = gpuobj;
+ 	chan->nvsw.vblsem_offset = ~0;
+ 	return 0;
  }
 diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
 index 42a8fb2..336aab2 100644
@@ -15837,78 +18627,531 @@ index 42a8fb2..336aab2 100644
  			size = (ctx->ctxvals_pos-offset)/8;
  	}
 diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
-index 5f21df3..092057b 100644
+index 5f21df3..c0eef78 100644
 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c
 +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
-@@ -35,8 +35,6 @@ struct nv50_instmem_priv {
- 	struct nouveau_gpuobj_ref *pramin_pt;
- 	struct nouveau_gpuobj_ref *pramin_bar;
- 	struct nouveau_gpuobj_ref *fb_bar;
+@@ -32,41 +32,87 @@
+ struct nv50_instmem_priv {
+ 	uint32_t save1700[5]; /* 0x1700->0x1710 */
+ 
+-	struct nouveau_gpuobj_ref *pramin_pt;
+-	struct nouveau_gpuobj_ref *pramin_bar;
+-	struct nouveau_gpuobj_ref *fb_bar;
 -
 -	bool last_access_wr;
++	struct nouveau_gpuobj *pramin_pt;
++	struct nouveau_gpuobj *pramin_bar;
++	struct nouveau_gpuobj *fb_bar;
  };
  
- #define NV50_INSTMEM_PAGE_SHIFT 12
-@@ -141,13 +139,15 @@ nv50_instmem_init(struct drm_device *dev)
- 	chan->file_priv = (struct drm_file *)-2;
- 	dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
+-#define NV50_INSTMEM_PAGE_SHIFT 12
+-#define NV50_INSTMEM_PAGE_SIZE  (1 << NV50_INSTMEM_PAGE_SHIFT)
+-#define NV50_INSTMEM_PT_SIZE(a)	(((a) >> 12) << 3)
++static void
++nv50_channel_del(struct nouveau_channel **pchan)
++{
++	struct nouveau_channel *chan;
  
-+	INIT_LIST_HEAD(&chan->ramht_refs);
+-/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN
+- */
+-#define BAR0_WI32(g, o, v) do {                                   \
+-	uint32_t offset;                                          \
+-	if ((g)->im_backing) {                                    \
+-		offset = (g)->im_backing_start;                   \
+-	} else {                                                  \
+-		offset  = chan->ramin->gpuobj->im_backing_start;  \
+-		offset += (g)->im_pramin->start;                  \
+-	}                                                         \
+-	offset += (o);                                            \
+-	nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v));              \
+-} while (0)
++	chan = *pchan;
++	*pchan = NULL;
++	if (!chan)
++		return;
++
++	nouveau_gpuobj_ref(NULL, &chan->ramfc);
++	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
++	if (chan->ramin_heap.free_stack.next)
++		drm_mm_takedown(&chan->ramin_heap);
++	nouveau_gpuobj_ref(NULL, &chan->ramin);
++	kfree(chan);
++}
++
++static int
++nv50_channel_new(struct drm_device *dev, u32 size,
++		 struct nouveau_channel **pchan)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
++	u32  fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200;
++	struct nouveau_channel *chan;
++	int ret;
++
++	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
++	if (!chan)
++		return -ENOMEM;
++	chan->dev = dev;
++
++	ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
++	if (ret) {
++		nv50_channel_del(&chan);
++		return ret;
++	}
++
++	ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size);
++	if (ret) {
++		nv50_channel_del(&chan);
++		return ret;
++	}
++
++	ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
++				      chan->ramin->pinst + pgd,
++				      chan->ramin->vinst + pgd,
++				      0x4000, NVOBJ_FLAG_ZERO_ALLOC,
++				      &chan->vm_pd);
++	if (ret) {
++		nv50_channel_del(&chan);
++		return ret;
++	}
++
++	ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
++				      chan->ramin->pinst + fc,
++				      chan->ramin->vinst + fc, 0x100,
++				      NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc);
++	if (ret) {
++		nv50_channel_del(&chan);
++		return ret;
++	}
 +
- 	/* Channel's PRAMIN object + heap */
- 	ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
- 							NULL, &chan->ramin);
++	*pchan = chan;
++	return 0;
++}
+ 
+ int
+ nv50_instmem_init(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+-	struct nouveau_channel *chan;
+-	uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size;
+-	uint32_t save_nv001700;
+-	uint64_t v;
+ 	struct nv50_instmem_priv *priv;
++	struct nouveau_channel *chan;
+ 	int ret, i;
++	u32 tmp;
+ 
+ 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ 	if (!priv)
+@@ -77,215 +123,113 @@ nv50_instmem_init(struct drm_device *dev)
+ 	for (i = 0x1700; i <= 0x1710; i += 4)
+ 		priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
+ 
+-	/* Reserve the last MiB of VRAM, we should probably try to avoid
+-	 * setting up the below tables over the top of the VBIOS image at
+-	 * some point.
+-	 */
+-	dev_priv->ramin_rsvd_vram = 1 << 20;
+-	c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+-	c_size   = 128 << 10;
+-	c_vmpd   = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
+-	c_ramfc  = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
+-	c_base   = c_vmpd + 0x4000;
+-	pt_size  = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size);
+-
+-	NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset);
+-	NV_DEBUG(dev, "    VBIOS image: 0x%08x\n",
+-				(nv_rd32(dev, 0x619f04) & ~0xff) << 8);
+-	NV_DEBUG(dev, "  Aperture size: %d MiB\n", dev_priv->ramin_size >> 20);
+-	NV_DEBUG(dev, "        PT size: %d KiB\n", pt_size >> 10);
+-
+-	/* Determine VM layout, we need to do this first to make sure
+-	 * we allocate enough memory for all the page tables.
+-	 */
+-	dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
+-	dev_priv->vm_gart_size = NV50_VM_BLOCK;
+-
+-	dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
+-	dev_priv->vm_vram_size = dev_priv->vram_size;
+-	if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
+-		dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
+-	dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
+-	dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
+-
+-	dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
+-
+-	NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
+-		 dev_priv->vm_gart_base,
+-		 dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
+-	NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
+-		 dev_priv->vm_vram_base,
+-		 dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
+-
+-	c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8);
+-
+-	/* Map BAR0 PRAMIN aperture over the memory we want to use */
+-	save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN);
+-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16));
+-
+-	/* Create a fake channel, and use it as our "dummy" channels 0/127.
+-	 * The main reason for creating a channel is so we can use the gpuobj
+-	 * code.  However, it's probably worth noting that NVIDIA also setup
+-	 * their channels 0/127 with the same values they configure here.
+-	 * So, there may be some other reason for doing this.
+-	 *
+-	 * Have to create the entire channel manually, as the real channel
+-	 * creation code assumes we have PRAMIN access, and we don't until
+-	 * we're done here.
+-	 */
+-	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+-	if (!chan)
++	/* Global PRAMIN heap */
++	ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size);
++	if (ret) {
++		NV_ERROR(dev, "Failed to init RAMIN heap\n");
+ 		return -ENOMEM;
+-	chan->id = 0;
+-	chan->dev = dev;
+-	chan->file_priv = (struct drm_file *)-2;
+-	dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
++	}
+ 
+-	/* Channel's PRAMIN object + heap */
+-	ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
+-							NULL, &chan->ramin);
++	/* we need a channel to plug into the hw to control the BARs */
++	ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]);
  	if (ret)
  		return ret;
++	chan = dev_priv->fifos[127] = dev_priv->fifos[0];
  
 -	if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
-+	if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
- 		return -ENOMEM;
+-		return -ENOMEM;
+-
+-	/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
+-	ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc,
+-						0x4000, 0, NULL, &chan->ramfc);
++	/* allocate page table for PRAMIN BAR */
++	ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8,
++				 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
++				 &priv->pramin_pt);
+ 	if (ret)
+ 		return ret;
  
- 	/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
-@@ -262,30 +262,25 @@ nv50_instmem_init(struct drm_device *dev)
+-	for (i = 0; i < c_vmpd; i += 4)
+-		BAR0_WI32(chan->ramin->gpuobj, i, 0);
++	nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63);
++	nv_wo32(chan->vm_pd, 0x0004, 0);
  
- 	/* Assume that praying isn't enough, check that we can re-read the
- 	 * entire fake channel back from the PRAMIN BAR */
--	dev_priv->engine.instmem.prepare_access(dev, false);
- 	for (i = 0; i < c_size; i += 4) {
- 		if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
- 			NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
- 									i);
--			dev_priv->engine.instmem.finish_access(dev);
- 			return -EINVAL;
- 		}
+-	/* VM page directory */
+-	ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd,
+-					   0x4000, 0, &chan->vm_pd, NULL);
++	/* DMA object for PRAMIN BAR */
++	ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar);
+ 	if (ret)
+ 		return ret;
+-	for (i = 0; i < 0x4000; i += 8) {
+-		BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000);
+-		BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000);
+-	}
+-
+-	/* PRAMIN page table, cheat and map into VM at 0x0000000000.
+-	 * We map the entire fake channel into the start of the PRAMIN BAR
+-	 */
+-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
+-				     0, &priv->pramin_pt);
++	nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000);
++	nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1);
++	nv_wo32(priv->pramin_bar, 0x08, 0x00000000);
++	nv_wo32(priv->pramin_bar, 0x0c, 0x00000000);
++	nv_wo32(priv->pramin_bar, 0x10, 0x00000000);
++	nv_wo32(priv->pramin_bar, 0x14, 0x00000000);
++
++	/* map channel into PRAMIN, gpuobj didn't do it for us */
++	ret = nv50_instmem_bind(dev, chan->ramin);
+ 	if (ret)
+ 		return ret;
+ 
+-	v = c_offset | 1;
+-	if (dev_priv->vram_sys_base) {
+-		v += dev_priv->vram_sys_base;
+-		v |= 0x30;
+-	}
++	/* poke regs... */
++	nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12));
++	nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
++	nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4));
+ 
+-	i = 0;
+-	while (v < dev_priv->vram_sys_base + c_offset + c_size) {
+-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v));
+-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v));
+-		v += 0x1000;
+-		i += 8;
++	tmp = nv_ri32(dev, 0);
++	nv_wi32(dev, 0, ~tmp);
++	if (nv_ri32(dev, 0) != ~tmp) {
++		NV_ERROR(dev, "PRAMIN readback failed\n");
++		return -EIO;
  	}
--	dev_priv->engine.instmem.finish_access(dev);
++	nv_wi32(dev, 0, tmp);
  
- 	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
+-	while (i < pt_size) {
+-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
+-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+-		i += 8;
+-	}
++	dev_priv->ramin_available = true;
++
++	/* Determine VM layout */
++	dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
++	dev_priv->vm_gart_size = NV50_VM_BLOCK;
++
++	dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
++	dev_priv->vm_vram_size = dev_priv->vram_size;
++	if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
++		dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
++	dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
++	dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK;
++
++	dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size;
+ 
+-	BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
+-	BAR0_WI32(chan->vm_pd, 0x04, 0x00000000);
++	NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n",
++		 dev_priv->vm_gart_base,
++		 dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1);
++	NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n",
++		 dev_priv->vm_vram_base,
++		 dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
+ 
+ 	/* VRAM page table(s), mapped into VM at +1GiB  */
+ 	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
+-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0,
+-					     NV50_VM_BLOCK/65536*8, 0, 0,
+-					     &chan->vm_vram_pt[i]);
++		ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8,
++					 0, NVOBJ_FLAG_ZERO_ALLOC,
++					 &chan->vm_vram_pt[i]);
+ 		if (ret) {
+-			NV_ERROR(dev, "Error creating VRAM page tables: %d\n",
+-									ret);
++			NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret);
+ 			dev_priv->vm_vram_pt_nr = i;
+ 			return ret;
+ 		}
+-		dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj;
++		dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i];
+ 
+-		for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size;
+-								v += 4)
+-			BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0);
+-
+-		BAR0_WI32(chan->vm_pd, 0x10 + (i*8),
+-			  chan->vm_vram_pt[i]->instance | 0x61);
+-		BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0);
++		nv_wo32(chan->vm_pd, 0x10 + (i*8),
++			chan->vm_vram_pt[i]->vinst | 0x61);
++		nv_wo32(chan->vm_pd, 0x14 + (i*8), 0);
+ 	}
  
- 	/* Global PRAMIN heap */
+-	/* DMA object for PRAMIN BAR */
+-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
+-							&priv->pramin_bar);
+-	if (ret)
+-		return ret;
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000);
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1);
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000);
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000);
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000);
+-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000);
+-
+ 	/* DMA object for FB BAR */
+-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
+-							&priv->fb_bar);
++	ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar);
+ 	if (ret)
+ 		return ret;
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
+-					      drm_get_resource_len(dev, 1) - 1);
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
+-	BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000);
+-
+-	/* Poke the relevant regs, and pray it works :) */
+-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
+-	nv_wr32(dev, NV50_PUNK_UNK1710, 0);
+-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
+-					 NV50_PUNK_BAR_CFG_BASE_VALID);
+-	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
+-					NV50_PUNK_BAR1_CTXDMA_VALID);
+-	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
+-					NV50_PUNK_BAR3_CTXDMA_VALID);
+-
++	nv_wo32(priv->fb_bar, 0x00, 0x7fc00000);
++	nv_wo32(priv->fb_bar, 0x04, 0x40000000 +
++				    pci_resource_len(dev->pdev, 1) - 1);
++	nv_wo32(priv->fb_bar, 0x08, 0x40000000);
++	nv_wo32(priv->fb_bar, 0x0c, 0x00000000);
++	nv_wo32(priv->fb_bar, 0x10, 0x00000000);
++	nv_wo32(priv->fb_bar, 0x14, 0x00000000);
++
++	nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4));
+ 	for (i = 0; i < 8; i++)
+ 		nv_wr32(dev, 0x1900 + (i*4), 0);
+ 
+-	/* Assume that praying isn't enough, check that we can re-read the
+-	 * entire fake channel back from the PRAMIN BAR */
+-	dev_priv->engine.instmem.prepare_access(dev, false);
+-	for (i = 0; i < c_size; i += 4) {
+-		if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
+-			NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
+-									i);
+-			dev_priv->engine.instmem.finish_access(dev);
+-			return -EINVAL;
+-		}
+-	}
+-	dev_priv->engine.instmem.finish_access(dev);
+-
+-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
+-
+-	/* Global PRAMIN heap */
 -	if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
 -				  c_size, dev_priv->ramin_size - c_size)) {
 -		dev_priv->ramin_heap = NULL;
-+	if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
- 		NV_ERROR(dev, "Failed to init RAMIN heap\n");
- 	}
- 
- 	/*XXX: incorrect, but needed to make hash func "work" */
- 	dev_priv->ramht_offset = 0x10000;
- 	dev_priv->ramht_bits   = 9;
+-		NV_ERROR(dev, "Failed to init RAMIN heap\n");
+-	}
+-
+-	/*XXX: incorrect, but needed to make hash func "work" */
+-	dev_priv->ramht_offset = 0x10000;
+-	dev_priv->ramht_bits   = 9;
 -	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits);
-+	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
  	return 0;
  }
  
-@@ -321,7 +316,7 @@ nv50_instmem_takedown(struct drm_device *dev)
- 		nouveau_gpuobj_del(dev, &chan->vm_pd);
- 		nouveau_gpuobj_ref_del(dev, &chan->ramfc);
- 		nouveau_gpuobj_ref_del(dev, &chan->ramin);
+@@ -302,29 +246,24 @@ nv50_instmem_takedown(struct drm_device *dev)
+ 	if (!priv)
+ 		return;
+ 
++	dev_priv->ramin_available = false;
++
+ 	/* Restore state from before init */
+ 	for (i = 0x1700; i <= 0x1710; i += 4)
+ 		nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]);
+ 
+-	nouveau_gpuobj_ref_del(dev, &priv->fb_bar);
+-	nouveau_gpuobj_ref_del(dev, &priv->pramin_bar);
+-	nouveau_gpuobj_ref_del(dev, &priv->pramin_pt);
++	nouveau_gpuobj_ref(NULL, &priv->fb_bar);
++	nouveau_gpuobj_ref(NULL, &priv->pramin_bar);
++	nouveau_gpuobj_ref(NULL, &priv->pramin_pt);
+ 
+ 	/* Destroy dummy channel */
+ 	if (chan) {
+-		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
+-			nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+-			dev_priv->vm_vram_pt[i] = NULL;
+-		}
++		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
++			nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
+ 		dev_priv->vm_vram_pt_nr = 0;
+ 
+-		nouveau_gpuobj_del(dev, &chan->vm_pd);
+-		nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
 -		nouveau_mem_takedown(&chan->ramin_heap);
-+		drm_mm_takedown(&chan->ramin_heap);
+-
+-		dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
+-		kfree(chan);
++		nv50_channel_del(&dev_priv->fifos[0]);
++		dev_priv->fifos[127] = NULL;
+ 	}
+ 
+ 	dev_priv->engine.instmem.priv = NULL;
+@@ -336,14 +275,14 @@ nv50_instmem_suspend(struct drm_device *dev)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nouveau_channel *chan = dev_priv->fifos[0];
+-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
++	struct nouveau_gpuobj *ramin = chan->ramin;
+ 	int i;
+ 
+-	ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size);
++	ramin->im_backing_suspend = vmalloc(ramin->size);
+ 	if (!ramin->im_backing_suspend)
+ 		return -ENOMEM;
+ 
+-	for (i = 0; i < ramin->im_pramin->size; i += 4)
++	for (i = 0; i < ramin->size; i += 4)
+ 		ramin->im_backing_suspend[i/4] = nv_ri32(dev, i);
+ 	return 0;
+ }
+@@ -354,23 +293,25 @@ nv50_instmem_resume(struct drm_device *dev)
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
+ 	struct nouveau_channel *chan = dev_priv->fifos[0];
+-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
++	struct nouveau_gpuobj *ramin = chan->ramin;
+ 	int i;
+ 
+-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16));
+-	for (i = 0; i < ramin->im_pramin->size; i += 4)
+-		BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]);
++	dev_priv->ramin_available = false;
++	dev_priv->ramin_base = ~0;
++	for (i = 0; i < ramin->size; i += 4)
++		nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]);
++	dev_priv->ramin_available = true;
+ 	vfree(ramin->im_backing_suspend);
+ 	ramin->im_backing_suspend = NULL;
+ 
+ 	/* Poke the relevant regs, and pray it works :) */
+-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
++	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12));
+ 	nv_wr32(dev, NV50_PUNK_UNK1710, 0);
+-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
++	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) |
+ 					 NV50_PUNK_BAR_CFG_BASE_VALID);
+-	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
++	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) |
+ 					NV50_PUNK_BAR1_CTXDMA_VALID);
+-	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
++	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) |
+ 					NV50_PUNK_BAR3_CTXDMA_VALID);
+ 
+ 	for (i = 0; i < 8; i++)
+@@ -386,7 +327,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+ 	if (gpuobj->im_backing)
+ 		return -EINVAL;
+ 
+-	*sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
++	*sz = ALIGN(*sz, 4096);
+ 	if (*sz == 0)
+ 		return -EINVAL;
+ 
+@@ -404,9 +345,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+ 		return ret;
+ 	}
+ 
+-	gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
+-	gpuobj->im_backing_start <<= PAGE_SHIFT;
+-
++	gpuobj->vinst = gpuobj->im_backing->bo.mem.mm_node->start << PAGE_SHIFT;
+ 	return 0;
+ }
+ 
+@@ -429,23 +368,23 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ {
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
+-	struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
++	struct nouveau_gpuobj *pramin_pt = priv->pramin_pt;
+ 	uint32_t pte, pte_end;
+ 	uint64_t vram;
  
- 		dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
- 		kfree(chan);
-@@ -436,14 +431,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
  	if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
  		return -EINVAL;
  
@@ -15918,14 +19161,18 @@ index 5f21df3..092057b 100644
  
  	pte     = (gpuobj->im_pramin->start >> 12) << 1;
  	pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
- 	vram    = gpuobj->im_backing_start;
+-	vram    = gpuobj->im_backing_start;
++	vram    = gpuobj->vinst;
  
 -	NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
 +	NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
  		 gpuobj->im_pramin->start, pte, pte_end);
- 	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+-	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
++	NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
  
-@@ -453,27 +448,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ 	vram |= 1;
+ 	if (dev_priv->vram_sys_base) {
+@@ -453,27 +392,16 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
  		vram |= 0x30;
  	}
  
@@ -15933,11 +19180,8 @@ index 5f21df3..092057b 100644
  	while (pte < pte_end) {
 -		nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
 -		nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
-+		nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
-+		nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
- 		vram += NV50_INSTMEM_PAGE_SIZE;
-+		pte += 2;
- 	}
+-		vram += NV50_INSTMEM_PAGE_SIZE;
+-	}
 -	dev_priv->engine.instmem.finish_access(dev);
 -
 -	nv_wr32(dev, 0x100c80, 0x00040001);
@@ -15945,7 +19189,11 @@ index 5f21df3..092057b 100644
 -		NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n");
 -		NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
 -		return -EBUSY;
--	}
++		nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
++		nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
++		vram += 0x1000;
++		pte += 2;
+ 	}
 +	dev_priv->engine.instmem.flush(dev);
  
 -	nv_wr32(dev, 0x100c80, 0x00060001);
@@ -15959,7 +19207,14 @@ index 5f21df3..092057b 100644
  
  	gpuobj->im_bound = 1;
  	return 0;
-@@ -492,36 +476,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+@@ -489,39 +417,44 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+ 	if (gpuobj->im_bound == 0)
+ 		return -EINVAL;
+ 
++	/* can happen during late takedown */
++	if (unlikely(!dev_priv->ramin_available))
++		return 0;
++
  	pte     = (gpuobj->im_pramin->start >> 12) << 1;
  	pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
  
@@ -15967,8 +19222,8 @@ index 5f21df3..092057b 100644
  	while (pte < pte_end) {
 -		nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
 -		nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
-+		nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 0, 0x00000000);
-+		nv_wo32(priv->pramin_pt->gpuobj, (pte * 4) + 4, 0x00000000);
++		nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000);
++		nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000);
 +		pte += 2;
  	}
 -	dev_priv->engine.instmem.finish_access(dev);
@@ -15987,7 +19242,7 @@ index 5f21df3..092057b 100644
 -
 -	priv->last_access_wr = write;
 +	nv_wr32(dev, 0x00330c, 0x00000001);
-+	if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
++	if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
 +		NV_ERROR(dev, "PRAMIN flush timeout\n");
  }
  
@@ -16004,7 +19259,7 @@ index 5f21df3..092057b 100644
 -			NV_ERROR(dev, "PRAMIN flush timeout\n");
 -	}
 +	nv_wr32(dev, 0x070000, 0x00000001);
-+	if (!nv_wait(0x070000, 0x00000002, 0x00000000))
++	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 +		NV_ERROR(dev, "PRAMIN flush timeout\n");
  }
  
@@ -16012,11 +19267,11 @@ index 5f21df3..092057b 100644
 +nv50_vm_flush(struct drm_device *dev, int engine)
 +{
 +	nv_wr32(dev, 0x100c80, (engine << 16) | 1);
-+	if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
++	if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
 +		NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
-index 812778d..bcd4cf8 100644
+index 812778d..b4a5ecb 100644
 --- a/drivers/gpu/drm/nouveau/nv50_sor.c
 +++ b/drivers/gpu/drm/nouveau/nv50_sor.c
 @@ -37,52 +37,32 @@
@@ -16104,7 +19359,24 @@ index 812778d..bcd4cf8 100644
  		    nvenc->dcb->or != nv_encoder->dcb->or)
  			continue;
  
-@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
+@@ -110,7 +92,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
+ 	}
+ 
+ 	/* wait for it to be done */
+-	if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
++	if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+ 		     NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
+ 		NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
+ 		NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
+@@ -126,15 +108,29 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
+ 
+ 	nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
+ 		NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
+-	if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(or),
++	if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or),
+ 		     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
+ 		NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
+ 		NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
  			 nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
  	}
  
@@ -16264,10 +19536,10 @@ index 0000000..26a9960
 +}
 diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
 new file mode 100644
-index 0000000..45ca994
+index 0000000..2cdb7c3
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
-@@ -0,0 +1,95 @@
+@@ -0,0 +1,89 @@
 +/*
 + * Copyright 2010 Red Hat Inc.
 + *
@@ -16313,12 +19585,6 @@ index 0000000..45ca994
 +}
 +
 +bool
-+nvc0_fifo_cache_flush(struct drm_device *dev)
-+{
-+	return true;
-+}
-+
-+bool
 +nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
 +{
 +	return false;
@@ -16445,10 +19711,10 @@ index 0000000..edf2b21
 +}
 diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
 new file mode 100644
-index 0000000..9238c73
+index 0000000..152d8e8
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c
-@@ -0,0 +1,234 @@
+@@ -0,0 +1,229 @@
 +/*
 + * Copyright 2010 Red Hat Inc.
 + *
@@ -16501,8 +19767,7 @@ index 0000000..9238c73
 +		return ret;
 +	}
 +
-+	gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
-+	gpuobj->im_backing_start <<= PAGE_SHIFT;
++	gpuobj->vinst = gpuobj->im_backing->bo.mem.mm_node->start << PAGE_SHIFT;
 +	return 0;
 +}
 +
@@ -16535,11 +19800,11 @@ index 0000000..9238c73
 +
 +	pte     = gpuobj->im_pramin->start >> 12;
 +	pte_end = (gpuobj->im_pramin->size >> 12) + pte;
-+	vram    = gpuobj->im_backing_start;
++	vram    = gpuobj->vinst;
 +
 +	NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
 +		 gpuobj->im_pramin->start, pte, pte_end);
-+	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
++	NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
 +
 +	while (pte < pte_end) {
 +		nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
@@ -16585,7 +19850,7 @@ index 0000000..9238c73
 +nvc0_instmem_flush(struct drm_device *dev)
 +{
 +	nv_wr32(dev, 0x070000, 1);
-+	if (!nv_wait(0x070000, 0x00000002, 0x00000000))
++	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 +		NV_ERROR(dev, "PRAMIN flush timeout\n");
 +}
 +
@@ -16672,10 +19937,6 @@ index 0000000..9238c73
 +		return -ENOMEM;
 +	}
 +
-+	/*XXX: incorrect, but needed to make hash func "work" */
-+	dev_priv->ramht_offset = 0x10000;
-+	dev_priv->ramht_bits   = 9;
-+	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
 +	return 0;
 +}
 +
diff --git a/kernel.spec b/kernel.spec
index 4d2cd3e..134f6f3 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -48,7 +48,7 @@ Summary: The Linux kernel
 # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec).
 # scripts/rebase.sh should be made to do that for you, actually.
 #
-%global baserelease 22
+%global baserelease 23
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -1921,6 +1921,9 @@ fi
 # and build.
 
 %changelog
+* Wed Sep 08 2010 Ben Skeggs <bskeggs at redhat.com> 2.6.35.4-23
+- nouveau: handle certain GPU errors better, AGP + misc fixes
+
 * Tue Sep 07 2010 Dave Jones <davej at redhat.com> 2.6.35.4-22
 - Disable hung task checker, it only ever causes false positives. (#630777)
 


More information about the scm-commits mailing list