aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs2008-03-06 22:08:59 -0600
committerBen Skeggs2008-03-06 22:18:34 -0600
commit1ccccbd4ce3463edb459eb193feb572938fce19e (patch)
treeace23a5bff45a664b2e8f4242883398e1ed9db99 /shared-core
parentcd924de02927a091c517b0ac6b9cd8f065ce448c (diff)
downloadexternal-libdrm-1ccccbd4ce3463edb459eb193feb572938fce19e.tar.gz
external-libdrm-1ccccbd4ce3463edb459eb193feb572938fce19e.tar.xz
external-libdrm-1ccccbd4ce3463edb459eb193feb572938fce19e.zip
nouveau: redo channel idle detection
Will hopefully work a bit better than previous code, which depended on knowing the channel's most recent PUT value. Some chips always return 0 on reading these regs, and currently userspace is the only other entity which knows the value.
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/nouveau_fifo.c43
1 files changed, 29 insertions, 14 deletions
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index 8e93207e..d8fda277 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -390,6 +390,34 @@ nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
390 return 0; 390 return 0;
391} 391}
392 392
393static int
394nouveau_channel_idle(struct nouveau_channel *chan)
395{
396 struct drm_device *dev = chan->dev;
397 struct drm_nouveau_private *dev_priv = dev->dev_private;
398 struct nouveau_engine *engine = &dev_priv->Engine;
399 uint32_t caches;
400 int idle;
401
402 caches = NV_READ(NV03_PFIFO_CACHES);
403 NV_WRITE(NV03_PFIFO_CACHES, caches & ~1);
404
405 if (engine->fifo.channel_id(dev) != chan->id) {
406 struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj;
407
408 if (INSTANCE_RD(ramfc, 0) != INSTANCE_RD(ramfc, 1))
409 idle = 0;
410 else
411 idle = 1;
412 } else {
413 idle = (NV_READ(NV04_PFIFO_CACHE1_DMA_GET) ==
414 NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
415 }
416
417 NV_WRITE(NV03_PFIFO_CACHES, caches);
418 return idle;
419}
420
393/* stops a fifo */ 421/* stops a fifo */
394void nouveau_fifo_free(struct nouveau_channel *chan) 422void nouveau_fifo_free(struct nouveau_channel *chan)
395{ 423{
@@ -400,22 +428,9 @@ void nouveau_fifo_free(struct nouveau_channel *chan)
400 428
401 DRM_INFO("%s: freeing fifo %d\n", __func__, chan->id); 429 DRM_INFO("%s: freeing fifo %d\n", __func__, chan->id);
402 430
403 /* Disable channel switching, if this channel isn't currenly
404 * active re-enable it if there's still pending commands.
405 * We really should do a manual context switch here, but I'm
406 * not sure I trust our ability to do this reliably yet..
407 */
408 NV_WRITE(NV03_PFIFO_CACHES, 0);
409 if (engine->fifo.channel_id(dev) != chan->id &&
410 NV_READ(chan->get) != NV_READ(chan->put)) {
411 NV_WRITE(NV03_PFIFO_CACHES, 1);
412 }
413
414 /* Give the channel a chance to idle, wait 2s (hopefully) */ 431 /* Give the channel a chance to idle, wait 2s (hopefully) */
415 t_start = engine->timer.read(dev); 432 t_start = engine->timer.read(dev);
416 while (NV_READ(chan->get) != NV_READ(chan->put) || 433 while (!nouveau_channel_idle(chan)) {
417 NV_READ(NV03_PFIFO_CACHE1_GET) !=
418 NV_READ(NV03_PFIFO_CACHE1_PUT)) {
419 if (engine->timer.read(dev) - t_start > 2000000000ULL) { 434 if (engine->timer.read(dev) - t_start > 2000000000ULL) {
420 DRM_ERROR("Failed to idle channel %d before destroy." 435 DRM_ERROR("Failed to idle channel %d before destroy."
421 "Prepare for strangeness..\n", chan->id); 436 "Prepare for strangeness..\n", chan->id);