From: Alon Ziv Date: Sat, 28 Jul 2007 10:32:26 +0300 Subject: [PATCH] Sane handling of timeouts in WaitForVerticalSync RADEONWaitForVerticalSync() and RADEONWaitForVerticalSync2() need to wait for a timeout specified in milliseconds; looping around usleep() causes the timeout to be unnecessarily long, as the OS may sleep longer than requested (on Linux the minimum actual sleep value is 10ms). The new logic uses gettimeofday() in the loop to see when the (absolute) timeout has arrived. Signed-off-by: Alon Ziv --- src/radeon.h | 17 +++++++++++++++++ src/radeon_driver.c | 18 +++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/radeon.h b/src/radeon.h index a22e481..1f012b1 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -1178,4 +1178,21 @@ static __inline__ void RADEON_SYNC(RADEONInfoPtr info, ScrnInfoPtr pScrn) #endif } +static __inline__ void radeon_init_timeout(struct timeval *endtime, + unsigned int timeout) +{ + gettimeofday(endtime, NULL); + endtime->tv_usec += timeout; + endtime->tv_sec += endtime->tv_usec / 1000000; + endtime->tv_usec %= 1000000; +} + +static __inline__ int radeon_timedout(const struct timeval *endtime) +{ + struct timeval now; + gettimeofday(&now, NULL); + return now.tv_sec == endtime->tv_sec ? + now.tv_usec > endtime->tv_usec : now.tv_sec > endtime->tv_sec; +} + #endif /* _RADEON_H_ */ diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 5c20b0e..98f6b39 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -759,7 +759,7 @@ void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn) RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 crtc_gen_cntl; - int i; + struct timeval timeout; crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || @@ -770,10 +770,10 @@ void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn) OUTREG(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); /* Wait for it to go back up */ - for (i = 0; i < RADEON_TIMEOUT/1000; i++) { - if (INREG(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_SAVE) break; + radeon_init_timeout(&timeout, 2000); + while (!(INREG(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_SAVE) && + !radeon_timed_out(&timeout)) usleep(1); - } } /* Wait for vertical sync on secondary CRTC */ @@ -782,7 +782,7 @@ void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn) RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 crtc2_gen_cntl; - int i; + struct timeval timeout; crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || @@ -793,10 +793,10 @@ void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn) OUTREG(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); /* Wait for it to go back up */ - for (i = 0; i < RADEON_TIMEOUT/1000; i++) { - if (INREG(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_SAVE) break; - usleep(1); - } + radeon_init_timeout(&timeout, 20000); + while (!(INREG(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_SAVE) && + !radeon_timedout(&timeout)) + usleep(100); }