rpms/kernel/F-13 drm-nouveau-updates.patch, 1.2, 1.3 kernel.spec, 1.1945, 1.1946

Ben Skeggs bskeggs at fedoraproject.org
Mon Mar 15 00:35:49 UTC 2010


Author: bskeggs

Update of /cvs/pkgs/rpms/kernel/F-13
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv572

Modified Files:
	drm-nouveau-updates.patch kernel.spec 
Log Message:
* Mon Mar 15 2010 Ben Skeggs <bskeggs at redhat.com>
- nouveau: pull in more fixes from upstream



drm-nouveau-updates.patch:
 Makefile            |    4 
 nouveau_bios.c      |  365 ++++----
 nouveau_bios.h      |  127 +-
 nouveau_bo.c        |    3 
 nouveau_calc.c      |    4 
 nouveau_channel.c   |   13 
 nouveau_connector.c |  169 ++-
 nouveau_connector.h |    3 
 nouveau_debugfs.c   |   13 
 nouveau_dma.c       |    5 
 nouveau_drv.c       |   14 
 nouveau_drv.h       |   13 
 nouveau_hw.c        |    6 
 nouveau_i2c.c       |   10 
 nouveau_irq.c       |  614 ++++++++++++-
 nouveau_state.c     |    6 
 nv04_crtc.c         |    6 
 nv04_dac.c          |    8 
 nv04_dfp.c          |    4 
 nv04_display.c      |   49 -
 nv04_fbcon.c        |    6 
 nv04_fifo.c         |    5 
 nv04_tv.c           |    2 
 nv17_tv.c           |    6 
 nv40_fifo.c         |    5 
 nv50_dac.c          |    4 
 nv50_display.c      |   54 -
 nv50_fb.c           |   32 
 nv50_fbcon.c        |    4 
 nv50_fifo.c         |    5 
 nv50_graph.c        |   96 +-
 nv50_grctx.c        | 2372 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 nv50_instmem.c      |    3 
 33 files changed, 3544 insertions(+), 486 deletions(-)

Index: drm-nouveau-updates.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-13/drm-nouveau-updates.patch,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- drm-nouveau-updates.patch	25 Feb 2010 05:46:53 -0000	1.2
+++ drm-nouveau-updates.patch	15 Mar 2010 00:35:48 -0000	1.3
@@ -1,7 +1,7 @@
-From 98cd876a6ead2217c8933a721f038655cf125601 Mon Sep 17 00:00:00 2001
+From 45040686ab0c8d320c6b738970293585ea0bf5bf Mon Sep 17 00:00:00 2001
 From: Marcin Slusarz <marcin.slusarz at gmail.com>
 Date: Wed, 17 Feb 2010 19:04:00 +0100
-Subject: [PATCH] drm-nouveau-updates
+Subject: [PATCH 2/2] drm-nouveau-updates
 MIME-Version: 1.0
 Content-Type: text/plain; charset=UTF-8
 Content-Transfer-Encoding: 8bit
@@ -128,44 +128,155 @@ guarantee a ctxprog isn't running).
 
 Signed-off-by: Maarten Maathuis <madman2003 at gmail.com>
 Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: Remove redundant/incorrect ctxvals initialisation.
+
+11c/004 offset corresponds to PGRAPH reg 0x400828, and is initialised
+earlier anyway by both our ctxprog generator and blob ctxvals. It's
+actually incorrect with the generator, since we use different layout
+on pre-NVA0.
+
+Signed-off-by: Marcin Kościelnicki <koriakin at 0x04.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: Fix fbcon corruption with font width not divisible by 8
+
+NV50 is nice and has a switch that autoaligns stuff for us. Pre-NV50,
+we need to align input bitmap width manually.
+
+Signed-off-by: Marcin Kościelnicki <koriakin at 0x04.net>
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nv50: Make ctxprog wait until interrupt handler is done.
+
+This will fix races between generated ctxprogs and interrupt handler.
+
+Signed-off-by: Marcin Kościelnicki <koriakin at 0x04.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: Improve PGRAPH interrupt handling.
+
+This makes nouveau recognise and report more kinds of PGRAPH errors, as
+well as prevent GPU lockups resulting from some of them.
+
+Lots of guesswork was involved and some part of this is probably
+incorrect. Some potential-lockuop situations are handled by just
+resetting a whole PGRAPH subunit, which doesn't sound like a "proper"
+solution, but seems to work just fine... for now.
+
+Signed-off-by: Marcin Kościelnicki <koriakin at 0x04.net>
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: add option to allow override of dcb connector table types
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: Gigabyte NX85T connector table lies, it has DVI-I not HDMI
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv04-nv40: Fix up the programmed horizontal sync pulse delay.
+
+The calculated values were a little bit off (~16 clocks), the only
+effect it could have had is a slightly offset image with respect to
+the blob on analog outputs (bug 26790).
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: print a message very early during suspend
+
+- In case of suspend lockups it's nice to know it happened in nouveau.
+
+Signed-off-by: Maarten Maathuis <madman2003 at gmail.com>
+
+drm/nv50: add a memory barrier to pushbuf submission
+
+- This is useful for vram pushbuffers that are write combined.
+- pre-nv50 has one too (in WRITE_PUT).
+
+Signed-off-by: Maarten Maathuis <madman2003 at gmail.com>
+
+drm/nv50: fix connector table parsing for some cards
+
+The connector table index in the DCB entry for each output type is an
+index into the connector table, and does *not* necessarily match up
+with what was previously called "index" in the connector table entries
+themselves.
+
+Not real sure what that index is exactly, renamed to "index2" as we
+still use it to prevent creating multiple TV connectors.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: Never evict VRAM buffers to system.
+
+VRAM->system is a synchronous operation: it involves scheduling a
+VRAM->TT DMA transfer and stalling the CPU until it's finished so that
+we can unbind the new memory from the translation tables. VRAM->TT can
+always be performed asynchronously, even if TT is already full and we
+have to move something out of it.
+
+Additionally, allowing VRAM->system behaves badly under heavy memory
+pressure because once we run out of TT, stuff starts to be moved back
+and forth between VRAM and system, and the TT contents are hardly
+renewed.
+
+Signed-off-by: Francisco Jerez <currojerez at riseup.net>
+
+drm/nouveau: add module option to disable TV detection
+
+Intended to be used as a workaround in cases where we falsely detect
+that a TV is connected when it's not.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
 ---
- drivers/gpu/drm/nouveau/Makefile            |    2 +-
- drivers/gpu/drm/nouveau/nouveau_bios.c      |  339 +++--
- drivers/gpu/drm/nouveau/nouveau_bios.h      |  126 +-
+ drivers/gpu/drm/nouveau/Makefile            |    4 +-
+ drivers/gpu/drm/nouveau/nouveau_bios.c      |  365 +++--
+ drivers/gpu/drm/nouveau/nouveau_bios.h      |  127 +-
+ drivers/gpu/drm/nouveau/nouveau_bo.c        |    3 +-
  drivers/gpu/drm/nouveau/nouveau_calc.c      |    4 +-
  drivers/gpu/drm/nouveau/nouveau_channel.c   |   13 +-
- drivers/gpu/drm/nouveau/nouveau_connector.c |  167 ++-
+ drivers/gpu/drm/nouveau/nouveau_connector.c |  169 ++-
  drivers/gpu/drm/nouveau/nouveau_connector.h |    3 +-
  drivers/gpu/drm/nouveau/nouveau_debugfs.c   |   13 +
- drivers/gpu/drm/nouveau/nouveau_drv.c       |    4 +-
- drivers/gpu/drm/nouveau/nouveau_drv.h       |    7 +-
+ drivers/gpu/drm/nouveau/nouveau_dma.c       |    5 +
+ drivers/gpu/drm/nouveau/nouveau_drv.c       |   14 +-
+ drivers/gpu/drm/nouveau/nouveau_drv.h       |   13 +-
  drivers/gpu/drm/nouveau/nouveau_hw.c        |    6 +-
  drivers/gpu/drm/nouveau/nouveau_i2c.c       |   10 +-
- drivers/gpu/drm/nouveau/nouveau_irq.c       |    5 +
- drivers/gpu/drm/nouveau/nouveau_state.c     |    1 +
+ drivers/gpu/drm/nouveau/nouveau_irq.c       |  614 +++++++-
+ drivers/gpu/drm/nouveau/nouveau_state.c     |    6 +-
+ drivers/gpu/drm/nouveau/nv04_crtc.c         |    6 +-
  drivers/gpu/drm/nouveau/nv04_dac.c          |    8 +-
  drivers/gpu/drm/nouveau/nv04_dfp.c          |    4 +-
  drivers/gpu/drm/nouveau/nv04_display.c      |   49 +-
- drivers/gpu/drm/nouveau/nv04_fbcon.c        |    2 +-
+ drivers/gpu/drm/nouveau/nv04_fbcon.c        |    6 +-
  drivers/gpu/drm/nouveau/nv04_fifo.c         |    5 +
  drivers/gpu/drm/nouveau/nv04_tv.c           |    2 +-
  drivers/gpu/drm/nouveau/nv17_tv.c           |    6 +-
  drivers/gpu/drm/nouveau/nv40_fifo.c         |    5 +
  drivers/gpu/drm/nouveau/nv50_dac.c          |    4 +-
  drivers/gpu/drm/nouveau/nv50_display.c      |   54 +-
- drivers/gpu/drm/nouveau/nv50_fbcon.c        |    2 +-
+ drivers/gpu/drm/nouveau/nv50_fb.c           |   32 +
+ drivers/gpu/drm/nouveau/nv50_fbcon.c        |    4 +-
  drivers/gpu/drm/nouveau/nv50_fifo.c         |    5 +
- drivers/gpu/drm/nouveau/nv50_graph.c        |   74 +-
- drivers/gpu/drm/nouveau/nv50_grctx.c        | 2367 +++++++++++++++++++++++++++
+ drivers/gpu/drm/nouveau/nv50_graph.c        |   96 +-
+ drivers/gpu/drm/nouveau/nv50_grctx.c        | 2372 +++++++++++++++++++++++++++
  drivers/gpu/drm/nouveau/nv50_instmem.c      |    2 +-
- 29 files changed, 2870 insertions(+), 419 deletions(-)
+ 33 files changed, 3544 insertions(+), 485 deletions(-)
+ create mode 100644 drivers/gpu/drm/nouveau/nv50_fb.c
  create mode 100644 drivers/gpu/drm/nouveau/nv50_grctx.c
 
 diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
-index 48c290b..32db806 100644
+index 48c290b..7f0d807 100644
 --- a/drivers/gpu/drm/nouveau/Makefile
 +++ b/drivers/gpu/drm/nouveau/Makefile
-@@ -16,7 +16,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+@@ -12,11 +12,11 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+              nouveau_dp.o nouveau_grctx.o \
+              nv04_timer.o \
+              nv04_mc.o nv40_mc.o nv50_mc.o \
+-             nv04_fb.o nv10_fb.o nv40_fb.o \
++             nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \
               nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
               nv04_graph.o nv10_graph.o nv20_graph.o \
               nv40_graph.o nv50_graph.o \
@@ -175,7 +286,7 @@ index 48c290b..32db806 100644
               nv50_crtc.o nv50_dac.o nv50_sor.o \
               nv50_cursor.o nv50_display.o nv50_fbcon.o \
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
-index 0e9cd1d..71247da 100644
+index 0e9cd1d..aed6068 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
 @@ -311,11 +311,11 @@ valid_reg(struct nvbios *bios, uint32_t reg)
@@ -597,7 +708,7 @@ index 0e9cd1d..71247da 100644
  		/*
  		 * DCBs older than v3.0 don't really have a GPIO
  		 * table, instead they keep some GPIO info at fixed
-@@ -5158,30 +5160,67 @@ struct dcb_connector_table_entry *
+@@ -5158,30 +5160,82 @@ struct dcb_connector_table_entry *
  nouveau_bios_connector_entry(struct drm_device *dev, int index)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -654,6 +765,21 @@ index 0e9cd1d..71247da 100644
 +	return type;
 +}
 +
++static void
++apply_dcb_connector_quirks(struct nvbios *bios, int idx)
++{
++	struct dcb_connector_table_entry *cte = &bios->dcb.connector.entry[idx];
++	struct drm_device *dev = bios->dev;
++
++	/* Gigabyte NX85T */
++	if ((dev->pdev->device == 0x0421) &&
++	    (dev->pdev->subsystem_vendor == 0x1458) &&
++	    (dev->pdev->subsystem_device == 0x344c)) {
++		if (cte->type == DCB_CONNECTOR_HDMI_1)
++			cte->type = DCB_CONNECTOR_DVI_I;
++	}
++}
++
  static void
  parse_dcb_connector_table(struct nvbios *bios)
  {
@@ -671,16 +797,28 @@ index 0e9cd1d..71247da 100644
  		NV_DEBUG_KMS(dev, "No DCB connector table present\n");
  		return;
  	}
-@@ -5203,6 +5242,7 @@ parse_dcb_connector_table(struct nvbios *bios)
+@@ -5199,12 +5253,14 @@ parse_dcb_connector_table(struct nvbios *bios)
+ 	entry = conntab + conntab[1];
+ 	cte = &ct->entry[0];
+ 	for (i = 0; i < conntab[2]; i++, entry += conntab[3], cte++) {
++		cte->index = i;
+ 		if (conntab[3] == 2)
  			cte->entry = ROM16(entry[0]);
  		else
  			cte->entry = ROM32(entry[0]);
 +
  		cte->type  = (cte->entry & 0x000000ff) >> 0;
- 		cte->index = (cte->entry & 0x00000f00) >> 8;
+-		cte->index = (cte->entry & 0x00000f00) >> 8;
++		cte->index2 = (cte->entry & 0x00000f00) >> 8;
  		switch (cte->entry & 0x00033000) {
-@@ -5228,10 +5268,33 @@ parse_dcb_connector_table(struct nvbios *bios)
+ 		case 0x00001000:
+ 			cte->gpio_tag = 0x07;
+@@ -5226,12 +5282,43 @@ parse_dcb_connector_table(struct nvbios *bios)
+ 		if (cte->type == 0xff)
+ 			continue;
  
++		apply_dcb_connector_quirks(bios, i);
++
  		NV_INFO(dev, "  %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n",
  			i, cte->entry, cte->type, cte->index, cte->gpio_tag);
 +
@@ -702,10 +840,16 @@ index 0e9cd1d..71247da 100644
 +			break;
 +		default:
 +			cte->type = divine_connector_type(bios, cte->index);
-+			NV_WARN(dev, "unknown type, using 0x%02x", cte->type);
++			NV_WARN(dev, "unknown type, using 0x%02x\n", cte->type);
 +			break;
 +		}
 +
++		if (nouveau_override_conntype) {
++			int type = divine_connector_type(bios, cte->index);
++			if (type != cte->type)
++				NV_WARN(dev, " -> type 0x%02x\n", cte->type);
++		}
++
  	}
  }
  
@@ -714,7 +858,7 @@ index 0e9cd1d..71247da 100644
  {
  	struct dcb_entry *entry = &dcb->entry[dcb->entries];
  
-@@ -5241,7 +5304,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
+@@ -5241,7 +5328,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
  	return entry;
  }
  
@@ -723,7 +867,7 @@ index 0e9cd1d..71247da 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5252,7 +5315,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
+@@ -5252,7 +5339,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
  	/* "or" mostly unused in early gen crt modesetting, 0 is fine */
  }
  
@@ -732,7 +876,7 @@ index 0e9cd1d..71247da 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5279,7 +5342,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
+@@ -5279,7 +5366,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
  #endif
  }
  
@@ -741,7 +885,7 @@ index 0e9cd1d..71247da 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5290,13 +5353,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
+@@ -5290,13 +5377,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
  }
  
  static bool
@@ -757,7 +901,7 @@ index 0e9cd1d..71247da 100644
  		entry->connector = (conn >> 12) & 0xf;
  	entry->bus = (conn >> 16) & 0xf;
  	entry->location = (conn >> 20) & 0x3;
-@@ -5314,7 +5377,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5314,7 +5401,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		 * Although the rest of a CRT conf dword is usually
  		 * zeros, mac biosen have stuff there so we must mask
  		 */
@@ -766,7 +910,7 @@ index 0e9cd1d..71247da 100644
  					 (conf & 0xffff) * 10 :
  					 (conf & 0xff) * 10000;
  		break;
-@@ -5323,7 +5386,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5323,7 +5410,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		uint32_t mask;
  		if (conf & 0x1)
  			entry->lvdsconf.use_straps_for_mode = true;
@@ -775,7 +919,7 @@ index 0e9cd1d..71247da 100644
  			mask = ~0xd;
  			/*
  			 * The laptop in bug 14567 lies and claims to not use
-@@ -5347,7 +5410,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5347,7 +5434,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  			 * Until we even try to use these on G8x, it's
  			 * useless reporting unknown bits.  They all are.
  			 */
@@ -784,7 +928,7 @@ index 0e9cd1d..71247da 100644
  				break;
  
  			NV_ERROR(dev, "Unknown LVDS configuration bits, "
-@@ -5357,7 +5420,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5357,7 +5444,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		}
  	case OUTPUT_TV:
  	{
@@ -793,7 +937,7 @@ index 0e9cd1d..71247da 100644
  			entry->tvconf.has_component_output = conf & (0x8 << 4);
  		else
  			entry->tvconf.has_component_output = false;
-@@ -5384,8 +5447,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5384,8 +5471,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		break;
  	case 0xe:
  		/* weird g80 mobile type that "nv" treats as a terminator */
@@ -805,7 +949,7 @@ index 0e9cd1d..71247da 100644
  	}
  
  	/* unsure what DCB version introduces this, 3.0? */
-@@ -5396,7 +5461,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5396,7 +5485,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  }
  
  static bool
@@ -814,7 +958,7 @@ index 0e9cd1d..71247da 100644
  		  uint32_t conn, uint32_t conf, struct dcb_entry *entry)
  {
  	switch (conn & 0x0000000f) {
-@@ -5462,27 +5527,27 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
+@@ -5462,27 +5551,27 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
  	return true;
  }
  
@@ -850,7 +994,7 @@ index 0e9cd1d..71247da 100644
  {
  	/*
  	 * DCB v2.0 lists each output combination separately.
-@@ -5534,8 +5599,7 @@ static int
+@@ -5534,8 +5623,7 @@ static int
  parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -860,7 +1004,7 @@ index 0e9cd1d..71247da 100644
  	uint16_t dcbptr = 0, i2ctabptr = 0;
  	uint8_t *dcbtable;
  	uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES;
-@@ -5543,9 +5607,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5543,9 +5631,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	int recordlength = 8, confofs = 4;
  	int i;
  
@@ -870,7 +1014,7 @@ index 0e9cd1d..71247da 100644
  	/* get the offset from 0x36 */
  	if (dev_priv->card_type > NV_04) {
  		dcbptr = ROM16(bios->data[0x36]);
-@@ -5567,21 +5628,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5567,21 +5652,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	dcbtable = &bios->data[dcbptr];
  
  	/* get DCB version */
@@ -898,7 +1042,7 @@ index 0e9cd1d..71247da 100644
  		} else {
  			i2ctabptr = ROM16(dcbtable[2]);
  			sig = ROM32(dcbtable[4]);
-@@ -5593,7 +5654,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5593,7 +5678,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  					"signature (%08X)\n", sig);
  			return -EINVAL;
  		}
@@ -907,7 +1051,7 @@ index 0e9cd1d..71247da 100644
  		char sig[8] = { 0 };
  
  		strncpy(sig, (char *)&dcbtable[-7], 7);
-@@ -5641,14 +5702,11 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5641,14 +5726,11 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	if (!i2ctabptr)
  		NV_WARN(dev, "No pointer to DCB I2C port table\n");
  	else {
@@ -925,7 +1069,7 @@ index 0e9cd1d..71247da 100644
  	if (entries > DCB_MAX_NUM_ENTRIES)
  		entries = DCB_MAX_NUM_ENTRIES;
  
-@@ -5673,7 +5731,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5673,7 +5755,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  		NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n",
  			     dcb->entries, connection, config);
  
@@ -934,7 +1078,7 @@ index 0e9cd1d..71247da 100644
  			break;
  	}
  
-@@ -5681,18 +5739,22 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5681,18 +5763,22 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	 * apart for v2.1+ not being known for requiring merging, this
  	 * guarantees dcbent->index is the index of the entry in the rom image
  	 */
@@ -962,7 +1106,7 @@ index 0e9cd1d..71247da 100644
  
  	/*
  	 * DCB 3.0 also has the table in most cases, but there are some cards
-@@ -5700,9 +5762,11 @@ fixup_legacy_connector(struct nvbios *bios)
+@@ -5700,9 +5786,11 @@ fixup_legacy_connector(struct nvbios *bios)
  	 * indices are all 0.  We don't need the connector indices on pre-G80
  	 * chips (yet?) so limit the use to DCB 4.0 and above.
  	 */
@@ -975,7 +1119,7 @@ index 0e9cd1d..71247da 100644
  	/*
  	 * No known connector info before v3.0, so make it up.  the rule here
  	 * is: anything on the same i2c bus is considered to be on the same
-@@ -5710,37 +5774,38 @@ fixup_legacy_connector(struct nvbios *bios)
+@@ -5710,37 +5798,38 @@ fixup_legacy_connector(struct nvbios *bios)
  	 * its own unique connector index.
  	 */
  	for (i = 0; i < dcb->entries; i++) {
@@ -1027,7 +1171,7 @@ index 0e9cd1d..71247da 100644
  	int i;
  
  	for (i = 0; i < dcb->entries; i++) {
-@@ -5826,7 +5891,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
+@@ -5826,7 +5915,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
  uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1036,7 +1180,7 @@ index 0e9cd1d..71247da 100644
  	const uint8_t edid_sig[] = {
  			0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
  	uint16_t offset = 0;
-@@ -5859,7 +5924,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
+@@ -5859,7 +5948,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
  			    struct dcb_entry *dcbent)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1045,7 +1189,7 @@ index 0e9cd1d..71247da 100644
  	struct init_exec iexec = { true, false };
  
  	mutex_lock(&bios->lock);
-@@ -5872,7 +5937,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
+@@ -5872,7 +5961,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
  static bool NVInitVBIOS(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1054,7 +1198,7 @@ index 0e9cd1d..71247da 100644
  
  	memset(bios, 0, sizeof(struct nvbios));
  	mutex_init(&bios->lock);
-@@ -5888,7 +5953,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
+@@ -5888,7 +5977,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
  static int nouveau_parse_vbios_struct(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1063,7 +1207,7 @@ index 0e9cd1d..71247da 100644
  	const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
  	const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
  	int offset;
-@@ -5915,7 +5980,7 @@ int
+@@ -5915,7 +6004,7 @@ int
  nouveau_run_vbios_init(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1072,7 +1216,7 @@ index 0e9cd1d..71247da 100644
  	int i, ret = 0;
  
  	NVLockVgaCrtcs(dev, false);
-@@ -5946,9 +6011,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
+@@ -5946,9 +6035,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
  	}
  
  	if (dev_priv->card_type >= NV_50) {
@@ -1084,7 +1228,7 @@ index 0e9cd1d..71247da 100644
  						       0, 0);
  		}
  	}
-@@ -5962,11 +6027,11 @@ static void
+@@ -5962,11 +6051,11 @@ static void
  nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1098,7 +1242,7 @@ index 0e9cd1d..71247da 100644
  	for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
  		nouveau_i2c_fini(dev, entry);
  }
-@@ -5975,13 +6040,11 @@ int
+@@ -5975,13 +6064,11 @@ int
  nouveau_bios_init(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1113,7 +1257,7 @@ index 0e9cd1d..71247da 100644
  	if (!NVInitVBIOS(dev))
  		return -ENODEV;
  
-@@ -6023,10 +6086,8 @@ nouveau_bios_init(struct drm_device *dev)
+@@ -6023,10 +6110,8 @@ nouveau_bios_init(struct drm_device *dev)
  	bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0);
  
  	ret = nouveau_run_vbios_init(dev);
@@ -1126,10 +1270,10 @@ index 0e9cd1d..71247da 100644
  	/* feature_byte on BMP is poor, but init always sets CR4B */
  	was_locked = NVLockVgaCrtcs(dev, false);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
-index fd94bd6..9f688aa 100644
+index fd94bd6..4f88e69 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
-@@ -34,9 +34,67 @@
+@@ -34,9 +34,68 @@
  
  #define DCB_LOC_ON_CHIP 0
  
@@ -1171,9 +1315,10 @@ index fd94bd6..9f688aa 100644
 +};
 +
 +struct dcb_connector_table_entry {
++	uint8_t index;
 +	uint32_t entry;
 +	enum dcb_connector_type type;
-+	uint8_t index;
++	uint8_t index2;
 +	uint8_t gpio_tag;
 +};
 +
@@ -1198,7 +1343,7 @@ index fd94bd6..9f688aa 100644
  	uint8_t i2c_index;
  	uint8_t heads;
  	uint8_t connector;
-@@ -71,69 +129,22 @@ struct dcb_entry {
+@@ -71,69 +130,22 @@ struct dcb_entry {
  	bool i2c_upper_default;
  };
  
@@ -1272,7 +1417,7 @@ index fd94bd6..9f688aa 100644
  enum nouveau_or {
  	OUTPUT_A = (1 << 0),
  	OUTPUT_B = (1 << 1),
-@@ -190,8 +201,8 @@ struct pll_lims {
+@@ -190,8 +202,8 @@ struct pll_lims {
  	int refclk;
  };
  
@@ -1283,7 +1428,7 @@ index fd94bd6..9f688aa 100644
  
  	uint8_t chip_version;
  
-@@ -199,11 +210,6 @@ struct nouveau_bios_info {
+@@ -199,11 +211,6 @@ struct nouveau_bios_info {
  	uint32_t tvdactestval;
  	uint8_t digital_min_front_porch;
  	bool fp_no_ddc;
@@ -1295,7 +1440,7 @@ index fd94bd6..9f688aa 100644
  
  	struct mutex lock;
  
-@@ -234,7 +240,7 @@ struct nvbios {
+@@ -234,7 +241,7 @@ struct nvbios {
  	uint16_t some_script_ptr; /* BIT I + 14 */
  	uint16_t init96_tbl_ptr; /* BIT I + 16 */
  
@@ -1304,6 +1449,20 @@ index fd94bd6..9f688aa 100644
  
  	struct {
  		int crtchead;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
+index 028719f..0266124 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
+@@ -439,8 +439,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+ 
+ 	switch (bo->mem.mem_type) {
+ 	case TTM_PL_VRAM:
+-		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT |
+-					 TTM_PL_FLAG_SYSTEM);
++		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT);
+ 		break;
+ 	default:
+ 		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
 index ee2b845..88f9bc0 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_calc.c
@@ -1360,7 +1519,7 @@ index adac0f8..6dfb425 100644
  	nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
  	if (chan->pushbuf_bo) {
 diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
-index d2f6335..24327f4 100644
+index d2f6335..14afe1e 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
 @@ -218,7 +218,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
@@ -1402,6 +1561,15 @@ index d2f6335..24327f4 100644
  			if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
  				type = OUTPUT_TMDS;
  			else
+@@ -300,7 +302,7 @@ nouveau_connector_detect(struct drm_connector *connector)
+ 
+ detect_analog:
+ 	nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
+-	if (!nv_encoder)
++	if (!nv_encoder && !nouveau_tv_disable)
+ 		nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
+ 	if (nv_encoder) {
+ 		struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 @@ -321,11 +323,11 @@ detect_analog:
  static void
  nouveau_connector_force(struct drm_connector *connector)
@@ -1714,11 +1882,27 @@ index 89e36ee..8ff9ef5 100644
  };
  #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
  
+diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
+index c8482a1..65c441a 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
++++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
+@@ -190,6 +190,11 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
+ 	nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8);
+ 
+ 	chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
++
++	DRM_MEMORYBARRIER();
++	/* Flush writes. */
++	nouveau_bo_rd32(pb, 0);
++
+ 	nvchan_wr32(chan, 0x8c, chan->dma.ib_put);
+ 	chan->dma.ib_free--;
+ }
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
-index da3b93b..874adf5 100644
+index da3b93b..60a709c 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
-@@ -75,11 +75,11 @@ MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
+@@ -75,14 +75,22 @@ MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
  int nouveau_ignorelid = 0;
  module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
  
@@ -1732,8 +1916,31 @@ index da3b93b..874adf5 100644
  int nouveau_nofbaccel = 0;
  module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
  
++MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
++int nouveau_override_conntype = 0;
++module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
++
++MODULE_PARM_DESC(tv_disable, "Disable TV-out detection\n");
++int nouveau_tv_disable = 0;
++module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
++
+ MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
+ 		 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
+ 		 "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
+@@ -154,9 +162,11 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
+ 	if (pm_state.event == PM_EVENT_PRETHAW)
+ 		return 0;
+ 
++	NV_INFO(dev, "Disabling fbcon acceleration...\n");
+ 	fbdev_flags = dev_priv->fbdev_info->flags;
+ 	dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
+ 
++	NV_INFO(dev, "Unpinning framebuffer(s)...\n");
+ 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ 		struct nouveau_framebuffer *nouveau_fb;
+ 
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
-index 5be0cca..2f8ce42 100644
+index 5be0cca..3b6bbd0 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
 @@ -539,6 +539,9 @@ struct drm_nouveau_private {
@@ -1756,7 +1963,34 @@ index 5be0cca..2f8ce42 100644
  
  	struct nv04_mode_state mode_reg;
  	struct nv04_mode_state saved_reg;
-@@ -1027,6 +1029,7 @@ extern void nv50_graph_destroy_context(struct nouveau_channel *);
+@@ -680,6 +682,7 @@ extern int nouveau_uscript_tmds;
+ extern int nouveau_vram_pushbuf;
+ extern int nouveau_vram_notify;
+ extern int nouveau_fbpercrtc;
++extern int nouveau_tv_disable;
+ extern char *nouveau_tv_norm;
+ extern int nouveau_reg_debug;
+ extern char *nouveau_vbios;
+@@ -687,6 +690,7 @@ extern int nouveau_ctxfw;
+ extern int nouveau_ignorelid;
+ extern int nouveau_nofbaccel;
+ extern int nouveau_noaccel;
++extern int nouveau_override_conntype;
+ 
+ /* nouveau_state.c */
+ extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
+@@ -928,6 +932,10 @@ extern void nv40_fb_takedown(struct drm_device *);
+ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
+ 				      uint32_t, uint32_t);
+ 
++/* nv50_fb.c */
++extern int  nv50_fb_init(struct drm_device *);
++extern void nv50_fb_takedown(struct drm_device *);
++
+ /* nv04_fifo.c */
+ extern int  nv04_fifo_init(struct drm_device *);
+ extern void nv04_fifo_disable(struct drm_device *);
+@@ -1027,6 +1035,7 @@ extern void nv50_graph_destroy_context(struct nouveau_channel *);
  extern int  nv50_graph_load_context(struct nouveau_channel *);
  extern int  nv50_graph_unload_context(struct drm_device *);
  extern void nv50_graph_context_switch(struct drm_device *);
@@ -1822,10 +2056,679 @@ index 70e994d..88583e7 100644
  }
  
 diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
-index 447f9f6..95220dd 100644
+index 447f9f6..2bd59a9 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
-@@ -691,11 +691,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
+@@ -311,6 +311,31 @@ nouveau_print_bitfield_names_(uint32_t value,
+ #define nouveau_print_bitfield_names(val, namelist) \
+ 	nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
+ 
++struct nouveau_enum_names {
++	uint32_t value;
++	const char *name;
++};
++
++static void
++nouveau_print_enum_names_(uint32_t value,
++				const struct nouveau_enum_names *namelist,
++				const int namelist_len)
++{
++	/*
++	 * Caller must have already printed the KERN_* log level for us.
++	 * Also the caller is responsible for adding the newline.
++	 */
++	int i;
++	for (i = 0; i < namelist_len; ++i) {
++		if (value == namelist[i].value) {
++			printk("%s", namelist[i].name);
++			return;
++		}
++	}
++	printk("unknown value 0x%08x", value);
++}
++#define nouveau_print_enum_names(val, namelist) \
++	nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist))
+ 
+ static int
+ nouveau_graph_chid_from_grctx(struct drm_device *dev)
+@@ -427,14 +452,16 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+ 	uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
+ 
+-	NV_INFO(dev, "%s - nSource:", id);
+-	nouveau_print_bitfield_names(nsource, nsource_names);
+-	printk(", nStatus:");
+-	if (dev_priv->card_type < NV_10)
+-		nouveau_print_bitfield_names(nstatus, nstatus_names);
+-	else
+-		nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
+-	printk("\n");
++	if (dev_priv->card_type < NV_50) {
++		NV_INFO(dev, "%s - nSource:", id);
++		nouveau_print_bitfield_names(nsource, nsource_names);
++		printk(", nStatus:");
++		if (dev_priv->card_type < NV_10)
++			nouveau_print_bitfield_names(nstatus, nstatus_names);
++		else
++			nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
++		printk("\n");
++	}
+ 
+ 	NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
+ 					"Data 0x%08x:0x%08x\n",
+@@ -578,27 +605,502 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
+ }
+ 
+ static void
++nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	uint32_t trap[6];
++	int i, ch;
++	uint32_t idx = nv_rd32(dev, 0x100c90);
++	if (idx & 0x80000000) {
++		idx &= 0xffffff;
++		if (display) {
++			for (i = 0; i < 6; i++) {
++				nv_wr32(dev, 0x100c90, idx | i << 24);
++				trap[i] = nv_rd32(dev, 0x100c94);
++			}
++			for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
++				struct nouveau_channel *chan = dev_priv->fifos[ch];
++
++				if (!chan || !chan->ramin)
++					continue;
++
++				if (trap[1] == chan->ramin->instance >> 12)
++					break;
++			}
++			NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
++					name, (trap[5]&0x100?"read":"write"),
++					trap[5]&0xff, trap[4]&0xffff,
++					trap[3]&0xffff, trap[0], trap[2], ch);
++		}
++		nv_wr32(dev, 0x100c90, idx | 0x80000000);
++	} else if (display) {
++		NV_INFO(dev, "%s - no VM fault?\n", name);
++	}
++}
++
++static struct nouveau_enum_names nv50_mp_exec_error_names[] =
++{
++	{ 3, "STACK_UNDERFLOW" },
++	{ 4, "QUADON_ACTIVE" },
++	{ 8, "TIMEOUT" },
++	{ 0x10, "INVALID_OPCODE" },
++	{ 0x40, "BREAKPOINT" },
++};
++
++static void
++nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	uint32_t units = nv_rd32(dev, 0x1540);
++	uint32_t addr, mp10, status, pc, oplow, ophigh;
++	int i;
++	int mps = 0;
++	for (i = 0; i < 4; i++) {
++		if (!(units & 1 << (i+24)))
++			continue;
++		if (dev_priv->chipset < 0xa0)
++			addr = 0x408200 + (tpid << 12) + (i << 7);
++		else
++			addr = 0x408100 + (tpid << 11) + (i << 7);
++		mp10 = nv_rd32(dev, addr + 0x10);
++		status = nv_rd32(dev, addr + 0x14);
++		if (!status)
++			continue;
++		if (display) {
++			nv_rd32(dev, addr + 0x20);
++			pc = nv_rd32(dev, addr + 0x24);
++			oplow = nv_rd32(dev, addr + 0x70);
++			ophigh= nv_rd32(dev, addr + 0x74);
++			NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
++					"TP %d MP %d: ", tpid, i);
++			nouveau_print_enum_names(status,
++					nv50_mp_exec_error_names);
++			printk(" at %06x warp %d, opcode %08x %08x\n",
++					pc&0xffffff, pc >> 24,
++					oplow, ophigh);
++		}
++		nv_wr32(dev, addr + 0x10, mp10);
++		nv_wr32(dev, addr + 0x14, 0);
++		mps++;
++	}
++	if (!mps && display)
++		NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
++				"No MPs claiming errors?\n", tpid);
++}
++
++static void
++nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
++		uint32_t ustatus_new, int display, const char *name)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	int tps = 0;
++	uint32_t units = nv_rd32(dev, 0x1540);
++	int i, r;
++	uint32_t ustatus_addr, ustatus;
++	for (i = 0; i < 16; i++) {
++		if (!(units & (1 << i)))
++			continue;
++		if (dev_priv->chipset < 0xa0)
++			ustatus_addr = ustatus_old + (i << 12);
++		else
++			ustatus_addr = ustatus_new + (i << 11);
++		ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
++		if (!ustatus)
++			continue;
++		tps++;
++		switch (type) {
++		case 6: /* texture error... unknown for now */
++			nv50_pfb_vm_trap(dev, display, name);
++			if (display) {
++				NV_ERROR(dev, "magic set %d:\n", i);
++				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
++					NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
++						nv_rd32(dev, r));
++			}
++			break;
++		case 7: /* MP error */
++			if (ustatus & 0x00010000) {
++				nv50_pgraph_mp_trap(dev, i, display);
++				ustatus &= ~0x00010000;
++			}
++			break;
++		case 8: /* TPDMA error */
++			{
++			uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
++			uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
++			uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
++			uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
++			uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
++			uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
++			uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
++			nv50_pfb_vm_trap(dev, display, name);
++			/* 2d engine destination */
++			if (ustatus & 0x00000010) {
++				if (display) {
++					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
++							i, e14, e10);
++					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
++							i, e0c, e18, e1c, e20, e24);
++				}
++				ustatus &= ~0x00000010;
++			}
++			/* Render target */
++			if (ustatus & 0x00000040) {
++				if (display) {
++					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
++							i, e14, e10);
++					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
++							i, e0c, e18, e1c, e20, e24);
++				}
++				ustatus &= ~0x00000040;
++			}
++			/* CUDA memory: l[], g[] or stack. */
++			if (ustatus & 0x00000080) {
++				if (display) {
++					if (e18 & 0x80000000) {
++						/* g[] read fault? */
++						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
++								i, e14, e10 | ((e18 >> 24) & 0x1f));
++						e18 &= ~0x1f000000;
++					} else if (e18 & 0xc) {
++						/* g[] write fault? */
++						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
++								i, e14, e10 | ((e18 >> 7) & 0x1f));
++						e18 &= ~0x00000f80;
++					} else {
++						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
++								i, e14, e10);
++					}
++					NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
++							i, e0c, e18, e1c, e20, e24);
++				}
++				ustatus &= ~0x00000080;
++			}
++			}
++			break;
++		}
++		if (ustatus) {
++			if (display)
++				NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
++		}
++		nv_wr32(dev, ustatus_addr, 0xc0000000);
++	}
++
++	if (!tps && display)
++		NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
++}
++
++static void
++nv50_pgraph_trap_handler(struct drm_device *dev)
++{
++	struct nouveau_pgraph_trap trap;
++	uint32_t status = nv_rd32(dev, 0x400108);
++	uint32_t ustatus;
++	int display = nouveau_ratelimit();
++
++
++	if (!status && display) {
++		nouveau_graph_trap_info(dev, &trap);
++		nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap);
++		NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n");
++	}
++
++	/* DISPATCH: Relays commands to other units and handles NOTIFY,
++	 * COND, QUERY. If you get a trap from it, the command is still stuck
++	 * in DISPATCH and you need to do something about it. */
++	if (status & 0x001) {
++		ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
++		if (!ustatus && display) {
++			NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
++		}
++
++		/* Known to be triggered by screwed up NOTIFY and COND... */
++		if (ustatus & 0x00000001) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
++			nv_wr32(dev, 0x400500, 0);
++			if (nv_rd32(dev, 0x400808) & 0x80000000) {
++				if (display) {
++					if (nouveau_graph_trapped_channel(dev, &trap.channel))
++						trap.channel = -1;
++					trap.class = nv_rd32(dev, 0x400814);
++					trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc;
++					trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7;
++					trap.data = nv_rd32(dev, 0x40080c);
++					trap.data2 = nv_rd32(dev, 0x400810);
++					nouveau_graph_dump_trap_info(dev,
++							"PGRAPH_TRAP_DISPATCH_FAULT", &trap);
++					NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808));
++					NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848));
++				}
++				nv_wr32(dev, 0x400808, 0);
++			} else if (display) {
++				NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n");
++			}
++			nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
++			nv_wr32(dev, 0x400848, 0);
++			ustatus &= ~0x00000001;
++		}
++		if (ustatus & 0x00000002) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
++			nv_wr32(dev, 0x400500, 0);
++			if (nv_rd32(dev, 0x40084c) & 0x80000000) {
++				if (display) {
++					if (nouveau_graph_trapped_channel(dev, &trap.channel))
++						trap.channel = -1;
++					trap.class = nv_rd32(dev, 0x400814);
++					trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc;
++					trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7;
++					trap.data = nv_rd32(dev, 0x40085c);
++					trap.data2 = 0;
++					nouveau_graph_dump_trap_info(dev,
++							"PGRAPH_TRAP_DISPATCH_QUERY", &trap);
++					NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c));
++				}
++				nv_wr32(dev, 0x40084c, 0);
++			} else if (display) {
++				NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n");
++			}
++			ustatus &= ~0x00000002;
++		}
++		if (ustatus && display)
++			NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus);
++		nv_wr32(dev, 0x400804, 0xc0000000);
++		nv_wr32(dev, 0x400108, 0x001);
++		status &= ~0x001;
++	}
++
++	/* TRAPs other than dispatch use the "normal" trap regs. */
++	if (status && display) {
++		nouveau_graph_trap_info(dev, &trap);
++		nouveau_graph_dump_trap_info(dev,
++				"PGRAPH_TRAP", &trap);
++	}
++
++	/* M2MF: Memory to memory copy engine. */
++	if (status & 0x002) {
++		ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
++		if (!ustatus && display) {
++			NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
++		}
++		if (ustatus & 0x00000001) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
++			ustatus &= ~0x00000001;
++		}
++		if (ustatus & 0x00000002) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
++			ustatus &= ~0x00000002;
++		}
++		if (ustatus & 0x00000004) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
++			ustatus &= ~0x00000004;
++		}
++		NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
++				nv_rd32(dev, 0x406804),
++				nv_rd32(dev, 0x406808),
++				nv_rd32(dev, 0x40680c),
++				nv_rd32(dev, 0x406810));
++		if (ustatus && display)
++			NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus);
++		/* No sane way found yet -- just reset the bugger. */
++		nv_wr32(dev, 0x400040, 2);
++		nv_wr32(dev, 0x400040, 0);
++		nv_wr32(dev, 0x406800, 0xc0000000);
++		nv_wr32(dev, 0x400108, 0x002);
++		status &= ~0x002;
++	}
++
++	/* VFETCH: Fetches data from vertex buffers. */
++	if (status & 0x004) {
++		ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
++		if (!ustatus && display) {
++			NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
++		}
++		if (ustatus & 0x00000001) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
++			NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
++					nv_rd32(dev, 0x400c00),
++					nv_rd32(dev, 0x400c08),
++					nv_rd32(dev, 0x400c0c),
++					nv_rd32(dev, 0x400c10));
++			ustatus &= ~0x00000001;
++		}
++		if (ustatus && display)
++			NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus);
++		nv_wr32(dev, 0x400c04, 0xc0000000);
++		nv_wr32(dev, 0x400108, 0x004);
++		status &= ~0x004;
++	}
++
++	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
++	if (status & 0x008) {
++		ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
++		if (!ustatus && display) {
++			NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
++		}
++		if (ustatus & 0x00000001) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
++			NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
++					nv_rd32(dev, 0x401804),
++					nv_rd32(dev, 0x401808),
++					nv_rd32(dev, 0x40180c),
++					nv_rd32(dev, 0x401810));
++			ustatus &= ~0x00000001;
++		}
++		if (ustatus && display)
++			NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus);
++		/* No sane way found yet -- just reset the bugger. */
++		nv_wr32(dev, 0x400040, 0x80);
++		nv_wr32(dev, 0x400040, 0);
++		nv_wr32(dev, 0x401800, 0xc0000000);
++		nv_wr32(dev, 0x400108, 0x008);
++		status &= ~0x008;
++	}
++
++	/* CCACHE: Handles code and c[] caches and fills them. */
++	if (status & 0x010) {
++		ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
++		if (!ustatus && display) {
++			NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
++		}
++		if (ustatus & 0x00000001) {
++			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
++			NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
++					nv_rd32(dev, 0x405800),
++					nv_rd32(dev, 0x405804),
++					nv_rd32(dev, 0x405808),
++					nv_rd32(dev, 0x40580c),
++					nv_rd32(dev, 0x405810),
++					nv_rd32(dev, 0x405814),
++					nv_rd32(dev, 0x40581c));
++			ustatus &= ~0x00000001;
++		}
++		if (ustatus && display)
++			NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus);
++		nv_wr32(dev, 0x405018, 0xc0000000);
++		nv_wr32(dev, 0x400108, 0x010);
++		status &= ~0x010;
++	}
++
++	/* Unknown, not seen yet... 0x402000 is the only trap status reg
++	 * remaining, so try to handle it anyway. Perhaps related to that
++	 * unknown DMA slot on tesla? */
++	if (status & 0x20) {
++		nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
++		ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
++		if (display)
++			NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
++		nv_wr32(dev, 0x402000, 0xc0000000);
++		/* no status modifiction on purpose */
++	}
++
++	/* TEXTURE: CUDA texturing units */
++	if (status & 0x040) {
++		nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display,
++				"PGRAPH_TRAP_TEXTURE");
++		nv_wr32(dev, 0x400108, 0x040);
++		status &= ~0x040;
++	}
++
++	/* MP: CUDA execution engines. */
++	if (status & 0x080) {
++		nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display,
++				"PGRAPH_TRAP_MP");
++		nv_wr32(dev, 0x400108, 0x080);
++		status &= ~0x080;
++	}
++
++	/* TPDMA:  Handles TP-initiated uncached memory accesses:
++	 * l[], g[], stack, 2d surfaces, render targets. */
++	if (status & 0x100) {
++		nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display,
++				"PGRAPH_TRAP_TPDMA");
++		nv_wr32(dev, 0x400108, 0x100);
++		status &= ~0x100;
++	}
++
++	if (status) {
++		if (display)
++			NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n",
++				status);
++		nv_wr32(dev, 0x400108, status);
++	}
++}
++
++/* There must be a *lot* of these. Will take some time to gather them up. */
++static struct nouveau_enum_names nv50_data_error_names[] =
++{
++	{ 4,	"INVALID_VALUE" },
++	{ 5,	"INVALID_ENUM" },
++	{ 8,	"INVALID_OBJECT" },
++	{ 0xc,	"INVALID_BITFIELD" },
++	{ 0x28,	"MP_NO_REG_SPACE" },
++	{ 0x2b,	"MP_BLOCK_SIZE_MISMATCH" },
++};
++
++static void
+ nv50_pgraph_irq_handler(struct drm_device *dev)
+ {
++	struct nouveau_pgraph_trap trap;
++	int unhandled = 0;
+ 	uint32_t status;
+ 
+ 	while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+-		uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+-
++		/* NOTIFY: You've set a NOTIFY an a command and it's done. */
+ 		if (status & 0x00000001) {
+-			nouveau_pgraph_intr_notify(dev, nsource);
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_NOTIFY", &trap);
+ 			status &= ~0x00000001;
+ 			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
+ 		}
+ 
+-		if (status & 0x00000010) {
+-			nouveau_pgraph_intr_error(dev, nsource |
+-					NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD);
++		/* COMPUTE_QUERY: Purpose and exact cause unknown, happens
++		 * when you write 0x200 to 0x50c0 method 0x31c. */
++		if (status & 0x00000002) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_COMPUTE_QUERY", &trap);
++			status &= ~0x00000002;
++			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002);
++		}
++
++		/* Unknown, never seen: 0x4 */
+ 
++		/* ILLEGAL_MTHD: You used a wrong method for this class. */
++		if (status & 0x00000010) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_pgraph_intr_swmthd(dev, &trap))
++				unhandled = 1;
++			if (unhandled && nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_ILLEGAL_MTHD", &trap);
+ 			status &= ~0x00000010;
+ 			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
+ 		}
+ 
++		/* ILLEGAL_CLASS: You used a wrong class. */
++		if (status & 0x00000020) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_ILLEGAL_CLASS", &trap);
++			status &= ~0x00000020;
++			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020);
++		}
++
++		/* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */
++		if (status & 0x00000040) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_DOUBLE_NOTIFY", &trap);
++			status &= ~0x00000040;
++			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040);
++		}
++
++		/* CONTEXT_SWITCH: PGRAPH needs us to load a new context */
+ 		if (status & 0x00001000) {
+ 			nv_wr32(dev, 0x400500, 0x00000000);
+ 			nv_wr32(dev, NV03_PGRAPH_INTR,
+@@ -613,49 +1115,59 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
+ 			status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ 		}
+ 
+-		if (status & 0x00100000) {
+-			nouveau_pgraph_intr_error(dev, nsource |
+-					NV03_PGRAPH_NSOURCE_DATA_ERROR);
++		/* BUFFER_NOTIFY: Your m2mf transfer finished */
++		if (status & 0x00010000) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_BUFFER_NOTIFY", &trap);
++			status &= ~0x00010000;
++			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000);
++		}
+ 
++		/* DATA_ERROR: Invalid value for this method, or invalid
++		 * state in current PGRAPH context for this operation */
++		if (status & 0x00100000) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit()) {
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_DATA_ERROR", &trap);
++				NV_INFO (dev, "PGRAPH_DATA_ERROR - ");
++				nouveau_print_enum_names(nv_rd32(dev, 0x400110),
++						nv50_data_error_names);
++				printk("\n");
++			}
+ 			status &= ~0x00100000;
+ 			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
+ 		}
+ 
++		/* TRAP: Something bad happened in the middle of command
++		 * execution.  Has a billion types, subtypes, and even
++		 * subsubtypes. */
+ 		if (status & 0x00200000) {
+-			int r;
+-
+-			nouveau_pgraph_intr_error(dev, nsource |
+-					NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
+-
+-			NV_ERROR(dev, "magic set 1:\n");
+-			for (r = 0x408900; r <= 0x408910; r += 4)
+-				NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+-					nv_rd32(dev, r));
+-			nv_wr32(dev, 0x408900,
+-				nv_rd32(dev, 0x408904) | 0xc0000000);
+-			for (r = 0x408e08; r <= 0x408e24; r += 4)
+-				NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+-							nv_rd32(dev, r));
+-			nv_wr32(dev, 0x408e08,
+-				nv_rd32(dev, 0x408e08) | 0xc0000000);
+-
+-			NV_ERROR(dev, "magic set 2:\n");
+-			for (r = 0x409900; r <= 0x409910; r += 4)
+-				NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+-					nv_rd32(dev, r));
+-			nv_wr32(dev, 0x409900,
+-				nv_rd32(dev, 0x409904) | 0xc0000000);
+-			for (r = 0x409e08; r <= 0x409e24; r += 4)
+-				NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
+-					nv_rd32(dev, r));
+-			nv_wr32(dev, 0x409e08,
+-				nv_rd32(dev, 0x409e08) | 0xc0000000);
+-
++			nv50_pgraph_trap_handler(dev);
+ 			status &= ~0x00200000;
+-			nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource);
+ 			nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
+ 		}
+ 
++		/* Unknown, never seen: 0x00400000 */
++
++		/* SINGLE_STEP: Happens on every method if you turned on
++		 * single stepping in 40008c */
++		if (status & 0x01000000) {
++			nouveau_graph_trap_info(dev, &trap);
++			if (nouveau_ratelimit())
++				nouveau_graph_dump_trap_info(dev,
++						"PGRAPH_SINGLE_STEP", &trap);
++			status &= ~0x01000000;
++			nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000);
++		}
++
++		/* 0x02000000 happens when you pause a ctxprog...
++		 * but the only way this can happen that I know is by
++		 * poking the relevant MMIO register, and we don't
++		 * do that. */
++
+ 		if (status) {
+ 			NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n",
+ 				status);
+@@ -672,7 +1184,8 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
+ 	}
+ 
+ 	nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
+-	nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
++	if (nv_rd32(dev, 0x400824) & (1 << 31))
++		nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+ }
+ 
+ static void
+@@ -691,11 +1204,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
  	struct drm_device *dev = (struct drm_device *)arg;
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	uint32_t status, fbdev_flags = 0;
@@ -1840,7 +2743,7 @@ index 447f9f6..95220dd 100644
  	if (dev_priv->fbdev_info) {
  		fbdev_flags = dev_priv->fbdev_info->flags;
  		dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
-@@ -733,5 +736,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
+@@ -733,5 +1249,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
  	if (dev_priv->fbdev_info)
  		dev_priv->fbdev_info->flags = fbdev_flags;
  
@@ -1849,10 +2752,29 @@ index 447f9f6..95220dd 100644
  	return IRQ_HANDLED;
  }
 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
-index a8d77c8..516a8d3 100644
+index a8d77c8..f4ea3e6 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_state.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_state.c
-@@ -391,6 +391,7 @@ nouveau_card_init(struct drm_device *dev)
+@@ -34,7 +34,6 @@
+ #include "nouveau_drm.h"
+ #include "nv50_display.h"
+ 
+-static int nouveau_stub_init(struct drm_device *dev) { return 0; }
+ static void nouveau_stub_takedown(struct drm_device *dev) {}
+ 
+ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+@@ -276,8 +275,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
+ 		engine->timer.init		= nv04_timer_init;
+ 		engine->timer.read		= nv04_timer_read;
+ 		engine->timer.takedown		= nv04_timer_takedown;
+-		engine->fb.init			= nouveau_stub_init;
+-		engine->fb.takedown		= nouveau_stub_takedown;
++		engine->fb.init			= nv50_fb_init;
++		engine->fb.takedown		= nv50_fb_takedown;
+ 		engine->graph.grclass		= nv50_graph_grclass;
+ 		engine->graph.init		= nv50_graph_init;
+ 		engine->graph.takedown		= nv50_graph_takedown;
+@@ -391,6 +390,7 @@ nouveau_card_init(struct drm_device *dev)
  		goto out;
  	engine = &dev_priv->engine;
  	dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
@@ -1860,6 +2782,23 @@ index a8d77c8..516a8d3 100644
  
  	/* Parse BIOS tables / Run init tables if card not POSTed */
  	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
+index d2f143e..9986aba 100644
+--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
++++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
+@@ -230,9 +230,9 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
+ 	struct drm_framebuffer *fb = crtc->fb;
+ 
+ 	/* Calculate our timings */
+-	int horizDisplay	= (mode->crtc_hdisplay >> 3) 	- 1;
+-	int horizStart		= (mode->crtc_hsync_start >> 3) 	- 1;
+-	int horizEnd		= (mode->crtc_hsync_end >> 3) 	- 1;
++	int horizDisplay	= (mode->crtc_hdisplay >> 3)		- 1;
++	int horizStart		= (mode->crtc_hsync_start >> 3) 	+ 1;
++	int horizEnd		= (mode->crtc_hsync_end >> 3)		+ 1;
+ 	int horizTotal		= (mode->crtc_htotal >> 3)		- 5;
+ 	int horizBlankStart	= (mode->crtc_hdisplay >> 3)		- 1;
+ 	int horizBlankEnd	= (mode->crtc_htotal >> 3)		- 1;
 diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
 index 1d73b15..1cb19e3 100644
 --- a/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -1971,18 +2910,30 @@ index ef77215..c7898b4 100644
  	/* Save previous state */
  	NVLockVgaCrtcs(dev, false);
 diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
-index fd01caa..3da90c2 100644
+index fd01caa..813b25c 100644
 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
 +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
-@@ -118,7 +118,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
+@@ -118,8 +118,8 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
  		return;
  	}
  
 -	width = (image->width + 31) & ~31;
-+	width = ALIGN(image->width, 32);
- 	dsize = (width * image->height) >> 5;
+-	dsize = (width * image->height) >> 5;
++	width = ALIGN(image->width, 8);
++	dsize = ALIGN(width * image->height, 32) >> 5;
  
  	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ 	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+@@ -136,8 +136,8 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
+ 			 ((image->dx + image->width) & 0xffff));
+ 	OUT_RING(chan, bg);
+ 	OUT_RING(chan, fg);
+-	OUT_RING(chan, (image->height << 16) | image->width);
+ 	OUT_RING(chan, (image->height << 16) | width);
++	OUT_RING(chan, (image->height << 16) | image->width);
+ 	OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
+ 
+ 	while (dsize) {
 diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
 index f31347b..66fe559 100644
 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -2096,7 +3047,7 @@ index f08f042..1fd9537 100644
  			  load_pattern);
  	} else {
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
-index 90f0bf5..61a89f2 100644
+index 90f0bf5..fac6c88 100644
 --- a/drivers/gpu/drm/nouveau/nv50_display.c
 +++ b/drivers/gpu/drm/nouveau/nv50_display.c
 @@ -370,9 +370,7 @@ nv50_display_init(struct drm_device *dev)
@@ -2141,8 +3092,8 @@ index 90f0bf5..61a89f2 100644
 -		encoders = connector[entry->connector];
 -		if (!(encoders & (1 << entry->type)))
 +	for (i = 0 ; i < dcb->connector.entries; i++) {
-+		if (i != 0 && dcb->connector.entry[i].index ==
-+			      dcb->connector.entry[i - 1].index)
++		if (i != 0 && dcb->connector.entry[i].index2 ==
++			      dcb->connector.entry[i - 1].index2)
  			continue;
 -		connector[entry->connector] = 0;
 -
@@ -2198,8 +3149,46 @@ index 90f0bf5..61a89f2 100644
  			if (bios->fp.dual_link)
  				script |= 0x0100;
  			if (bios->fp.if_is_24bit)
+diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
+new file mode 100644
+index 0000000..a95e694
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nv50_fb.c
+@@ -0,0 +1,32 @@
++#include "drmP.h"
++#include "drm.h"
++#include "nouveau_drv.h"
++#include "nouveau_drm.h"
++
++int
++nv50_fb_init(struct drm_device *dev)
++{
++	/* This is needed to get meaningful information from 100c90
++	 * on traps. No idea what these values mean exactly. */
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++
++	switch (dev_priv->chipset) {
++	case 0x50:
++		nv_wr32(dev, 0x100c90, 0x0707ff);
++		break;
++	case 0xa5:
++	case 0xa8:
++		nv_wr32(dev, 0x100c90, 0x0d0fff);
++		break;
++	default:
++		nv_wr32(dev, 0x100c90, 0x1d07ff);
++		break;
++	}
++
++	return 0;
++}
++
++void
++nv50_fb_takedown(struct drm_device *dev)
++{
++}
 diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
-index 0f57cdf..993c712 100644
+index 0f57cdf..25a3cd8 100644
 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
 +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
 @@ -109,7 +109,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
@@ -2211,6 +3200,15 @@ index 0f57cdf..993c712 100644
  	dwords = (width * image->height) >> 5;
  
  	BEGIN_RING(chan, NvSub2D, 0x0814, 2);
+@@ -233,7 +233,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
+ 	BEGIN_RING(chan, NvSub2D, 0x0808, 3);
+ 	OUT_RING(chan, 0);
+ 	OUT_RING(chan, 0);
+-	OUT_RING(chan, 0);
++	OUT_RING(chan, 1);
+ 	BEGIN_RING(chan, NvSub2D, 0x081c, 1);
+ 	OUT_RING(chan, 1);
+ 	BEGIN_RING(chan, NvSub2D, 0x0840, 4);
 diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
 index df5335a..e20c0e2 100644
 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -2246,7 +3244,7 @@ index df5335a..e20c0e2 100644
  }
  
 diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
-index 6d50480..857a096 100644
+index 6d50480..c62b33a 100644
 --- a/drivers/gpu/drm/nouveau/nv50_graph.c
 +++ b/drivers/gpu/drm/nouveau/nv50_graph.c
 @@ -28,30 +28,7 @@
@@ -2281,7 +3279,39 @@ index 6d50480..857a096 100644
  
  #define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
  
-@@ -111,9 +88,34 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
+@@ -79,6 +56,10 @@ nv50_graph_init_intr(struct drm_device *dev)
+ static void
+ nv50_graph_init_regs__nv(struct drm_device *dev)
+ {
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	uint32_t units = nv_rd32(dev, 0x1540);
++	int i;
++
+ 	NV_DEBUG(dev, "\n");
+ 
+ 	nv_wr32(dev, 0x400804, 0xc0000000);
+@@ -88,6 +69,20 @@ nv50_graph_init_regs__nv(struct drm_device *dev)
+ 	nv_wr32(dev, 0x405018, 0xc0000000);
+ 	nv_wr32(dev, 0x402000, 0xc0000000);
+ 
++	for (i = 0; i < 16; i++) {
++		if (units & 1 << i) {
++			if (dev_priv->chipset < 0xa0) {
++				nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
++				nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
++				nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
++			} else {
++				nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
++				nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
++				nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
++			}
++		}
++	}
++
+ 	nv_wr32(dev, 0x400108, 0xffffffff);
+ 
+ 	nv_wr32(dev, 0x400824, 0x00004000);
+@@ -111,9 +106,34 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
  
  	NV_DEBUG(dev, "\n");
  
@@ -2319,7 +3349,7 @@ index 6d50480..857a096 100644
  
  	nv_wr32(dev, 0x400320, 4);
  	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
-@@ -193,13 +195,13 @@ nv50_graph_create_context(struct nouveau_channel *chan)
+@@ -193,13 +213,13 @@ nv50_graph_create_context(struct nouveau_channel *chan)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
  	struct nouveau_gpuobj *ctx;
@@ -2336,7 +3366,7 @@ index 6d50480..857a096 100644
  				     NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
  	if (ret)
  		return ret;
-@@ -209,7 +211,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
+@@ -209,7 +229,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
  	dev_priv->engine.instmem.prepare_access(dev, true);
  	nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
  	nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
@@ -2345,7 +3375,7 @@ index 6d50480..857a096 100644
  	nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
  	nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
  	nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
-@@ -217,7 +219,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
+@@ -217,12 +237,16 @@ nv50_graph_create_context(struct nouveau_channel *chan)
  	dev_priv->engine.instmem.finish_access(dev);
  
  	dev_priv->engine.instmem.prepare_access(dev, true);
@@ -2360,14 +3390,19 @@ index 6d50480..857a096 100644
 +		nouveau_grctx_vals_load(dev, ctx);
 +	}
  	nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
- 	if ((dev_priv->chipset & 0xf0) == 0xa0)
- 		nv_wo32(dev, ctx, 0x00004/4, 0x00000000);
+-	if ((dev_priv->chipset & 0xf0) == 0xa0)
+-		nv_wo32(dev, ctx, 0x00004/4, 0x00000000);
+-	else
+-		nv_wo32(dev, ctx, 0x0011c/4, 0x00000000);
+ 	dev_priv->engine.instmem.finish_access(dev);
+ 
+ 	return 0;
 diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
 new file mode 100644
-index 0000000..d105fcd
+index 0000000..546b319
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
-@@ -0,0 +1,2367 @@
+@@ -0,0 +1,2372 @@
 +/*
 + * Copyright 2009 Marcin Kościelnicki
 + *
@@ -2434,6 +3469,9 @@ index 0000000..d105fcd
 +#define CP_FLAG_ALWAYS                ((2 * 32) + 13)
 +#define CP_FLAG_ALWAYS_FALSE          0
 +#define CP_FLAG_ALWAYS_TRUE           1
++#define CP_FLAG_INTR                  ((2 * 32) + 15)
++#define CP_FLAG_INTR_NOT_PENDING      0
++#define CP_FLAG_INTR_PENDING          1
 +
 +#define CP_CTX                   0x00100000
 +#define CP_CTX_COUNT             0x000f0000
@@ -2584,6 +3622,8 @@ index 0000000..d105fcd
 +	cp_name(ctx, cp_setup_save);
 +	cp_set (ctx, UNK1D, SET);
 +	cp_wait(ctx, STATUS, BUSY);
++	cp_wait(ctx, INTR, PENDING);
++	cp_bra (ctx, STATUS, BUSY, cp_setup_save);
 +	cp_set (ctx, UNK01, SET);
 +	cp_set (ctx, SWAP_DIRECTION, SAVE);
 +
@@ -2639,7 +3679,7 @@ index 0000000..d105fcd
 +	int offset, base;
 +	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
 +
-+	/* 0800 */
++	/* 0800: DISPATCH */
 +	cp_ctx(ctx, 0x400808, 7);
 +	gr_def(ctx, 0x400814, 0x00000030);
 +	cp_ctx(ctx, 0x400834, 0x32);
@@ -2670,7 +3710,7 @@ index 0000000..d105fcd
 +		gr_def(ctx, 0x400b20, 0x0001629d);
 +	}
 +
-+	/* 0C00 */
++	/* 0C00: VFETCH */
 +	cp_ctx(ctx, 0x400c08, 0x2);
 +	gr_def(ctx, 0x400c08, 0x0000fe0c);
 +
@@ -2696,7 +3736,7 @@ index 0000000..d105fcd
 +	cp_ctx(ctx, 0x401540, 0x5);
 +	gr_def(ctx, 0x401550, 0x00001018);
 +
-+	/* 1800 */
++	/* 1800: STREAMOUT */
 +	cp_ctx(ctx, 0x401814, 0x1);
 +	gr_def(ctx, 0x401814, 0x000000ff);
 +	if (dev_priv->chipset == 0x50) {
@@ -3011,7 +4051,7 @@ index 0000000..d105fcd
 +	if (dev_priv->chipset == 0x50)
 +		cp_ctx(ctx, 0x4063e0, 0x1);
 +
-+	/* 6800 */
++	/* 6800: M2MF */
 +	if (dev_priv->chipset < 0x90) {
 +		cp_ctx(ctx, 0x406814, 0x2b);
 +		gr_def(ctx, 0x406818, 0x00000f80);
@@ -4749,5 +5789,5 @@ index f0dc4e3..de1f5b0 100644
  		return -EINVAL;
  
 -- 
-1.7.0
+1.7.0.1
 


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-13/kernel.spec,v
retrieving revision 1.1945
retrieving revision 1.1946
diff -u -p -r1.1945 -r1.1946
--- kernel.spec	6 Mar 2010 21:10:31 -0000	1.1945
+++ kernel.spec	15 Mar 2010 00:35:48 -0000	1.1946
@@ -1999,6 +1999,9 @@ fi
 # and build.
 
 %changelog
+* Mon Mar 15 2010 Ben Skeggs <bskeggs at redhat.com>
+- nouveau: pull in more fixes from upstream
+
 * Sat Mar 06 2010 Kyle McMartin <kyle at redhat.com>
 - Add libdwarf dep if %with_perftool.
 



More information about the scm-commits mailing list