diff options
author | 2013-06-02 18:16:42 +0000 | |
---|---|---|
committer | 2013-06-02 18:16:42 +0000 | |
commit | 3dfa7d27498a5325560a8e3f4d3be695474d35e8 (patch) | |
tree | c5ccedf7d346136b42045ee8da72b95f7633ae18 /sys | |
parent | With HTTP keepalive, relayd only filtered the first request and (diff) | |
download | wireguard-openbsd-3dfa7d27498a5325560a8e3f4d3be695474d35e8.tar.xz wireguard-openbsd-3dfa7d27498a5325560a8e3f4d3be695474d35e8.zip |
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')
-rw-r--r-- | sys/arch/amd64/amd64/lapic.c | 42 | ||||
-rw-r--r-- | sys/arch/i386/i386/lapic.c | 42 |
2 files changed, 48 insertions, 36 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; /* diff --git a/sys/arch/i386/i386/lapic.c b/sys/arch/i386/i386/lapic.c index 495cff631ca..a6a51b68bd6 100644 --- a/sys/arch/i386/i386/lapic.c +++ b/sys/arch/i386/i386/lapic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lapic.c,v 1.31 2010/09/20 06:33:47 matthew Exp $ */ +/* $OpenBSD: lapic.c,v 1.32 2013/06/02 18:16:42 gerhard Exp $ */ /* $NetBSD: lapic.c,v 1.1.2.8 2000/02/23 06:10:50 sommerfeld Exp $ */ /*- @@ -272,6 +272,20 @@ lapic_initclocks(void) extern int gettick(void); /* 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 @@ -286,8 +300,7 @@ extern int gettick(void); /* 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; int i, ef = read_eflags(); @@ -303,27 +316,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_eflags(ef); - dtick = hz * TIMER_DIV(hz) + (starttick-endtick); + dtick = hz * TIMER_DIV(hz); dapic = startapic-endapic; /* |