diff options
author | Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 2007-05-08 01:47:41 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2007-05-08 01:47:41 -0400 |
commit | a0a6dd0b221260be1e3da725e6b49797e5fa7429 (patch) | |
tree | bdb04b4abb2f940ee2a6bc002a7c2cd551121ed6 /drivers/char | |
parent | bc07dc7f07a2f2d4d0aa4ffb9597413ad9137d44 (diff) |
via: Try to improve command-buffer chaining.
Bump driver date and patchlevel.
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/drm/via_dma.c | 107 | ||||
-rw-r--r-- | drivers/char/drm/via_drv.h | 5 |
2 files changed, 46 insertions, 66 deletions
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index c0539c6299cf..7635e859b879 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,32 @@ 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)) ; | ||
438 | *dev_priv->last_pause_ptr = pause_addr_lo; | 439 | *dev_priv->last_pause_ptr = pause_addr_lo; |
439 | via_flush_write_combine(); | 440 | via_flush_write_combine(); |
440 | 441 | reader = *(dev_priv->hw_addr_ptr); | |
441 | /* | 442 | ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + |
442 | * The below statement is inserted to really force the flush. | 443 | dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; |
443 | * Not sure it is needed. | ||
444 | */ | ||
445 | |||
446 | while (!*dev_priv->last_pause_ptr) ; | ||
447 | dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; | 444 | dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; |
448 | while (!*dev_priv->last_pause_ptr) ; | ||
449 | 445 | ||
450 | paused = 0; | 446 | if ((ptr - reader) <= dev_priv->dma_diff ) { |
451 | count = 20; | 447 | count = 10000000; |
452 | 448 | 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 | } | 449 | } |
469 | 450 | ||
470 | if (paused && !no_pci_fire) { | 451 | if (paused && !no_pci_fire) { |
471 | uint32_t rgtr, ptr; | 452 | reader = *(dev_priv->hw_addr_ptr); |
472 | uint32_t ptr_low; | 453 | if ((ptr - reader) == dev_priv->dma_diff) { |
473 | 454 | ||
474 | count = 1000000; | 455 | /* |
475 | while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) | 456 | * There is a concern that these writes may stall the PCI bus |
476 | && count--) ; | 457 | * if the GPU is not idle. However, idling the GPU first |
458 | * doesn't make a difference. | ||
459 | */ | ||
477 | 460 | ||
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)); | 461 | VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); |
486 | VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); | 462 | VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); |
487 | VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); | 463 | VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); |
@@ -494,6 +470,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, | |||
494 | static int via_wait_idle(drm_via_private_t * dev_priv) | 470 | static int via_wait_idle(drm_via_private_t * dev_priv) |
495 | { | 471 | { |
496 | int count = 10000000; | 472 | int count = 10000000; |
473 | |||
474 | while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--); | ||
475 | |||
497 | while (count-- && (VIA_READ(VIA_REG_STATUS) & | 476 | while (count-- && (VIA_READ(VIA_REG_STATUS) & |
498 | (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | | 477 | (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | |
499 | VIA_3D_ENG_BUSY))) ; | 478 | VIA_3D_ENG_BUSY))) ; |
@@ -537,6 +516,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) | |||
537 | uint32_t end_addr, end_addr_lo; | 516 | uint32_t end_addr, end_addr_lo; |
538 | uint32_t command; | 517 | uint32_t command; |
539 | uint32_t agp_base; | 518 | uint32_t agp_base; |
519 | uint32_t ptr; | ||
520 | uint32_t reader; | ||
521 | int count; | ||
540 | 522 | ||
541 | dev_priv->dma_low = 0; | 523 | dev_priv->dma_low = 0; |
542 | 524 | ||
@@ -554,7 +536,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) | |||
554 | &pause_addr_hi, &pause_addr_lo, 1) - 1; | 536 | &pause_addr_hi, &pause_addr_lo, 1) - 1; |
555 | 537 | ||
556 | via_flush_write_combine(); | 538 | via_flush_write_combine(); |
557 | while (!*dev_priv->last_pause_ptr) ; | 539 | while(! *dev_priv->last_pause_ptr); |
558 | 540 | ||
559 | VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); | 541 | VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); |
560 | VIA_WRITE(VIA_REG_TRANSPACE, command); | 542 | VIA_WRITE(VIA_REG_TRANSPACE, command); |
@@ -566,6 +548,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) | |||
566 | DRM_WRITEMEMORYBARRIER(); | 548 | DRM_WRITEMEMORYBARRIER(); |
567 | VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); | 549 | VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); |
568 | VIA_READ(VIA_REG_TRANSPACE); | 550 | VIA_READ(VIA_REG_TRANSPACE); |
551 | |||
552 | dev_priv->dma_diff = 0; | ||
553 | |||
554 | count = 10000000; | ||
555 | while (!(VIA_READ(0x41c) & 0x80000000) && count--); | ||
556 | |||
557 | reader = *(dev_priv->hw_addr_ptr); | ||
558 | ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + | ||
559 | dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; | ||
560 | |||
561 | /* | ||
562 | * This is the difference between where we tell the | ||
563 | * command reader to pause and where it actually pauses. | ||
564 | * This differs between hw implementation so we need to | ||
565 | * detect it. | ||
566 | */ | ||
567 | |||
568 | dev_priv->dma_diff = ptr - reader; | ||
569 | } | 569 | } |
570 | 570 | ||
571 | static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) | 571 | static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) |
@@ -592,7 +592,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) | |||
592 | uint32_t pause_addr_lo, pause_addr_hi; | 592 | uint32_t pause_addr_lo, pause_addr_hi; |
593 | uint32_t jump_addr_lo, jump_addr_hi; | 593 | uint32_t jump_addr_lo, jump_addr_hi; |
594 | volatile uint32_t *last_pause_ptr; | 594 | volatile uint32_t *last_pause_ptr; |
595 | uint32_t dma_low_save1, dma_low_save2; | ||
596 | 595 | ||
597 | agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; | 596 | agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; |
598 | via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, | 597 | via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, |
@@ -619,31 +618,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) | |||
619 | &pause_addr_lo, 0); | 618 | &pause_addr_lo, 0); |
620 | 619 | ||
621 | *last_pause_ptr = pause_addr_lo; | 620 | *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 | 621 | ||
633 | last_pause_ptr = | 622 | 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 | } | 623 | } |
646 | 624 | ||
625 | |||
647 | static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) | 626 | static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) |
648 | { | 627 | { |
649 | via_cmdbuf_jump(dev_priv); | 628 | via_cmdbuf_jump(dev_priv); |
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 8b8778d4a423..b46ca8e6306d 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h | |||
@@ -29,11 +29,11 @@ | |||
29 | 29 | ||
30 | #define DRIVER_NAME "via" | 30 | #define DRIVER_NAME "via" |
31 | #define DRIVER_DESC "VIA Unichrome / Pro" | 31 | #define DRIVER_DESC "VIA Unichrome / Pro" |
32 | #define DRIVER_DATE "20061227" | 32 | #define DRIVER_DATE "20070202" |
33 | 33 | ||
34 | #define DRIVER_MAJOR 2 | 34 | #define DRIVER_MAJOR 2 |
35 | #define DRIVER_MINOR 11 | 35 | #define DRIVER_MINOR 11 |
36 | #define DRIVER_PATCHLEVEL 0 | 36 | #define DRIVER_PATCHLEVEL 1 |
37 | 37 | ||
38 | #include "via_verifier.h" | 38 | #include "via_verifier.h" |
39 | 39 | ||
@@ -93,6 +93,7 @@ typedef struct drm_via_private { | |||
93 | unsigned long vram_offset; | 93 | unsigned long vram_offset; |
94 | unsigned long agp_offset; | 94 | unsigned long agp_offset; |
95 | drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; | 95 | drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; |
96 | uint32_t dma_diff; | ||
96 | } drm_via_private_t; | 97 | } drm_via_private_t; |
97 | 98 | ||
98 | enum via_family { | 99 | enum via_family { |