The time-stamp-counter has a higher accuracy than is needed in SeaBIOS. Down shift it to ensure it safely fits in a 32bit variable.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/timer.c | 50 ++++++++++++++++++++++++++++---------------------- src/util.h | 6 +++--- 2 files changed, 31 insertions(+), 25 deletions(-)
diff --git a/src/timer.c b/src/timer.c index c92ebc2..7fa0610 100644 --- a/src/timer.c +++ b/src/timer.c @@ -33,6 +33,8 @@ u16 pmtimer_ioport VARFSEG; u32 pmtimer_wraps VARLOW; u32 pmtimer_last VARLOW;
+u8 ShiftTSC VARFSEG; + void timer_setup(void) { @@ -76,21 +78,25 @@ timer_setup(void) u64 diff = end - start; dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n" , (u32)start, (u32)end, (u32)diff); - u32 t = DIV_ROUND_UP(diff * PMTIMER_HZ, CALIBRATE_COUNT); - TimerKHz = DIV_ROUND_UP(t, 1000 * PMTIMER_TO_PIT); + u64 t = DIV_ROUND_UP(diff * PMTIMER_HZ, CALIBRATE_COUNT); + while (t >= (1<<24)) { + ShiftTSC++; + t >>= 1; + } + TimerKHz = DIV_ROUND_UP((u32)t, 1000 * PMTIMER_TO_PIT);
- dprintf(1, "CPU Mhz=%u\n", t / (1000000 * PMTIMER_TO_PIT)); + dprintf(1, "CPU Mhz=%u\n", (TimerKHz << ShiftTSC) / 1000); }
/* TSC emulation timekeepers */ -u64 TSC_8254 VARLOW; +u32 TSC_8254 VARLOW; int Last_TSC_8254 VARLOW;
-static u64 +static u32 emulate_tsc(void) { /* read timer 0 current count */ - u64 ret = GET_LOW(TSC_8254); + u32 ret = GET_LOW(TSC_8254); /* readback mode has slightly shifted registers, works on all * 8254, readback PIT0 latch */ outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE); @@ -112,7 +118,7 @@ void pmtimer_setup(u16 ioport) TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000); }
-static u64 pmtimer_get(void) +static u32 pmtimer_get(void) { u16 ioport = GET_GLOBAL(pmtimer_ioport); u32 wraps = GET_LOW(pmtimer_wraps); @@ -125,39 +131,39 @@ static u64 pmtimer_get(void) SET_LOW(pmtimer_last, pmtimer);
dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer); - return (u64)wraps << 24 | pmtimer; + return wraps << 24 | pmtimer; }
-static u64 +static u32 get_tsc(void) { if (unlikely(GET_GLOBAL(no_tsc))) return emulate_tsc(); if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) return pmtimer_get(); - return rdtscll(); + return rdtscll() >> GET_GLOBAL(ShiftTSC); }
int -check_tsc(u64 end) +check_tsc(u32 end) { - return (s64)(get_tsc() - end) > 0; + return (s32)(get_tsc() - end) > 0; }
static void -tscdelay(u64 diff) +tscdelay(u32 diff) { - u64 start = get_tsc(); - u64 end = start + diff; + u32 start = get_tsc(); + u32 end = start + diff; while (!check_tsc(end)) cpu_relax(); }
static void -tscsleep(u64 diff) +tscsleep(u32 diff) { - u64 start = get_tsc(); - u64 end = start + diff; + u32 start = get_tsc(); + u32 end = start + diff; while (!check_tsc(end)) yield(); } @@ -183,17 +189,17 @@ void msleep(u32 count) { }
// Return the TSC value that is 'msecs' time in the future. -u64 +u32 calc_future_tsc(u32 msecs) { u32 khz = GET_GLOBAL(TimerKHz); - return get_tsc() + ((u64)khz * msecs); + return get_tsc() + (khz * msecs); } -u64 +u32 calc_future_tsc_usec(u32 usecs) { u32 khz = GET_GLOBAL(TimerKHz); - return get_tsc() + ((u64)DIV_ROUND_UP(khz, 1000) * usecs); + return get_tsc() + DIV_ROUND_UP(khz * usecs, 1000); }
diff --git a/src/util.h b/src/util.h index a91b7f8..bc2fd00 100644 --- a/src/util.h +++ b/src/util.h @@ -285,7 +285,7 @@ void releaseRTC(void); u32 ticks_to_ms(u32 ticks); u32 ticks_from_ms(u32 ms); void pmtimer_setup(u16 ioport); -int check_tsc(u64 end); +int check_tsc(u32 end); void timer_setup(void); void ndelay(u32 count); void udelay(u32 count); @@ -293,8 +293,8 @@ void mdelay(u32 count); void nsleep(u32 count); void usleep(u32 count); void msleep(u32 count); -u64 calc_future_tsc(u32 msecs); -u64 calc_future_tsc_usec(u32 usecs); +u32 calc_future_tsc(u32 msecs); +u32 calc_future_tsc_usec(u32 usecs); u32 calc_future_timer_ticks(u32 count); u32 calc_future_timer(u32 msecs); int check_timer(u32 end);