diff --git a/hw/kdrive/ati/ati_dma.c b/hw/kdrive/ati/ati_dma.c index 975707668..1acb8e544 100644 --- a/hw/kdrive/ati/ati_dma.c +++ b/hw/kdrive/ati/ati_dma.c @@ -21,6 +21,8 @@ */ /* $Header$ */ +#include + #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 diff --git a/hw/kdrive/ati/ati_dma.h b/hw/kdrive/ati/ati_dma.h index 76c7733de..62501fa8f 100644 --- a/hw/kdrive/ati/ati_dma.h +++ b/hw/kdrive/ati/ati_dma.h @@ -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); diff --git a/hw/kdrive/ati/ati_dri.c b/hw/kdrive/ati/ati_dri.c index 9b792b158..1ac75cf0a 100644 --- a/hw/kdrive/ati/ati_dri.c +++ b/hw/kdrive/ati/ati_dri.c @@ -23,6 +23,8 @@ */ /* $Header$ */ +#include + #ifdef HAVE_CONFIG_H #include #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);