summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgerhard <gerhard@openbsd.org>2013-06-02 18:16:42 +0000
committergerhard <gerhard@openbsd.org>2013-06-02 18:16:42 +0000
commit3dfa7d27498a5325560a8e3f4d3be695474d35e8 (patch)
treec5ccedf7d346136b42045ee8da72b95f7633ae18
parentWith HTTP keepalive, relayd only filtered the first request and (diff)
downloadwireguard-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@
-rw-r--r--sys/arch/amd64/amd64/lapic.c42
-rw-r--r--sys/arch/i386/i386/lapic.c42
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;
/*