Re: [RFC][PATCH] tsc_khz= boot option to avoid TSC calibration variance

From: George Spelvin
Date: Fri May 08 2009 - 08:19:27 EST


> To mitigate this, I wanted to provide a tsc_khz= boot option. This would
> allow users to set the tsc_khz value at boot-up, assuming they are
> within 1Mhz of the calibrated value (to protect against bad values).
> Once the tsc_khz value is set in grub, the box will always boot with the
> same value, so the NTP drift value prior to reboot will still be correct
> after rebooting.

A run-time adjustable would be more convenient, but this is simple and works.

The 1 MHz tolerance, however, isn't implemented right. I can't quote
figure out what you were trying to do; was that (x + (x/2))/1000 trying
to round the /1000 properly? That should be (x + 1000/2)/1000 in that
case, which I normally write as (x/500 + 1)/2;

But in any case, no equality comparison can possibly work; there's
always a case where the measured value rounds to k and the correct
value rounds to k+1. Also, 1 MHz is a pretty wide tolerance on
sub-GHz processors. I'd suggest the following:

diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index d57de05..d7ab640 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -825,15 +825,42 @@ static void __init init_tsc_clocksource(void)
clocksource_register(&clocksource_tsc);
}

+unsigned long tsc_khz_specified;
+static int __init tsc_khz_specified_setup(char *str)
+{
+ tsc_khz_specified = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+
+__setup("tsc_khz=", tsc_khz_specified_setup);
+
+
void __init tsc_init(void)
{
u64 lpj;
int cpu;
+ long difference;

if (!cpu_has_tsc)
return;

tsc_khz = calibrate_tsc();
+
+ /*
* * If the calibrated TSC freq and user specified TSC freq
* * are close enough, pick the what the user told us. Reject
* * obviously bogus values to make the option safe to use.
+ */
+ difference = tsc_khz - tsc_khz_specified;
+ if (difference < 0)
+ difference = -difference;
+ if (difference <= tsc_khz >> 10) { /* 1/1024 = 976 ppm */
+ printk(KERN_INFO "Using user defined TSC freq: %lu.%03lu MHz\n",
+ tsc_khz_specified/1000,
+ tsc_khz_specified%1000);
+ tsc_khz = tsc_khz_specified;
+ }
+
cpu_khz = tsc_khz;

if (!tsc_khz) {
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/