X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Ftimers%2Ftimer_pm.c;h=737a0219d1937ce4f5273941d00852bd390cd164;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=7aa63c9b8e18f3de62650e2c1ef97e08b8bfaeed;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c index 7aa63c9b8..737a0219d 100644 --- a/arch/i386/kernel/timers/timer_pm.c +++ b/arch/i386/kernel/timers/timer_pm.c @@ -21,6 +21,14 @@ #include #include +#include +#include "mach_timer.h" + +/* Number of PMTMR ticks expected during calibration run */ +#define PMTMR_TICKS_PER_SEC 3579545 +#define PMTMR_EXPECTED_RATE \ + ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10)) + /* The I/O port the PMTMR resides at. * The location is detected during setup_arch(), @@ -57,6 +65,33 @@ static inline u32 read_pmtmr(void) return v2 & ACPI_PM_MASK; } + +/* + * Some boards have the PMTMR running way too fast. We check + * the PMTMR rate against PIT channel 2 to catch these cases. + */ +static int verify_pmtmr_rate(void) +{ + u32 value1, value2; + unsigned long count, delta; + + mach_prepare_counter(); + value1 = read_pmtmr(); + mach_countup(&count); + value2 = read_pmtmr(); + delta = (value2 - value1) & ACPI_PM_MASK; + + /* Check that the PMTMR delta is within 5% of what we expect */ + if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 || + delta > (PMTMR_EXPECTED_RATE * 21) / 20) { + printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% of normal - aborting.\n", 100UL * delta / PMTMR_EXPECTED_RATE); + return -1; + } + + return 0; +} + + static int init_pmtmr(char* override) { u32 value1, value2; @@ -89,6 +124,9 @@ static int init_pmtmr(char* override) return -ENODEV; pm_good: + if (verify_pmtmr_rate() != 0) + return -ENODEV; + init_cpu_khz(); return 0; }