From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Linus Torvalds <torvalds@osdl.org>, Ingo Molnar <mingo@elte.hu>,
Alok Kataria <akataria@vmware.com>,
Arjan van de Veen <arjan@infradead.org>
Subject: [RFC patch 4/4] x86: TSC make the calibration loop smarter
Date: Thu, 04 Sep 2008 15:18:59 -0000 [thread overview]
Message-ID: <20080904151249.783722713@linutronix.de> (raw)
In-Reply-To: <20080904150339.896115280@linutronix.de>
[-- Attachment #1: tsc-loop-smarter.patch --]
[-- Type: text/plain, Size: 6786 bytes --]
The last changes made the calibration loop 250ms long which is far
too much. Try to do that more clever.
Experiments have shown that using a 10ms delay for the PIT based calibration
gives us a good enough value. If we have a reference (HPET/PMTIMER) and the
result of the PIT and the reference is close enough, then we can break out of
the calibration loop on a match right away and use the reference value.
Otherwise we just loop 3 times and decide then, which value to take.
One caveat is that for virtualized environments the PIT calibration often does
not work at all and I found out that 10us is a bit too short as well for the
reference to give a sane result. The solution here is to make the last loop
longer when the first two PIT calibrations failed.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/tsc.c | 95 ++++++++++++++++++++++++++++++--------------------
1 file changed, 58 insertions(+), 37 deletions(-)
Index: linux-2.6/arch/x86/kernel/tsc.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/tsc.c
+++ linux-2.6/arch/x86/kernel/tsc.c
@@ -159,9 +159,14 @@ static unsigned long calc_pmtimer_ref(u6
return (unsigned long) deltatsc;
}
-#define CAL_MS 50
+#define CAL_MS 10
#define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS))
-#define CAL_PIT_LOOPS 5000
+#define CAL_PIT_LOOPS 1000
+
+#define CAL2_MS 50
+#define CAL2_LATCH (CLOCK_TICK_RATE / (1000 / CAL2_MS))
+#define CAL2_PIT_LOOPS 5000
+
/*
* Try to calibrate the TSC against the Programmable
@@ -170,7 +175,7 @@ static unsigned long calc_pmtimer_ref(u6
*
* Return ULONG_MAX on failure to calibrate.
*/
-static unsigned long pit_calibrate_tsc(void)
+static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin)
{
u64 tsc, t1, t2, delta;
unsigned long tscmin, tscmax;
@@ -185,8 +190,8 @@ static unsigned long pit_calibrate_tsc(v
* (LSB then MSB) to begin countdown.
*/
outb(0xb0, 0x43);
- outb(CAL_LATCH & 0xff, 0x42);
- outb(CAL_LATCH >> 8, 0x42);
+ outb(latch & 0xff, 0x42);
+ outb(latch >> 8, 0x42);
tsc = t1 = t2 = get_cycles();
@@ -207,18 +212,18 @@ static unsigned long pit_calibrate_tsc(v
/*
* Sanity checks:
*
- * If we were not able to read the PIT more than PIT_MIN_LOOPS
+ * If we were not able to read the PIT more than loopmin
* times, then we have been hit by a massive SMI
*
* If the maximum is 10 times larger than the minimum,
* then we got hit by an SMI as well.
*/
- if (pitcnt < CAL_PIT_LOOPS || tscmax > 10 * tscmin)
+ if (pitcnt < loopmin || tscmax > 10 * tscmin)
return ULONG_MAX;
/* Calculate the PIT value */
delta = t2 - t1;
- do_div(delta, CAL_MS);
+ do_div(delta, ms);
return delta;
}
@@ -230,8 +235,8 @@ unsigned long native_calibrate_tsc(void)
{
u64 tsc1, tsc2, delta, ref1, ref2;
unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
- unsigned long flags;
- int hpet = is_hpet_enabled(), i;
+ unsigned long flags, latch, ms;
+ int hpet = is_hpet_enabled(), i, loopmin;
/*
* Run 5 calibration loops to get the lowest frequency value
@@ -257,7 +262,13 @@ unsigned long native_calibrate_tsc(void)
* calibration delay loop as we have to wait for a certain
* amount of time anyway.
*/
- for (i = 0; i < 5; i++) {
+
+ /* Preset PIT loop values */
+ latch = CAL_LATCH;
+ ms = CAL_MS;
+ loopmin = CAL_PIT_LOOPS;
+
+ for (i = 0; i < 3; i++) {
unsigned long tsc_pit_khz;
/*
@@ -268,7 +279,7 @@ unsigned long native_calibrate_tsc(void)
*/
local_irq_save(flags);
tsc1 = tsc_read_refs(&ref1, hpet);
- tsc_pit_khz = pit_calibrate_tsc();
+ tsc_pit_khz = pit_calibrate_tsc(latch, ms, loopmin);
tsc2 = tsc_read_refs(&ref2, hpet);
local_irq_restore(flags);
@@ -290,6 +301,35 @@ unsigned long native_calibrate_tsc(void)
tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2);
tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2);
+
+ /* Check the reference deviation */
+ delta = ((u64) tsc_pit_min) * 100;
+ do_div(delta, tsc_ref_min);
+
+ /*
+ * If both calibration results are inside a 10% window
+ * then we can be sure, that the calibration
+ * succeeded. We break out of the loop right away. We
+ * use the reference value, as it is more precise.
+ */
+ if (delta >= 90 && delta <= 110) {
+ printk(KERN_INFO
+ "TSC: PIT calibration matches %s. %d loops\n",
+ hpet ? "HPET" : "PMTIMER", i + 1);
+ return tsc_ref_min;
+ }
+
+ /*
+ * Check whether PIT failed more than once. This
+ * happens in virtualized environments. We need to
+ * give the virtual PC a slightly longer timeframe for
+ * the HPET/PMTIMER to make the result precise.
+ */
+ if (i == 1 && tsc_pit_min == ULONG_MAX) {
+ latch = CAL2_LATCH;
+ ms = CAL2_MS;
+ loopmin = CAL2_PIT_LOOPS;
+ }
}
/*
@@ -308,7 +348,7 @@ unsigned long native_calibrate_tsc(void)
/* The alternative source failed as well, disable TSC */
if (tsc_ref_min == ULONG_MAX) {
printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
- "failed due to SMI disturbance.\n");
+ "failed.\n");
return 0;
}
@@ -327,37 +367,18 @@ unsigned long native_calibrate_tsc(void)
/* The alternative source failed, use the PIT calibration value */
if (tsc_ref_min == ULONG_MAX) {
- printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due "
- "to SMI disturbance. Using PIT calibration\n");
+ printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. "
+ "Using PIT calibration\n");
return tsc_pit_min;
}
- /* Check the reference deviation */
- delta = ((u64) tsc_pit_min) * 100;
- do_div(delta, tsc_ref_min);
-
- /*
- * If both calibration results are inside a 5% window, the we
- * use the lower frequency of those as it is probably the
- * closest estimate.
- */
- if (delta >= 95 && delta <= 105) {
- printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n",
- hpet ? "HPET" : "PMTIMER");
- printk(KERN_INFO "TSC: using %s calibration value\n",
- tsc_pit_min <= tsc_ref_min ? "PIT" :
- hpet ? "HPET" : "PMTIMER");
- return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min;
- }
-
- printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
- hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
-
/*
* The calibration values differ too much. In doubt, we use
* the PIT value as we know that there are PMTIMERs around
- * running at double speed.
+ * running at double speed. At least we let the user know:
*/
+ printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
+ hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
printk(KERN_INFO "TSC: Using PIT calibration value\n");
return tsc_pit_min;
}
--
next prev parent reply other threads:[~2008-09-04 15:20 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-04 15:18 [RFC patch 0/4] TSC calibration improvements Thomas Gleixner
2008-09-04 15:18 ` [RFC patch 1/4] x86: TSC: define the PIT latch value separate Thomas Gleixner
2008-09-04 15:18 ` [RFC patch 2/4] x86: TSC: separate hpet/pmtimer calculation out Thomas Gleixner
2008-09-04 15:18 ` [RFC patch 3/4] x86: TSC: use one set of reference variables Thomas Gleixner
2008-09-04 15:18 ` Thomas Gleixner [this message]
2008-09-04 15:36 ` [RFC patch 0/4] TSC calibration improvements Ingo Molnar
2008-09-04 15:45 ` Linus Torvalds
2008-09-04 16:00 ` Ingo Molnar
2008-09-04 16:21 ` Linus Torvalds
2008-09-04 16:36 ` Ingo Molnar
2008-09-04 17:41 ` Linus Torvalds
2008-09-04 18:07 ` Alan Cox
2008-09-04 18:26 ` Linus Torvalds
2008-09-04 18:30 ` H. Peter Anvin
2008-09-04 20:09 ` Linus Torvalds
2008-09-04 20:43 ` Ingo Molnar
2008-09-04 20:52 ` Ingo Molnar
2008-09-04 21:09 ` Linus Torvalds
2008-09-04 21:21 ` Ingo Molnar
2008-09-04 21:30 ` Linus Torvalds
2008-09-04 21:34 ` Linus Torvalds
2008-09-04 21:39 ` Ingo Molnar
2008-09-04 21:33 ` Ingo Molnar
2008-09-05 22:18 ` Alok Kataria
2008-09-05 22:34 ` Linus Torvalds
2008-09-06 20:03 ` Thomas Gleixner
2008-09-06 20:29 ` Linus Torvalds
2008-09-06 20:37 ` Thomas Gleixner
2008-09-06 20:50 ` Linus Torvalds
2008-09-06 20:55 ` Linus Torvalds
2008-09-06 21:15 ` Thomas Gleixner
2008-09-06 21:22 ` Linus Torvalds
2008-09-06 21:30 ` Thomas Gleixner
2008-09-06 22:40 ` Ingo Molnar
2008-09-06 20:58 ` Thomas Gleixner
2008-09-06 21:10 ` Linus Torvalds
2008-09-07 6:01 ` Willy Tarreau
2008-09-06 20:52 ` Thomas Gleixner
2008-09-06 20:59 ` Linus Torvalds
2008-09-06 21:07 ` Thomas Gleixner
2008-09-06 21:15 ` Linus Torvalds
2008-09-06 21:26 ` Thomas Gleixner
2008-09-06 21:32 ` Linus Torvalds
2008-09-04 20:53 ` Linus Torvalds
2008-09-04 21:38 ` Alok Kataria
2008-09-04 21:52 ` Linus Torvalds
2008-09-04 22:09 ` Alok Kataria
2008-09-04 17:39 ` Alok Kataria
2008-09-04 17:53 ` Linus Torvalds
2008-09-04 18:31 ` Alok Kataria
2008-09-04 18:34 ` H. Peter Anvin
2008-09-04 21:00 ` Valdis.Kletnieks
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080904151249.783722713@linutronix.de \
--to=tglx@linutronix.de \
--cc=akataria@vmware.com \
--cc=arjan@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome