diff options
| author | Dominik Brodowski <linux@dominikbrodowski.net> | 2008-09-05 14:05:35 -0700 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-09-06 15:33:33 +0200 | 
| commit | 4ab6a219113197425ac112e35e1ec8062c69888e (patch) | |
| tree | dd5458a0dd70c00ef6ba171e7369148905f0b27c /drivers/clocksource/acpi_pm.c | |
| parent | dfdf748a61a21b7397b9f57c83de722de71dc56a (diff) | |
| download | olio-linux-3.10-4ab6a219113197425ac112e35e1ec8062c69888e.tar.xz olio-linux-3.10-4ab6a219113197425ac112e35e1ec8062c69888e.zip  | |
clocksource, acpi_pm.c: check for monotonicity
The current check for monotonicity is way too weak: Andreas Mohr reports (
http://lkml.org/lkml/2008/8/10/77 ) that on one of his test systems the
current check only triggers in 50% of all cases, leading to catastrophic
timer behaviour.  To fix this issue, expand the check for monotonicity by
doing ten consecutive tests instead of one.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/clocksource/acpi_pm.c')
| -rw-r--r-- | drivers/clocksource/acpi_pm.c | 46 | 
1 files changed, 29 insertions, 17 deletions
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 860d033bc74..4eee533f3f4 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -21,6 +21,7 @@  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/pci.h> +#include <linux/delay.h>  #include <asm/io.h>  /* @@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void)  #define verify_pmtmr_rate() (0)  #endif +/* Number of monotonicity checks to perform during initialization */ +#define ACPI_PM_MONOTONICITY_CHECKS 10 +  static int __init init_acpi_pm_clocksource(void)  {  	cycle_t value1, value2; -	unsigned int i; +	unsigned int i, j, good = 0;  	if (!pmtmr_ioport)  		return -ENODEV; @@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void)  						clocksource_acpi_pm.shift);  	/* "verify" this timing source: */ -	value1 = clocksource_acpi_pm.read(); -	for (i = 0; i < 10000; i++) { -		value2 = clocksource_acpi_pm.read(); -		if (value2 == value1) -			continue; -		if (value2 > value1) -			goto pm_good; -		if ((value2 < value1) && ((value2) < 0xFFF)) -			goto pm_good; -		printk(KERN_INFO "PM-Timer had inconsistent results:" -			" 0x%#llx, 0x%#llx - aborting.\n", value1, value2); -		return -EINVAL; +	for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { +		value1 = clocksource_acpi_pm.read(); +		for (i = 0; i < 10000; i++) { +			value2 = clocksource_acpi_pm.read(); +			if (value2 == value1) +				continue; +			if (value2 > value1) +				good++; +				break; +			if ((value2 < value1) && ((value2) < 0xFFF)) +				good++; +				break; +			printk(KERN_INFO "PM-Timer had inconsistent results:" +			       " 0x%#llx, 0x%#llx - aborting.\n", +			       value1, value2); +			return -EINVAL; +		} +		udelay(300 * i); +	} + +	if (good != ACPI_PM_MONOTONICITY_CHECKS) { +		printk(KERN_INFO "PM-Timer failed consistency check " +		       " (0x%#llx) - aborting.\n", value1); +		return -ENODEV;  	} -	printk(KERN_INFO "PM-Timer had no reasonable result:" -			" 0x%#llx - aborting.\n", value1); -	return -ENODEV; -pm_good:  	if (verify_pmtmr_rate() != 0)  		return -ENODEV;  |