From 303d379c54fc9ed553562e36c1cbd1791a3f5d17 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Thu, 2 Apr 2009 16:58:31 -0700 Subject: hpet: fix the possibility of insane return value of hpet_calibrate() against SMI hpet_calibrate() has a possibility of miss-calibration due to SMI. If SMI interrupts in the while loop of calibration, then return value will be big. This change calibrates until stabilizing by the return value with a small value. [akpm@linux-foundation.org: trivial style tweaks] Signed-off-by: Yasunori Goto Acked-by: Clemens Ladisch Acked-by: Vojtech Pavlik Cc: Robert Picco Cc: Venkatesh Pallipadi Cc: Ingo Molnar Acked-by: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hpet.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 32b8bbf5003e..50dfa3bc71ce 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -713,7 +713,7 @@ static struct ctl_table_header *sysctl_header; */ #define TICK_CALIBRATE (1000UL) -static unsigned long hpet_calibrate(struct hpets *hpetp) +static unsigned long __hpet_calibrate(struct hpets *hpetp) { struct hpet_timer __iomem *timer = NULL; unsigned long t, m, count, i, flags, start; @@ -750,6 +750,26 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) return (m - start) / i; } +static unsigned long hpet_calibrate(struct hpets *hpetp) +{ + unsigned long ret = -1; + unsigned long tmp; + + /* + * Try to calibrate until return value becomes stable small value. + * If SMI interruption occurs in calibration loop, the return value + * will be big. This avoids its impact. + */ + for ( ; ; ) { + tmp = __hpet_calibrate(hpetp); + if (ret <= tmp) + break; + ret = tmp; + } + + return ret; +} + int hpet_alloc(struct hpet_data *hdp) { u64 cap, mcfg; -- cgit v1.2.2