Commit 56ac7475 authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 06ef3e61
...@@ -307,6 +307,7 @@ struct nouveau_fifo_engine { ...@@ -307,6 +307,7 @@ struct nouveau_fifo_engine {
void (*destroy_context)(struct nouveau_channel *); void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *); int (*unload_context)(struct drm_device *);
void (*tlb_flush)(struct drm_device *dev);
}; };
struct nouveau_pgraph_object_method { struct nouveau_pgraph_object_method {
...@@ -339,6 +340,7 @@ struct nouveau_pgraph_engine { ...@@ -339,6 +340,7 @@ struct nouveau_pgraph_engine {
void (*destroy_context)(struct nouveau_channel *); void (*destroy_context)(struct nouveau_channel *);
int (*load_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *);
int (*unload_context)(struct drm_device *); 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, void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
uint32_t size, uint32_t pitch); uint32_t size, uint32_t pitch);
...@@ -1014,6 +1016,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); ...@@ -1014,6 +1016,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *);
extern void nv50_fifo_destroy_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_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *); extern int nv50_fifo_unload_context(struct drm_device *);
extern void nv50_fifo_tlb_flush(struct drm_device *dev);
/* nvc0_fifo.c */ /* nvc0_fifo.c */
extern int nvc0_fifo_init(struct drm_device *); extern int nvc0_fifo_init(struct drm_device *);
...@@ -1091,6 +1094,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *); ...@@ -1091,6 +1094,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *);
extern int nv50_graph_unload_context(struct drm_device *); extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *); 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);
/* nvc0_graph.c */ /* nvc0_graph.c */
extern int nvc0_graph_init(struct drm_device *); extern int nvc0_graph_init(struct drm_device *);
......
...@@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, ...@@ -175,11 +175,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); dev_priv->engine.instmem.flush(dev);
nv50_vm_flush(dev, 0); dev_priv->engine.fifo.tlb_flush(dev);
nv50_vm_flush(dev, 4); dev_priv->engine.graph.tlb_flush(dev);
nv50_vm_flush(dev, 6); nv50_vm_flush(dev, 6);
return 0; return 0;
} }
...@@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) ...@@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
pte++; pte++;
} }
} }
dev_priv->engine.instmem.flush(dev);
nv50_vm_flush(dev, 5); dev_priv->engine.instmem.flush(dev);
nv50_vm_flush(dev, 0); dev_priv->engine.fifo.tlb_flush(dev);
nv50_vm_flush(dev, 4); dev_priv->engine.graph.tlb_flush(dev);
nv50_vm_flush(dev, 6); nv50_vm_flush(dev, 6);
} }
......
...@@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) ...@@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
dev_priv->engine.instmem.flush(nvbe->dev); dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) { if (dev_priv->card_type == NV_50) {
nv50_vm_flush(dev, 5); /* PGRAPH */ dev_priv->engine.fifo.tlb_flush(dev);
nv50_vm_flush(dev, 0); /* PFIFO */ dev_priv->engine.graph.tlb_flush(dev);
} }
nvbe->bound = true; nvbe->bound = true;
...@@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) ...@@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
dev_priv->engine.instmem.flush(nvbe->dev); dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) { if (dev_priv->card_type == NV_50) {
nv50_vm_flush(dev, 5); dev_priv->engine.fifo.tlb_flush(dev);
nv50_vm_flush(dev, 0); dev_priv->engine.graph.tlb_flush(dev);
} }
nvbe->bound = false; nvbe->bound = false;
......
...@@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) ...@@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.destroy_context = nv50_graph_destroy_context;
engine->graph.load_context = nv50_graph_load_context; engine->graph.load_context = nv50_graph_load_context;
engine->graph.unload_context = nv50_graph_unload_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.channels = 128;
engine->fifo.init = nv50_fifo_init; engine->fifo.init = nv50_fifo_init;
engine->fifo.takedown = nv50_fifo_takedown; engine->fifo.takedown = nv50_fifo_takedown;
...@@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) ...@@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.destroy_context = nv50_fifo_destroy_context;
engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.load_context = nv50_fifo_load_context;
engine->fifo.unload_context = nv50_fifo_unload_context; engine->fifo.unload_context = nv50_fifo_unload_context;
engine->fifo.tlb_flush = nv50_fifo_tlb_flush;
engine->display.early_init = nv50_display_early_init; engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown; engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create; engine->display.create = nv50_display_create;
......
...@@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev) ...@@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev)
return 0; return 0;
} }
void
nv50_fifo_tlb_flush(struct drm_device *dev)
{
nv50_vm_flush(dev, 5);
}
...@@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { ...@@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ { 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);
}
...@@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) ...@@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
} }
dev_priv->engine.instmem.flush(dev); dev_priv->engine.instmem.flush(dev);
nv50_vm_flush(dev, 4);
nv50_vm_flush(dev, 6); nv50_vm_flush(dev, 6);
gpuobj->im_bound = 1; gpuobj->im_bound = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment