diff options
Diffstat (limited to 'drivers/clocksource/acpi_pm.c')
-rw-r--r-- | drivers/clocksource/acpi_pm.c | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 7fcb77a9d011..b6bcdbbf57b3 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -77,11 +77,11 @@ static struct clocksource clocksource_acpi_pm = { #ifdef CONFIG_PCI -static int acpi_pm_good; +static int __devinitdata acpi_pm_good; static int __init acpi_pm_good_setup(char *__str) { - acpi_pm_good = 1; - return 1; + acpi_pm_good = 1; + return 1; } __setup("acpi_pm_good", acpi_pm_good_setup); @@ -142,6 +142,39 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, acpi_pm_check_graylist); #endif +#ifndef CONFIG_X86_64 +#include "mach_timer.h" +#define PMTMR_EXPECTED_RATE \ + ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10)) +/* + * 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; +} +#else +#define verify_pmtmr_rate() (0) +#endif static int __init init_acpi_pm_clocksource(void) { @@ -173,6 +206,9 @@ static int __init init_acpi_pm_clocksource(void) return -ENODEV; pm_good: + if (verify_pmtmr_rate() != 0) + return -ENODEV; + return clocksource_register(&clocksource_acpi_pm); } |