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 | |
| parent | 06ef3e61dd44f76fef89d8e7ad5d6c845f3f345e (diff) | |
drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
| -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; |
