diff options
author | Yasunori Goto <y-goto@jp.fujitsu.com> | 2009-04-02 19:58:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-02 22:05:01 -0400 |
commit | 303d379c54fc9ed553562e36c1cbd1791a3f5d17 (patch) | |
tree | fa16886ba42f97af18eed3f2b791f54ce7ee2b09 /drivers/char/hpet.c | |
parent | 1f80769ffd36e74357fe896dc43dddf1af1510f3 (diff) |
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 <y-goto@jp.fujitsu.com>
Acked-by: Clemens Ladisch <clemens@ladisch.de>
Acked-by: Vojtech Pavlik <vojtech@suse.cz>
Cc: Robert Picco <Robert.Picco@hp.com>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: Ingo Molnar <mingo@elte.hu>
Acked-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r-- | drivers/char/hpet.c | 22 |
1 files changed, 21 insertions, 1 deletions
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; | |||
713 | */ | 713 | */ |
714 | #define TICK_CALIBRATE (1000UL) | 714 | #define TICK_CALIBRATE (1000UL) |
715 | 715 | ||
716 | static unsigned long hpet_calibrate(struct hpets *hpetp) | 716 | static unsigned long __hpet_calibrate(struct hpets *hpetp) |
717 | { | 717 | { |
718 | struct hpet_timer __iomem *timer = NULL; | 718 | struct hpet_timer __iomem *timer = NULL; |
719 | unsigned long t, m, count, i, flags, start; | 719 | unsigned long t, m, count, i, flags, start; |
@@ -750,6 +750,26 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) | |||
750 | return (m - start) / i; | 750 | return (m - start) / i; |
751 | } | 751 | } |
752 | 752 | ||
753 | static unsigned long hpet_calibrate(struct hpets *hpetp) | ||
754 | { | ||
755 | unsigned long ret = -1; | ||
756 | unsigned long tmp; | ||
757 | |||
758 | /* | ||
759 | * Try to calibrate until return value becomes stable small value. | ||
760 | * If SMI interruption occurs in calibration loop, the return value | ||
761 | * will be big. This avoids its impact. | ||
762 | */ | ||
763 | for ( ; ; ) { | ||
764 | tmp = __hpet_calibrate(hpetp); | ||
765 | if (ret <= tmp) | ||
766 | break; | ||
767 | ret = tmp; | ||
768 | } | ||
769 | |||
770 | return ret; | ||
771 | } | ||
772 | |||
753 | int hpet_alloc(struct hpet_data *hdp) | 773 | int hpet_alloc(struct hpet_data *hdp) |
754 | { | 774 | { |
755 | u64 cap, mcfg; | 775 | u64 cap, mcfg; |