Add a set of macros for dealing with the repeated code to wait for a while

reading a register/attempting DMA. Now it'll wait for a certain number
    of seconds rather than a certain number of times through the loop
    before deciding that it's timed out and resetting the hardware. Also,
    add more timeout handling, and reset the draw state after resetting the
    engine.
This commit is contained in:
Eric Anholt 2005-01-20 16:22:04 +00:00
parent dbe45c7159
commit 13c6b2f0b6
3 changed files with 79 additions and 34 deletions

View File

@ -21,6 +21,8 @@
*/
/* $Header$ */
#include <sys/time.h>
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
@ -115,15 +117,15 @@ ATIFlushPixelCache(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
int tries;
CARD32 temp;
TIMEOUT_LOCALS;
if (atic->is_radeon) {
temp = MMIO_IN32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT);
temp |= RADEON_RB2D_DC_FLUSH_ALL;
MMIO_OUT32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT, temp);
for (tries = 1000000; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
if ((MMIO_IN32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT) &
RADEON_RB2D_DC_BUSY) == 0)
break;
@ -133,13 +135,13 @@ ATIFlushPixelCache(ATIScreenInfo *atis)
temp |= R128_PC_FLUSH_ALL;
MMIO_OUT32(mmio, R128_REG_PC_NGUI_CTLSTAT, temp);
for (tries = 1000000; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
if ((MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT) &
R128_PC_BUSY) != R128_PC_BUSY)
break;
}
}
if (tries == 0)
if (TIMEDOUT())
ErrorF("Timeout flushing pixel cache.\n");
}
@ -184,7 +186,6 @@ ATIEngineReset(ATIScreenInfo *atis)
} else {
MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET,
RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_SE |
RADEON_SOFT_RESET_RE |
RADEON_SOFT_RESET_PP |
@ -235,28 +236,31 @@ ATIWaitAvailMMIO(ATIScreenInfo *atis, int n)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
int tries;
TIMEOUT_LOCALS;
if (atis->mmio_avail >= n) {
atis->mmio_avail -= n;
return;
}
if (atic->is_radeon) {
for (tries = 1000000; tries != 0 && atis->mmio_avail < n; tries--)
{
WHILE_NOT_TIMEOUT(.2) {
atis->mmio_avail = MMIO_IN32(mmio,
RADEON_REG_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK;
if (atis->mmio_avail >= n)
break;
}
} else {
for (tries = 1000000; tries != 0 && atis->mmio_avail < n; tries--)
{
WHILE_NOT_TIMEOUT(.2) {
atis->mmio_avail = MMIO_IN32(mmio, R128_REG_GUI_STAT) &
0xfff;
if (atis->mmio_avail >= n)
break;
}
}
if (tries == 0) {
if (TIMEDOUT()) {
ErrorF("Timeout waiting for %d MMIO slots.\n", n);
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
atis->mmio_avail -= n;
}
@ -291,23 +295,25 @@ ATIGetAvailPrimary(ATIScreenInfo *atis)
static void
ATIWaitAvailPrimary(ATIScreenInfo *atis, int n)
{
int tries;
TIMEOUT_LOCALS;
if (atis->cce_pri_avail >= n) {
atis->cce_pri_avail -= n;
return;
}
for (tries = 1000000; tries != 0 && atis->cce_pri_avail < n; tries--)
{
WHILE_NOT_TIMEOUT(.2) {
if (atis->cce_pri_avail >= n)
break;
atis->cce_pri_avail = ATIGetAvailPrimary(atis);
if (atis->cce_pri_avail >= n)
break;
}
if (tries == 0) {
if (TIMEDOUT()) {
ErrorF("Timeout waiting for %d CCE slots (%d avail).\n", n,
atis->cce_pri_avail);
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
atis->cce_pri_avail -= n;
}
@ -316,24 +322,24 @@ void
ATIWaitIdle(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
int tries;
char *mmio = atic->reg_base;
RING_LOCALS;
TIMEOUT_LOCALS;
if (atis->indirectBuffer != NULL)
ATIFlushIndirect(atis, 0);
#ifdef USE_DRI
if (atis->using_dri) {
int ret;
int ret = 0;
int cmd = (atic->is_radeon ? DRM_RADEON_CP_IDLE :
DRM_R128_CCE_IDLE);
for (tries = 100; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(2) {
ret = drmCommandNone(atic->drmFd, cmd);
if (ret != -EBUSY)
break;
}
if (tries == 0) {
if (TIMEDOUT()) {
ATIDebugFifo(atis);
FatalError("Timed out idling CCE (card hung)\n");
}
@ -356,14 +362,15 @@ ATIWaitIdle(ATIScreenInfo *atis)
if (!atic->is_radeon && (atis->using_pseudo || atis->using_dma)) {
ATIWaitAvailPrimary(atis, atis->cce_pri_size);
for (tries = 1000000; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
if ((MMIO_IN32(mmio, R128_REG_PM4_STAT) &
(R128_PM4_BUSY | R128_PM4_GUI_ACTIVE)) == 0)
break;
}
if (tries == 0) {
if (TIMEDOUT()) {
ErrorF("Timeout idling CCE, resetting...\n");
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
}
@ -373,21 +380,22 @@ ATIWaitIdle(ATIScreenInfo *atis)
ATIWaitAvailMMIO(atis, 64);
if (atic->is_radeon) {
for (tries = 1000000; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
if ((MMIO_IN32(mmio, RADEON_REG_RBBM_STATUS) &
RADEON_RBBM_ACTIVE) == 0)
break;
}
} else {
for (tries = 1000000; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
if ((MMIO_IN32(mmio, R128_REG_GUI_STAT) &
R128_GUI_ACTIVE) == 0)
break;
}
}
if (tries == 0) {
if (TIMEDOUT()) {
ErrorF("Timeout idling accelerator, resetting...\n");
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
}
@ -580,12 +588,16 @@ RadeonDispatchIndirectPDMA(ATIScreenInfo *atis)
char *mmio = atic->reg_base;
CARD32 *addr;
int count, avail, reg, i;
TIMEOUT_LOCALS;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
reg = RADEON_REG_CSQ_APER_PRIMARY;
while (count > 0) {
WHILE_NOT_TIMEOUT(3) {
/* 3 seconds is empirical, using render_bench on an r100. */
if (count <= 0)
break;
avail = ATIGetAvailPrimary(atis);
for (i = 0; i < min(count, avail); i++) {
MMIO_OUT32(mmio, reg, *addr++);
@ -596,6 +608,11 @@ RadeonDispatchIndirectPDMA(ATIScreenInfo *atis)
}
count -= i;
}
if (TIMEDOUT()) {
ErrorF("Timeout submitting packets, resetting...\n");
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
}
@ -610,26 +627,30 @@ R128DispatchIndirectDMA(ATIScreenInfo *atis)
char *mmio = atic->reg_base;
CARD32 *addr;
int count, ring_count;
TIMEOUT_LOCALS;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
ring_count = atis->ring_len / 4;
while (count > 0) {
int tries = 0;
WHILE_NOT_TIMEOUT(.2) {
if (count <= 0)
break;
atis->ring_addr[atis->ring_write++] = *addr++;
if (atis->ring_write >= ring_count)
atis->ring_write = 0;
while (atis->ring_write == atis->ring_read) {
atis->ring_read = MMIO_IN32(mmio, ATI_REG_CCE_RPTR);
if (tries++ == 1000000) {
ErrorF("Timeout submitting packets, resetting...\n");
ATIEngineReset(atis);
}
}
count--;
}
if (TIMEDOUT()) {
ErrorF("Timeout submitting packets, resetting...\n");
ATIEngineReset(atis);
ATIDrawSetup(atis->screen->pScreen);
}
/* Workaround for some early Rage 128 ASIC spins where the CCE parser
* may read up to 32 DWORDS beyond the end of the ring buffer memory
* before wrapping around, if the ring buffer was empty and a <32 DWORD

View File

@ -84,6 +84,27 @@ do { \
OUT_RING(val); \
} while (0)
#define TIMEOUT_LOCALS struct timeval _target, _curtime
static inline Bool
tv_le(struct timeval *tv1, struct timeval *tv2)
{
if (tv1->tv_sec < tv2->tv_sec ||
(tv1->tv_sec == tv2->tv_sec && tv1->tv_usec < tv2->tv_usec))
return TRUE;
else
return FALSE;
}
#define WHILE_NOT_TIMEOUT(_timeout) \
gettimeofday(&_target, NULL); \
_target.tv_usec += ((_timeout) * 1000000); \
_target.tv_sec += _target.tv_usec / 1000000; \
_target.tv_usec = _target.tv_usec % 1000000; \
while (gettimeofday(&_curtime, NULL), tv_le(&_curtime, &_target))
#define TIMEDOUT() (!tv_le(&_curtime, &_target))
dmaBuf *
ATIGetDMABuffer(ATIScreenInfo *atis);

View File

@ -23,6 +23,8 @@
*/
/* $Header$ */
#include <sys/time.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -1106,7 +1108,8 @@ ATIDRIGetBuffer(ATIScreenInfo *atis)
drmBufPtr buf = NULL;
int indx = 0;
int size = 0;
int ret, tries;
int ret;
TIMEOUT_LOCALS;
dma.context = atis->serverContext;
dma.send_count = 0;
@ -1122,12 +1125,12 @@ ATIDRIGetBuffer(ATIScreenInfo *atis)
dma.request_sizes = &size;
dma.granted_count = 0;
for (tries = 100; tries != 0; tries--) {
WHILE_NOT_TIMEOUT(.2) {
ret = drmDMA(atic->drmFd, &dma);
if (ret != -EBUSY)
break;
}
if (tries == 0)
if (TIMEDOUT())
FatalError("Timeout fetching DMA buffer (card hung)\n");
if (ret != 0)
FatalError("Error fetching DMA buffer: %d\n", ret);