summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorGerhard Roth <gerhard@cvs.openbsd.org>2013-06-02 18:16:43 +0000
committerGerhard Roth <gerhard@cvs.openbsd.org>2013-06-02 18:16:43 +0000
commitac9dbcdec632775c46dd19a4bd6d1d28b60b0244 (patch)
tree964d3be07ec211310b2aab714fd9d46d4cae63a7 /sys/arch/amd64
parent2c2546e21fb0bd23428f8190d046508481682be9 (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.c42
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;
/*