diff options
author | Gerhard Roth <gerhard@cvs.openbsd.org> | 2013-06-02 18:16:43 +0000 |
---|---|---|
committer | Gerhard Roth <gerhard@cvs.openbsd.org> | 2013-06-02 18:16:43 +0000 |
commit | ac9dbcdec632775c46dd19a4bd6d1d28b60b0244 (patch) | |
tree | 964d3be07ec211310b2aab714fd9d46d4cae63a7 /sys/arch/amd64 | |
parent | 2c2546e21fb0bd23428f8190d046508481682be9 (diff) |
Fix a bug where the calibration loop could show wrong CPU frequencies.
In case the 'starttick' had a rather large value, the code could miss
one or more cycles of the i8254 timer.
ok tedu@
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/amd64/lapic.c | 42 |
1 files changed, 24 insertions, 18 deletions
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index 5f651ae6e33..f558a5821b5 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lapic.c,v 1.27 2010/09/20 06:33:46 matthew Exp $ */ +/* $OpenBSD: lapic.c,v 1.28 2013/06/02 18:16:42 gerhard Exp $ */ /* $NetBSD: lapic.c,v 1.2 2003/05/08 01:04:35 fvdl Exp $ */ /*- @@ -305,6 +305,20 @@ lapic_initclocks(void) extern int gettick(void); /* XXX put in header file */ extern u_long rtclock_tval; /* XXX put in header file */ +static __inline void +wait_next_cycle(void) +{ + unsigned int tick, tlast; + + tlast = (1 << 16); /* i8254 counter has 16 bits at most */ + for (;;) { + tick = gettick(); + if (tick > tlast) + return; + tlast = tick; + } +} + /* * Calibrate the local apic count-down timer (which is running at * bus-clock speed) vs. the i8254 counter/timer (which is running at @@ -319,8 +333,7 @@ extern u_long rtclock_tval; /* XXX put in header file */ void lapic_calibrate_timer(struct cpu_info *ci) { - unsigned int starttick, tick1, tick2, endtick; - unsigned int startapic, apic1, apic2, endapic; + unsigned int startapic, endapic; u_int64_t dtick, dapic, tmp; long rf = read_rflags(); int i; @@ -337,27 +350,20 @@ lapic_calibrate_timer(struct cpu_info *ci) i82489_writereg(LAPIC_ICR_TIMER, 0x80000000); disable_intr(); - starttick = gettick(); + + /* wait for current cycle to finish */ + wait_next_cycle(); + startapic = lapic_gettick(); - for (i = 0; i < hz; i++) { - i8254_delay(2); - do { - tick1 = gettick(); - apic1 = lapic_gettick(); - } while (tick1 < starttick); - i8254_delay(2); - do { - tick2 = gettick(); - apic2 = lapic_gettick(); - } while (tick2 > starttick); - } + /* wait the next hz cycles */ + for (i = 0; i < hz; i++) + wait_next_cycle(); - endtick = gettick(); endapic = lapic_gettick(); write_rflags(rf); - dtick = hz * rtclock_tval + (starttick-endtick); + dtick = hz * rtclock_tval; dapic = startapic-endapic; /* |