via: Try to improve command-buffer chaining.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Tue, 8 May 2007 05:47:41 +0000 (15:47 +1000)
committerDave Airlie <airlied@linux.ie>
Tue, 8 May 2007 05:47:41 +0000 (15:47 +1000)
Bump driver date and patchlevel.

Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/via_dma.c
drivers/char/drm/via_drv.h

index c0539c6..7635e85 100644 (file)
@@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
                break;
        case VIA_DMA_INITIALIZED:
                retcode = (dev_priv->ring.virtual_start != NULL) ?
-                   0 : DRM_ERR(EFAULT);
+                       0 : DRM_ERR(EFAULT);
                break;
        default:
                retcode = DRM_ERR(EINVAL);
@@ -432,56 +432,32 @@ 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;
 
+       paused = 0;
        via_flush_write_combine();
-       while (!*(via_get_dma(dev_priv) - 1)) ;
        *dev_priv->last_pause_ptr = pause_addr_lo;
        via_flush_write_combine();
-
-       /*
-        * The below statement is inserted to really force the flush.
-        * Not sure it is needed.
-        */
-
-       while (!*dev_priv->last_pause_ptr) ;
+       reader = *(dev_priv->hw_addr_ptr);
+       ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
+               dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
        dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
-       while (!*dev_priv->last_pause_ptr) ;
 
-       paused = 0;
-       count = 20;
-
-       while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
-       if ((count <= 8) && (count >= 0)) {
-               uint32_t rgtr, ptr;
-               rgtr = *(dev_priv->hw_addr_ptr);
-               ptr = ((volatile char *)dev_priv->last_pause_ptr -
-                     dev_priv->dma_ptr) + dev_priv->dma_offset +
-                     (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
-               if (rgtr <= ptr) {
-                       DRM_ERROR
-                           ("Command regulator\npaused at count %d, address %x, "
-                            "while current pause address is %x.\n"
-                            "Please mail this message to "
-                            "<unichrome-devel@lists.sourceforge.net>\n", count,
-                            rgtr, ptr);
-               }
+       if ((ptr - reader) <= dev_priv->dma_diff ) {
+               count = 10000000;
+               while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
        }
 
        if (paused && !no_pci_fire) {
-               uint32_t rgtr, ptr;
-               uint32_t ptr_low;
+               reader = *(dev_priv->hw_addr_ptr);
+               if ((ptr - reader) == dev_priv->dma_diff) {
 
-               count = 1000000;
-               while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)
-                      && count--) ;
+                       /*
+                        * There is a concern that these writes may stall the PCI bus
+                        * if the GPU is not idle. However, idling the GPU first
+                        * doesn't make a difference.
+                        */
 
-               rgtr = *(dev_priv->hw_addr_ptr);
-               ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
-                   dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
-               ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
-                   ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
-               if (rgtr <= ptr && rgtr >= ptr_low) {
                        VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
                        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
                        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
@@ -494,6 +470,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
 static int via_wait_idle(drm_via_private_t * dev_priv)
 {
        int count = 10000000;
+
+       while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--);
+
        while (count-- && (VIA_READ(VIA_REG_STATUS) &
                           (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
                            VIA_3D_ENG_BUSY))) ;
@@ -537,6 +516,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
        uint32_t end_addr, end_addr_lo;
        uint32_t command;
        uint32_t agp_base;
+       uint32_t ptr;
+       uint32_t reader;
+       int count;
 
        dev_priv->dma_low = 0;
 
@@ -554,7 +536,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
                          &pause_addr_hi, &pause_addr_lo, 1) - 1;
 
        via_flush_write_combine();
-       while (!*dev_priv->last_pause_ptr) ;
+       while(! *dev_priv->last_pause_ptr);
 
        VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
        VIA_WRITE(VIA_REG_TRANSPACE, command);
@@ -566,6 +548,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
        DRM_WRITEMEMORYBARRIER();
        VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
        VIA_READ(VIA_REG_TRANSPACE);
+
+       dev_priv->dma_diff = 0;
+
+       count = 10000000;
+       while (!(VIA_READ(0x41c) & 0x80000000) && count--);
+
+       reader = *(dev_priv->hw_addr_ptr);
+       ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
+           dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
+       /*
+        * This is the difference between where we tell the
+        * command reader to pause and where it actually pauses.
+        * This differs between hw implementation so we need to
+        * detect it.
+        */
+
+       dev_priv->dma_diff = ptr - reader;
 }
 
 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)
        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,
@@ -619,31 +618,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
                      &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);
+       via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
 }
 
+
 static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
 {
        via_cmdbuf_jump(dev_priv);
index 8b8778d..b46ca8e 100644 (file)
 
 #define DRIVER_NAME            "via"
 #define DRIVER_DESC            "VIA Unichrome / Pro"
-#define DRIVER_DATE            "20061227"
+#define DRIVER_DATE            "20070202"
 
 #define DRIVER_MAJOR           2
 #define DRIVER_MINOR           11
-#define DRIVER_PATCHLEVEL      0
+#define DRIVER_PATCHLEVEL      1
 
 #include "via_verifier.h"
 
@@ -93,6 +93,7 @@ typedef struct drm_via_private {
        unsigned long vram_offset;
        unsigned long agp_offset;
        drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
+       uint32_t dma_diff;
 } drm_via_private_t;
 
 enum via_family {