forked from Minki/linux
[PATCH] x86-64: - Ignore long SMI interrupts in clock calibration
Ensure that no SMI interrupts occur between the read of the HPET & TSC in the clock calibration loop. I noticed that a 2.66GHz system incorrectly detected the processor clock speed about 1/7 of the time: time.c: Detected 2660.005 MHz processor. (most of the time) time.c: Detected 2988.203 MHz processor. (sometime) The problem is caused by an SMI interrupt occuring in hpet_calibrate_tsc() between the read of the HPET & TSC. Prior to switching the BIOS into ACPI mode, it appears that every 27msec an SMI interrupt occurs. The SMI interrupt takes 4.8 msec to process. Note: On my test system, TICK_MIN had to be >380. I picked 5000 to minimize risk of having a value that is too small for other platforms. Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Andi Kleen <ak@suse.de> arch/x86_64/kernel/time.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
This commit is contained in:
parent
9d24a81e84
commit
ed5316d445
@ -656,6 +656,25 @@ core_initcall(cpufreq_tsc);
|
||||
*/
|
||||
|
||||
#define TICK_COUNT 100000000
|
||||
#define TICK_MIN 5000
|
||||
|
||||
/*
|
||||
* Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
|
||||
* occurs between the reads of the hpet & TSC.
|
||||
*/
|
||||
static void __init read_hpet_tsc(int *hpet, int *tsc)
|
||||
{
|
||||
int tsc1, tsc2, hpet1;
|
||||
|
||||
do {
|
||||
tsc1 = get_cycles_sync();
|
||||
hpet1 = hpet_readl(HPET_COUNTER);
|
||||
tsc2 = get_cycles_sync();
|
||||
} while (tsc2 - tsc1 > TICK_MIN);
|
||||
*hpet = hpet1;
|
||||
*tsc = tsc2;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int __init hpet_calibrate_tsc(void)
|
||||
{
|
||||
@ -666,13 +685,11 @@ static unsigned int __init hpet_calibrate_tsc(void)
|
||||
local_irq_save(flags);
|
||||
local_irq_disable();
|
||||
|
||||
hpet_start = hpet_readl(HPET_COUNTER);
|
||||
rdtscl(tsc_start);
|
||||
read_hpet_tsc(&hpet_start, &tsc_start);
|
||||
|
||||
do {
|
||||
local_irq_disable();
|
||||
hpet_now = hpet_readl(HPET_COUNTER);
|
||||
tsc_now = get_cycles_sync();
|
||||
read_hpet_tsc(&hpet_now, &tsc_now);
|
||||
local_irq_restore(flags);
|
||||
} while ((tsc_now - tsc_start) < TICK_COUNT &&
|
||||
(hpet_now - hpet_start) < TICK_COUNT);
|
||||
|
Loading…
Reference in New Issue
Block a user