aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/via_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm/via_dma.c')
-rw-r--r--drivers/char/drm/via_dma.c111
1 files changed, 46 insertions, 65 deletions
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index c0539c6299cf..13a9c5ca4593 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
252 break; 252 break;
253 case VIA_DMA_INITIALIZED: 253 case VIA_DMA_INITIALIZED:
254 retcode = (dev_priv->ring.virtual_start != NULL) ? 254 retcode = (dev_priv->ring.virtual_start != NULL) ?
255 0 : DRM_ERR(EFAULT); 255 0 : DRM_ERR(EFAULT);
256 break; 256 break;
257 default: 257 default:
258 retcode = DRM_ERR(EINVAL); 258 retcode = DRM_ERR(EINVAL);
@@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
432{ 432{
433 int paused, count; 433 int paused, count;
434 volatile uint32_t *paused_at = dev_priv->last_pause_ptr; 434 volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
435 uint32_t reader,ptr;
435 436
437 paused = 0;
436 via_flush_write_combine(); 438 via_flush_write_combine();
437 while (!*(via_get_dma(dev_priv) - 1)) ; 439 (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
438 *dev_priv->last_pause_ptr = pause_addr_lo; 440 *paused_at = pause_addr_lo;
439 via_flush_write_combine(); 441 via_flush_write_combine();
440 442 (void) *paused_at;
441 /* 443 reader = *(dev_priv->hw_addr_ptr);
442 * The below statement is inserted to really force the flush. 444 ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
443 * Not sure it is needed. 445 dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
444 */
445
446 while (!*dev_priv->last_pause_ptr) ;
447 dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; 446 dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
448 while (!*dev_priv->last_pause_ptr) ;
449 447
450 paused = 0; 448 if ((ptr - reader) <= dev_priv->dma_diff ) {
451 count = 20; 449 count = 10000000;
452 450 while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
453 while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
454 if ((count <= 8) && (count >= 0)) {
455 uint32_t rgtr, ptr;
456 rgtr = *(dev_priv->hw_addr_ptr);
457 ptr = ((volatile char *)dev_priv->last_pause_ptr -
458 dev_priv->dma_ptr) + dev_priv->dma_offset +
459 (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
460 if (rgtr <= ptr) {
461 DRM_ERROR
462 ("Command regulator\npaused at count %d, address %x, "
463 "while current pause address is %x.\n"
464 "Please mail this message to "
465 "<unichrome-devel@lists.sourceforge.net>\n", count,
466 rgtr, ptr);
467 }
468 } 451 }
469 452
470 if (paused && !no_pci_fire) { 453 if (paused && !no_pci_fire) {
471 uint32_t rgtr, ptr; 454 reader = *(dev_priv->hw_addr_ptr);
472 uint32_t ptr_low; 455 if ((ptr - reader) == dev_priv->dma_diff) {
473 456
474 count = 1000000; 457 /*
475 while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) 458 * There is a concern that these writes may stall the PCI bus
476 && count--) ; 459 * if the GPU is not idle. However, idling the GPU first
460 * doesn't make a difference.
461 */
477 462
478 rgtr = *(dev_priv->hw_addr_ptr);
479 ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
480 dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
481
482 ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
483 ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
484 if (rgtr <= ptr && rgtr >= ptr_low) {
485 VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); 463 VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
486 VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); 464 VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
487 VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); 465 VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
@@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
494static int via_wait_idle(drm_via_private_t * dev_priv) 472static int via_wait_idle(drm_via_private_t * dev_priv)
495{ 473{
496 int count = 10000000; 474 int count = 10000000;
475
476 while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--);
477
497 while (count-- && (VIA_READ(VIA_REG_STATUS) & 478 while (count-- && (VIA_READ(VIA_REG_STATUS) &
498 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | 479 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
499 VIA_3D_ENG_BUSY))) ; 480 VIA_3D_ENG_BUSY))) ;
@@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
537 uint32_t end_addr, end_addr_lo; 518 uint32_t end_addr, end_addr_lo;
538 uint32_t command; 519 uint32_t command;
539 uint32_t agp_base; 520 uint32_t agp_base;
521 uint32_t ptr;
522 uint32_t reader;
523 int count;
540 524
541 dev_priv->dma_low = 0; 525 dev_priv->dma_low = 0;
542 526
@@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
554 &pause_addr_hi, &pause_addr_lo, 1) - 1; 538 &pause_addr_hi, &pause_addr_lo, 1) - 1;
555 539
556 via_flush_write_combine(); 540 via_flush_write_combine();
557 while (!*dev_priv->last_pause_ptr) ; 541 (void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
558 542
559 VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); 543 VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
560 VIA_WRITE(VIA_REG_TRANSPACE, command); 544 VIA_WRITE(VIA_REG_TRANSPACE, command);
@@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
566 DRM_WRITEMEMORYBARRIER(); 550 DRM_WRITEMEMORYBARRIER();
567 VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); 551 VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
568 VIA_READ(VIA_REG_TRANSPACE); 552 VIA_READ(VIA_REG_TRANSPACE);
553
554 dev_priv->dma_diff = 0;
555
556 count = 10000000;
557 while (!(VIA_READ(0x41c) & 0x80000000) && count--);
558
559 reader = *(dev_priv->hw_addr_ptr);
560 ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
561 dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
562
563 /*
564 * This is the difference between where we tell the
565 * command reader to pause and where it actually pauses.
566 * This differs between hw implementation so we need to
567 * detect it.
568 */
569
570 dev_priv->dma_diff = ptr - reader;
569} 571}
570 572
571static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) 573static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
@@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
592 uint32_t pause_addr_lo, pause_addr_hi; 594 uint32_t pause_addr_lo, pause_addr_hi;
593 uint32_t jump_addr_lo, jump_addr_hi; 595 uint32_t jump_addr_lo, jump_addr_hi;
594 volatile uint32_t *last_pause_ptr; 596 volatile uint32_t *last_pause_ptr;
595 uint32_t dma_low_save1, dma_low_save2;
596 597
597 agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; 598 agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
598 via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, 599 via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
@@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
619 &pause_addr_lo, 0); 620 &pause_addr_lo, 0);
620 621
621 *last_pause_ptr = pause_addr_lo; 622 *last_pause_ptr = pause_addr_lo;
622 dma_low_save1 = dev_priv->dma_low;
623
624 /*
625 * Now, set a trap that will pause the regulator if it tries to rerun the old
626 * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
627 * and reissues the jump command over PCI, while the regulator has already taken the jump
628 * and actually paused at the current buffer end).
629 * There appears to be no other way to detect this condition, since the hw_addr_pointer
630 * does not seem to get updated immediately when a jump occurs.
631 */
632 623
633 last_pause_ptr = 624 via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
634 via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
635 &pause_addr_lo, 0) - 1;
636 via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
637 &pause_addr_lo, 0);
638 *last_pause_ptr = pause_addr_lo;
639
640 dma_low_save2 = dev_priv->dma_low;
641 dev_priv->dma_low = dma_low_save1;
642 via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
643 dev_priv->dma_low = dma_low_save2;
644 via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
645} 625}
646 626
627
647static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) 628static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
648{ 629{
649 via_cmdbuf_jump(dev_priv); 630 via_cmdbuf_jump(dev_priv);