OSDN Git Service

[via] The millionth fixup for the millionth-1 attempt to stabilize the AGP
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Sun, 16 Mar 2008 10:37:17 +0000 (11:37 +0100)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Sun, 16 Mar 2008 10:45:57 +0000 (11:45 +0100)
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.

shared-core/via_dma.c

index 431738a..6335710 100644 (file)
@@ -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);