diff options
-rw-r--r-- | sys/arch/amd64/amd64/microtime.S | 3 | ||||
-rw-r--r-- | sys/arch/amd64/isa/clock.c | 71 |
2 files changed, 72 insertions, 2 deletions
diff --git a/sys/arch/amd64/amd64/microtime.S b/sys/arch/amd64/amd64/microtime.S index 6475d6baba5..ce3c24f01e6 100644 --- a/sys/arch/amd64/amd64/microtime.S +++ b/sys/arch/amd64/amd64/microtime.S @@ -1,4 +1,4 @@ -/* $OpenBSD: microtime.S,v 1.2 2004/03/09 23:05:13 deraadt Exp $ */ +/* $OpenBSD: microtime.S,v 1.3 2004/03/22 19:43:29 nordin Exp $ */ /* $NetBSD: microtime.S,v 1.1 2003/04/26 18:39:30 fvdl Exp $ */ /*- @@ -95,6 +95,7 @@ ENTRY(microtime) # time.tv_usec 2: leaq _C_LABEL(isa_timer_msb_table)(%rip),%rsi movw (%rsi,%rax,2),%ax + leaq _C_LABEL(isa_timer_lsb_table)(%rip),%rsi subw (%rsi,%rdx,2),%ax addq %rax,%r9 # add msb increment diff --git a/sys/arch/amd64/isa/clock.c b/sys/arch/amd64/isa/clock.c index 8c2fc2dab1f..fcf6db666e5 100644 --- a/sys/arch/amd64/isa/clock.c +++ b/sys/arch/amd64/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.2 2004/03/09 23:05:13 deraadt Exp $ */ +/* $OpenBSD: clock.c,v 1.3 2004/03/22 19:43:29 nordin Exp $ */ /* $NetBSD: clock.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ /*- @@ -230,6 +230,8 @@ void startrtclock() { int s; + u_long tval; + u_long t, msb, lsb, quotient, remainder; findcpuspeed(); /* use the clock (while it's free) to find the cpu speed */ @@ -238,6 +240,73 @@ startrtclock() /* Check diagnostic status */ if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ printf("RTC BIOS diagnostic error %b\n", s, NVRAM_DIAG_BITS); + + /* + * Compute timer_tick from hz. We truncate this value (i.e. + * round down) to minimize the possibility of a backward clock + * step if hz is not a nice number. + */ + isa_timer_tick = 1000000 / (u_long) hz; + + /* + * We can't stand any number with an MSB larger than + * TIMER_MSB_TABLE_SIZE will accomodate. + */ + tval = rtclock_tval; + if ((tval / 256) >= ISA_TIMER_MSB_TABLE_SIZE + || TIMER_FREQ > (8*1024*1024)) { + panic("startrtclock: TIMER_FREQ/HZ unsupportable"); + } + isa_timer_count = (u_short) tval; + + /* + * Now compute the translation tables from timer ticks to + * microseconds. We go to some length to ensure all values + * are rounded-to-nearest (i.e. +-0.5 of the exact values) + * as this will ensure the computation + * + * isa_timer_msb_table[msb] - isa_timer_lsb_table[lsb] + * + * will produce a result which is +-1 usec away from the + * correctly rounded conversion (in fact, it'll be exact about + * 75% of the time, 1 too large 12.5% of the time, and 1 too + * small 12.5% of the time). + */ + for (s = 0; s < 256; s++) { + /* LSB table is easy, just divide and round */ + t = ((u_long) s * 1000000 * 2) / TIMER_FREQ; + isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1)); + + /* MSB table is zero unless the MSB is <= isa_timer_count */ + if (s < ISA_TIMER_MSB_TABLE_SIZE) { + msb = ((u_long) s) * 256; + if (msb > tval) { + isa_timer_msb_table[s] = 0; + } else { + /* + * Harder computation here, since multiplying + * the value by 1000000 can overflow a long. + * To avoid 64-bit computations we divide + * the high order byte and the low order + * byte of the numerator separately, adding + * the remainder of the first computation + * into the second. The constraint on + * TIMER_FREQ above should prevent overflow + * here. + */ + msb = tval - msb; + lsb = msb % 256; + msb = (msb / 256) * 1000000; + quotient = msb / TIMER_FREQ; + remainder = msb % TIMER_FREQ; + t = ((remainder * 256 * 2) + + (lsb * 1000000 * 2)) / TIMER_FREQ; + isa_timer_msb_table[s] = (u_short)((t / 2) + + (t & 0x1) + (quotient * 256)); + } + } + } + } int |