diff options
Diffstat (limited to 'drivers/clocksource/acpi_pm.c')
| -rw-r--r-- | drivers/clocksource/acpi_pm.c | 36 | 
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 7fcb77a9d01..8ab61ef97b4 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -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);  }  |