From 6c04185857694b2293046b7ea1d4515404a740c3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 2 Feb 2007 09:15:44 +0100 Subject: via: Try to improve command-buffer chaining. Bump driver date and patchlevel. --- shared-core/via_dma.c | 129 ++++++++++++++++++++------------------------------ 1 file changed, 51 insertions(+), 78 deletions(-) (limited to 'shared-core/via_dma.c') diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c index a08d7d5a..09159634 100644 --- a/shared-core/via_dma.c +++ b/shared-core/via_dma.c @@ -299,7 +299,7 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd) cmd->size, dev, 1))) { return ret; } - + vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); if (vb == NULL) { return DRM_ERR(EAGAIN); @@ -433,70 +433,46 @@ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv) * modifying the pause address stored in the buffer itself. If * the regulator has already paused, restart it. */ + static int via_hook_segment(drm_via_private_t *dev_priv, uint32_t pause_addr_hi, uint32_t pause_addr_lo, int no_pci_fire) { 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 " - "\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; - - count = 1000000; - while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) - && count--); - - 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) { + reader = *(dev_priv->hw_addr_ptr); + if ((ptr - reader) == dev_priv->dma_diff) { + + /* + * 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. + */ + 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); VIA_READ(VIA_REG_TRANSPACE); - } + } } + return paused; } @@ -505,6 +481,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))) ; @@ -551,7 +530,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; @@ -581,6 +562,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) @@ -598,20 +597,18 @@ static inline void via_dummy_bitblt(drm_via_private_t * dev_priv) uint32_t *vb = via_get_dma(dev_priv); SetReg2DAGP(0x0C, (0 | (0 << 16))); SetReg2DAGP(0x10, 0 | (0 << 16)); - SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); + SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); } - static void via_cmdbuf_jump(drm_via_private_t * dev_priv) { uint32_t agp_base; 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, + via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, &jump_addr_lo, 0); dev_priv->dma_wrap = dev_priv->dma_low; @@ -627,38 +624,14 @@ 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; - 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, + 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; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + 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); } -- cgit v1.2.3