summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2008-03-16 11:37:17 +0100
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2008-03-16 11:45:57 +0100
commit7d3d15e67de27f7c47859f36bb55002f0c9d52d6 (patch)
treeafafbbdee51d657902d1867f4f3303078683ab7a
parent563fe9dcd4d08de8864ade161258df891f3db471 (diff)
[via] The millionth fixup for the millionth-1 attempt to stabilize the AGP
DMA command submission. It's worth remembering that all new bright ideas on how to make this command reader work properly and according to docs will probably fail :( Bring in some old code.
-rw-r--r--shared-core/via_dma.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c
index 431738a9..63357107 100644
--- a/shared-core/via_dma.c
+++ b/shared-core/via_dma.c
@@ -406,6 +406,8 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
uint32_t reader,ptr;
+ uint32_t data;
+ cycles_t time;
paused = 0;
via_flush_write_combine();
@@ -423,10 +425,17 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
}
+ paused = VIA_READ(0x41c) & 0x80000000;
if (paused && !no_pci_fire) {
+ uint32_t diff;
reader = *(dev_priv->hw_addr_ptr);
- if ((ptr - reader) == dev_priv->dma_diff) {
-
+ diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
+ diff &= (dev_priv->dma_high - 1);
+ if (diff != 0 && diff < (dev_priv->dma_high >> 1)) {
+ DRM_ERROR("Paused at incorrect address. "
+ "0x%08x, 0x%08x 0x%08x\n",
+ ptr, reader, dev_priv->dma_diff);
+ } else if (diff == 0) {
/*
* There is a concern that these writes may stall the PCI bus
* if the GPU is not idle. However, idling the GPU first
@@ -571,14 +580,14 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
uint32_t pause_addr_lo, pause_addr_hi;
uint32_t jump_addr_lo, jump_addr_hi;
volatile uint32_t *last_pause_ptr;
-
+ uint32_t dma_low_save1, dma_low_save2;
+
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
&jump_addr_lo, 0);
dev_priv->dma_wrap = dev_priv->dma_low;
-
/*
* Wrap command buffer to the beginning.
*/
@@ -590,15 +599,40 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
via_dummy_bitblt(dev_priv);
via_dummy_bitblt(dev_priv);
- last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) -1;
+
+ last_pause_ptr =
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0) - 1;
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
&pause_addr_lo, 0);
+
*last_pause_ptr = pause_addr_lo;
+ dma_low_save1 = dev_priv->dma_low;
+
+ /*
+ * Now, set a trap that will pause the regulator if it tries to rerun the old
+ * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
+ * and reissues the jump command over PCI, while the regulator has already taken the jump
+ * and actually paused at the current buffer end).
+ * There appears to be no other way to detect this condition, since the hw_addr_pointer
+ * does not seem to get updated immediately when a jump occurs.
+ */
+ last_pause_ptr =
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0) - 1;
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0);
+ *last_pause_ptr = pause_addr_lo;
+
+ dma_low_save2 = dev_priv->dma_low;
+ dev_priv->dma_low = dma_low_save1;
via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
+ dev_priv->dma_low = dma_low_save2;
+ via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
}
+
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
{
via_cmdbuf_jump(dev_priv);