diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-10-21 20:26:24 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-11-17 23:38:45 -0500 |
commit | 56ac7475350ee646f5f7316abcdf65d3be94da1c (patch) | |
tree | 3a8c51089766a366ee39482834b74e9de0551e98 /drivers/gpu | |
parent | 06ef3e61dd44f76fef89d8e7ad5d6c845f3f345e (diff) |
drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_sgdma.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fifo.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_graph.c | 52 | ||||
-rw-r--r-- | 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 60a54fae90c1..10a8d4e78e58 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -307,6 +307,7 @@ struct nouveau_fifo_engine { | |||
307 | void (*destroy_context)(struct nouveau_channel *); | 307 | void (*destroy_context)(struct nouveau_channel *); |
308 | int (*load_context)(struct nouveau_channel *); | 308 | int (*load_context)(struct nouveau_channel *); |
309 | int (*unload_context)(struct drm_device *); | 309 | int (*unload_context)(struct drm_device *); |
310 | void (*tlb_flush)(struct drm_device *dev); | ||
310 | }; | 311 | }; |
311 | 312 | ||
312 | struct nouveau_pgraph_object_method { | 313 | struct nouveau_pgraph_object_method { |
@@ -339,6 +340,7 @@ struct nouveau_pgraph_engine { | |||
339 | void (*destroy_context)(struct nouveau_channel *); | 340 | void (*destroy_context)(struct nouveau_channel *); |
340 | int (*load_context)(struct nouveau_channel *); | 341 | int (*load_context)(struct nouveau_channel *); |
341 | int (*unload_context)(struct drm_device *); | 342 | int (*unload_context)(struct drm_device *); |
343 | void (*tlb_flush)(struct drm_device *dev); | ||
342 | 344 | ||
343 | void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, | 345 | void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, |
344 | uint32_t size, uint32_t pitch); | 346 | uint32_t size, uint32_t pitch); |
@@ -1014,6 +1016,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); | |||
1014 | extern void nv50_fifo_destroy_context(struct nouveau_channel *); | 1016 | extern void nv50_fifo_destroy_context(struct nouveau_channel *); |
1015 | extern int nv50_fifo_load_context(struct nouveau_channel *); | 1017 | extern int nv50_fifo_load_context(struct nouveau_channel *); |
1016 | extern int nv50_fifo_unload_context(struct drm_device *); | 1018 | extern int nv50_fifo_unload_context(struct drm_device *); |
1019 | extern void nv50_fifo_tlb_flush(struct drm_device *dev); | ||
1017 | 1020 | ||
1018 | /* nvc0_fifo.c */ | 1021 | /* nvc0_fifo.c */ |
1019 | extern int nvc0_fifo_init(struct drm_device *); | 1022 | extern int nvc0_fifo_init(struct drm_device *); |
@@ -1091,6 +1094,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *); | |||
1091 | extern int nv50_graph_unload_context(struct drm_device *); | 1094 | extern int nv50_graph_unload_context(struct drm_device *); |
1092 | extern void nv50_graph_context_switch(struct drm_device *); | 1095 | extern void nv50_graph_context_switch(struct drm_device *); |
1093 | extern int nv50_grctx_init(struct nouveau_grctx *); | 1096 | extern int nv50_grctx_init(struct nouveau_grctx *); |
1097 | extern void nv50_graph_tlb_flush(struct drm_device *dev); | ||
1098 | extern void nv86_graph_tlb_flush(struct drm_device *dev); | ||
1094 | 1099 | ||
1095 | /* nvc0_graph.c */ | 1100 | /* nvc0_graph.c */ |
1096 | extern int nvc0_graph_init(struct drm_device *); | 1101 | extern int nvc0_graph_init(struct drm_device *); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 1165c3e68200..ac3bec024fd5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, | |||
175 | } | 175 | } |
176 | } | 176 | } |
177 | } | 177 | } |
178 | dev_priv->engine.instmem.flush(dev); | ||
179 | 178 | ||
180 | nv50_vm_flush(dev, 5); | 179 | dev_priv->engine.instmem.flush(dev); |
181 | nv50_vm_flush(dev, 0); | 180 | dev_priv->engine.fifo.tlb_flush(dev); |
182 | nv50_vm_flush(dev, 4); | 181 | dev_priv->engine.graph.tlb_flush(dev); |
183 | nv50_vm_flush(dev, 6); | 182 | nv50_vm_flush(dev, 6); |
184 | return 0; | 183 | return 0; |
185 | } | 184 | } |
@@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) | |||
209 | pte++; | 208 | pte++; |
210 | } | 209 | } |
211 | } | 210 | } |
212 | dev_priv->engine.instmem.flush(dev); | ||
213 | 211 | ||
214 | nv50_vm_flush(dev, 5); | 212 | dev_priv->engine.instmem.flush(dev); |
215 | nv50_vm_flush(dev, 0); | 213 | dev_priv->engine.fifo.tlb_flush(dev); |
216 | nv50_vm_flush(dev, 4); | 214 | dev_priv->engine.graph.tlb_flush(dev); |
217 | nv50_vm_flush(dev, 6); | 215 | nv50_vm_flush(dev, 6); |
218 | } | 216 | } |
219 | 217 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 15f358404645..0b309c1cc3d7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c | |||
@@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) | |||
120 | dev_priv->engine.instmem.flush(nvbe->dev); | 120 | dev_priv->engine.instmem.flush(nvbe->dev); |
121 | 121 | ||
122 | if (dev_priv->card_type == NV_50) { | 122 | if (dev_priv->card_type == NV_50) { |
123 | nv50_vm_flush(dev, 5); /* PGRAPH */ | 123 | dev_priv->engine.fifo.tlb_flush(dev); |
124 | nv50_vm_flush(dev, 0); /* PFIFO */ | 124 | dev_priv->engine.graph.tlb_flush(dev); |
125 | } | 125 | } |
126 | 126 | ||
127 | nvbe->bound = true; | 127 | nvbe->bound = true; |
@@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) | |||
162 | dev_priv->engine.instmem.flush(nvbe->dev); | 162 | dev_priv->engine.instmem.flush(nvbe->dev); |
163 | 163 | ||
164 | if (dev_priv->card_type == NV_50) { | 164 | if (dev_priv->card_type == NV_50) { |
165 | nv50_vm_flush(dev, 5); | 165 | dev_priv->engine.fifo.tlb_flush(dev); |
166 | nv50_vm_flush(dev, 0); | 166 | dev_priv->engine.graph.tlb_flush(dev); |
167 | } | 167 | } |
168 | 168 | ||
169 | nvbe->bound = false; | 169 | nvbe->bound = false; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ea3452194cd6..049f755567e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
354 | engine->graph.destroy_context = nv50_graph_destroy_context; | 354 | engine->graph.destroy_context = nv50_graph_destroy_context; |
355 | engine->graph.load_context = nv50_graph_load_context; | 355 | engine->graph.load_context = nv50_graph_load_context; |
356 | engine->graph.unload_context = nv50_graph_unload_context; | 356 | engine->graph.unload_context = nv50_graph_unload_context; |
357 | if (dev_priv->chipset != 0x86) | ||
358 | engine->graph.tlb_flush = nv50_graph_tlb_flush; | ||
359 | else { | ||
360 | /* from what i can see nvidia do this on every | ||
361 | * pre-NVA3 board except NVAC, but, we've only | ||
362 | * ever seen problems on NV86 | ||
363 | */ | ||
364 | engine->graph.tlb_flush = nv86_graph_tlb_flush; | ||
365 | } | ||
357 | engine->fifo.channels = 128; | 366 | engine->fifo.channels = 128; |
358 | engine->fifo.init = nv50_fifo_init; | 367 | engine->fifo.init = nv50_fifo_init; |
359 | engine->fifo.takedown = nv50_fifo_takedown; | 368 | engine->fifo.takedown = nv50_fifo_takedown; |
@@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
365 | engine->fifo.destroy_context = nv50_fifo_destroy_context; | 374 | engine->fifo.destroy_context = nv50_fifo_destroy_context; |
366 | engine->fifo.load_context = nv50_fifo_load_context; | 375 | engine->fifo.load_context = nv50_fifo_load_context; |
367 | engine->fifo.unload_context = nv50_fifo_unload_context; | 376 | engine->fifo.unload_context = nv50_fifo_unload_context; |
377 | engine->fifo.tlb_flush = nv50_fifo_tlb_flush; | ||
368 | engine->display.early_init = nv50_display_early_init; | 378 | engine->display.early_init = nv50_display_early_init; |
369 | engine->display.late_takedown = nv50_display_late_takedown; | 379 | engine->display.late_takedown = nv50_display_late_takedown; |
370 | engine->display.create = nv50_display_create; | 380 | engine->display.create = nv50_display_create; |
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index a46a961102f3..1da65bd60c10 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) | |||
464 | return 0; | 464 | return 0; |
465 | } | 465 | } |
466 | 466 | ||
467 | void | ||
468 | nv50_fifo_tlb_flush(struct drm_device *dev) | ||
469 | { | ||
470 | nv50_vm_flush(dev, 5); | ||
471 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index cbf5ae2f67d4..8b669d0af610 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c | |||
@@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { | |||
402 | { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ | 402 | { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ |
403 | {} | 403 | {} |
404 | }; | 404 | }; |
405 | |||
406 | void | ||
407 | nv50_graph_tlb_flush(struct drm_device *dev) | ||
408 | { | ||
409 | nv50_vm_flush(dev, 0); | ||
410 | } | ||
411 | |||
412 | void | ||
413 | nv86_graph_tlb_flush(struct drm_device *dev) | ||
414 | { | ||
415 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
416 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; | ||
417 | bool idle, timeout = false; | ||
418 | unsigned long flags; | ||
419 | u64 start; | ||
420 | u32 tmp; | ||
421 | |||
422 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | ||
423 | nv_mask(dev, 0x400500, 0x00000001, 0x00000000); | ||
424 | |||
425 | start = ptimer->read(dev); | ||
426 | do { | ||
427 | idle = true; | ||
428 | |||
429 | for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { | ||
430 | if ((tmp & 7) == 1) | ||
431 | idle = false; | ||
432 | } | ||
433 | |||
434 | for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { | ||
435 | if ((tmp & 7) == 1) | ||
436 | idle = false; | ||
437 | } | ||
438 | |||
439 | for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { | ||
440 | if ((tmp & 7) == 1) | ||
441 | idle = false; | ||
442 | } | ||
443 | } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000)); | ||
444 | |||
445 | if (timeout) { | ||
446 | NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " | ||
447 | "0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
448 | nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), | ||
449 | nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); | ||
450 | } | ||
451 | |||
452 | nv50_vm_flush(dev, 0); | ||
453 | |||
454 | nv_mask(dev, 0x400500, 0x00000001, 0x00000001); | ||
455 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | ||
456 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a53fc974332b..b773229b7647 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c | |||
@@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
402 | } | 402 | } |
403 | dev_priv->engine.instmem.flush(dev); | 403 | dev_priv->engine.instmem.flush(dev); |
404 | 404 | ||
405 | nv50_vm_flush(dev, 4); | ||
406 | nv50_vm_flush(dev, 6); | 405 | nv50_vm_flush(dev, 6); |
407 | 406 | ||
408 | gpuobj->im_bound = 1; | 407 | gpuobj->im_bound = 1; |