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