diff --git a/drm-nouveau-nv86-bug.patch b/drm-nouveau-nv86-bug.patch new file mode 100644 index 0000000..750ebbf --- /dev/null +++ b/drm-nouveau-nv86-bug.patch @@ -0,0 +1,229 @@ +From ad3ff4f72ef7fa1e559cc835535025a4b5a746e6 Mon Sep 17 00:00:00 2001 +From: Ben Skeggs +Date: Fri, 22 Oct 2010 10:26:24 +1000 +Subject: [PATCH] drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++ + drivers/gpu/drm/nouveau/nouveau_mem.c | 14 +++----- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 8 ++-- + drivers/gpu/drm/nouveau/nouveau_state.c | 10 ++++++ + drivers/gpu/drm/nouveau/nv50_fifo.c | 5 +++ + drivers/gpu/drm/nouveau/nv50_graph.c | 52 +++++++++++++++++++++++++++++++ + drivers/gpu/drm/nouveau/nv50_instmem.c | 1 - + 7 files changed, 82 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h +index 88b5093..14236b8 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -314,6 +314,7 @@ struct nouveau_fifo_engine { + void (*destroy_context)(struct nouveau_channel *); + int (*load_context)(struct nouveau_channel *); + int (*unload_context)(struct drm_device *); ++ void (*tlb_flush)(struct drm_device *dev); + }; + + struct nouveau_pgraph_object_method { +@@ -346,6 +347,7 @@ struct nouveau_pgraph_engine { + void (*destroy_context)(struct nouveau_channel *); + int (*load_context)(struct nouveau_channel *); + int (*unload_context)(struct drm_device *); ++ void (*tlb_flush)(struct drm_device *dev); + + void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch); +@@ -943,6 +945,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); + extern void nv50_fifo_destroy_context(struct nouveau_channel *); + extern int nv50_fifo_load_context(struct nouveau_channel *); + extern int nv50_fifo_unload_context(struct drm_device *); ++extern void nv50_fifo_tlb_flush(struct drm_device *dev); + + /* nv04_graph.c */ + extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; +@@ -1007,6 +1010,8 @@ 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 *); + extern int nv50_grctx_init(struct nouveau_grctx *); ++extern void nv50_graph_tlb_flush(struct drm_device *dev); ++extern void nv86_graph_tlb_flush(struct drm_device *dev); + + /* nv04_instmem.c */ + extern int nv04_instmem_init(struct drm_device *); +diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c +index 09db6f6..de43b3e 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_mem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c +@@ -174,11 +174,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, + } + } + } +- dev_priv->engine.instmem.flush(dev); + +- nv50_vm_flush(dev, 5); +- nv50_vm_flush(dev, 0); +- nv50_vm_flush(dev, 4); ++ dev_priv->engine.instmem.flush(dev); ++ dev_priv->engine.fifo.tlb_flush(dev); ++ dev_priv->engine.graph.tlb_flush(dev); + nv50_vm_flush(dev, 6); + return 0; + } +@@ -206,11 +205,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) + while (pte < end) + nv_wo32(dev, pgt, pte++, 0); + } +- dev_priv->engine.instmem.flush(dev); + +- nv50_vm_flush(dev, 5); +- nv50_vm_flush(dev, 0); +- nv50_vm_flush(dev, 4); ++ dev_priv->engine.instmem.flush(dev); ++ dev_priv->engine.fifo.tlb_flush(dev); ++ dev_priv->engine.graph.tlb_flush(dev); + nv50_vm_flush(dev, 6); + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +index 491767f..ae9f353 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +@@ -118,8 +118,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + dev_priv->engine.instmem.flush(nvbe->dev); + + if (dev_priv->card_type == NV_50) { +- nv50_vm_flush(dev, 5); /* PGRAPH */ +- nv50_vm_flush(dev, 0); /* PFIFO */ ++ dev_priv->engine.fifo.tlb_flush(dev); ++ dev_priv->engine.graph.tlb_flush(dev); + } + + nvbe->bound = true; +@@ -158,8 +158,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) + dev_priv->engine.instmem.flush(nvbe->dev); + + if (dev_priv->card_type == NV_50) { +- nv50_vm_flush(dev, 5); +- nv50_vm_flush(dev, 0); ++ dev_priv->engine.fifo.tlb_flush(dev); ++ dev_priv->engine.graph.tlb_flush(dev); + } + + nvbe->bound = false; +diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c +index 866f437..32a9d81 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -283,6 +283,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->graph.destroy_context = nv50_graph_destroy_context; + engine->graph.load_context = nv50_graph_load_context; + engine->graph.unload_context = nv50_graph_unload_context; ++ if (dev_priv->chipset != 0x86) ++ engine->graph.tlb_flush = nv50_graph_tlb_flush; ++ else { ++ /* from what i can see nvidia do this on every ++ * pre-NVA3 board except NVAC, but, we've only ++ * ever seen problems on NV86 ++ */ ++ engine->graph.tlb_flush = nv86_graph_tlb_flush; ++ } + engine->fifo.channels = 128; + engine->fifo.init = nv50_fifo_init; + engine->fifo.takedown = nv50_fifo_takedown; +@@ -294,6 +303,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->fifo.destroy_context = nv50_fifo_destroy_context; + engine->fifo.load_context = nv50_fifo_load_context; + engine->fifo.unload_context = nv50_fifo_unload_context; ++ engine->fifo.tlb_flush = nv50_fifo_tlb_flush; + break; + default: + NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); +diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c +index fb0281a..3c1cfde 100644 +--- a/drivers/gpu/drm/nouveau/nv50_fifo.c ++++ b/drivers/gpu/drm/nouveau/nv50_fifo.c +@@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev) + return 0; + } + ++void ++nv50_fifo_tlb_flush(struct drm_device *dev) ++{ ++ nv50_vm_flush(dev, 5); ++} +diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c +index 1413028..8bdbbe4 100644 +--- a/drivers/gpu/drm/nouveau/nv50_graph.c ++++ b/drivers/gpu/drm/nouveau/nv50_graph.c +@@ -403,3 +403,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { + { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ + {} + }; ++ ++void ++nv50_graph_tlb_flush(struct drm_device *dev) ++{ ++ nv50_vm_flush(dev, 0); ++} ++ ++void ++nv86_graph_tlb_flush(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; ++ bool idle, timeout = false; ++ unsigned long flags; ++ u64 start; ++ u32 tmp; ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x400500, 0x00000001, 0x00000000); ++ ++ start = ptimer->read(dev); ++ do { ++ idle = true; ++ ++ for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { ++ if ((tmp & 7) == 1) ++ idle = false; ++ } ++ ++ for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { ++ if ((tmp & 7) == 1) ++ idle = false; ++ } ++ ++ for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { ++ if ((tmp & 7) == 1) ++ idle = false; ++ } ++ } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000)); ++ ++ if (timeout) { ++ NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " ++ "0x%08x 0x%08x 0x%08x 0x%08x\n", ++ nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), ++ nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); ++ } ++ ++ nv50_vm_flush(dev, 0); ++ ++ nv_mask(dev, 0x400500, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++} +diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c +index 0c8a6f2..42fcc65 100644 +--- a/drivers/gpu/drm/nouveau/nv50_instmem.c ++++ b/drivers/gpu/drm/nouveau/nv50_instmem.c +@@ -453,7 +453,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + } + dev_priv->engine.instmem.flush(dev); + +- nv50_vm_flush(dev, 4); + nv50_vm_flush(dev, 6); + + gpuobj->im_bound = 1; +-- +1.7.3.1 + diff --git a/kernel.spec b/kernel.spec index 8093948..4dd7027 100644 --- a/kernel.spec +++ b/kernel.spec @@ -669,13 +669,13 @@ Patch1808: drm-ttm-fix.patch Patch1810: drm-nouveau-updates.patch Patch1811: drm-nouveau-race-fix.patch Patch1812: drm-nouveau-nva3-noaccel.patch +Patch1813: drm-nouveau-nv86-bug.patch Patch1819: drm-intel-big-hammer.patch # intel drm is all merged upstream Patch1824: drm-intel-next.patch # make sure the lvds comes back on lid open Patch1825: drm-intel-make-lvds-work.patch Patch1900: linux-2.6-intel-iommu-igfx.patch - Patch2000: efifb-add-more-models.patch Patch2001: efifb-check-that-the-base-addr-is-plausible-on-pci-systems.patch @@ -1334,6 +1334,7 @@ ApplyPatch drm-ttm-fix.patch ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-nouveau-race-fix.patch ApplyPatch drm-nouveau-nva3-noaccel.patch +ApplyPatch drm-nouveau-nv86-bug.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch