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>
This commit is contained in:
Dominik Brodowski 2008-09-05 14:05:35 -07:00 committed by Ingo Molnar
parent dfdf748a61
commit 4ab6a21911

View file

@ -21,6 +21,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h> #include <asm/io.h>
/* /*
@ -175,10 +176,13 @@ static int verify_pmtmr_rate(void)
#define verify_pmtmr_rate() (0) #define verify_pmtmr_rate() (0)
#endif #endif
/* Number of monotonicity checks to perform during initialization */
#define ACPI_PM_MONOTONICITY_CHECKS 10
static int __init init_acpi_pm_clocksource(void) static int __init init_acpi_pm_clocksource(void)
{ {
cycle_t value1, value2; cycle_t value1, value2;
unsigned int i; unsigned int i, j, good = 0;
if (!pmtmr_ioport) if (!pmtmr_ioport)
return -ENODEV; return -ENODEV;
@ -187,24 +191,32 @@ static int __init init_acpi_pm_clocksource(void)
clocksource_acpi_pm.shift); clocksource_acpi_pm.shift);
/* "verify" this timing source: */ /* "verify" this timing source: */
for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
value1 = clocksource_acpi_pm.read(); value1 = clocksource_acpi_pm.read();
for (i = 0; i < 10000; i++) { for (i = 0; i < 10000; i++) {
value2 = clocksource_acpi_pm.read(); value2 = clocksource_acpi_pm.read();
if (value2 == value1) if (value2 == value1)
continue; continue;
if (value2 > value1) if (value2 > value1)
goto pm_good; good++;
break;
if ((value2 < value1) && ((value2) < 0xFFF)) if ((value2 < value1) && ((value2) < 0xFFF))
goto pm_good; good++;
break;
printk(KERN_INFO "PM-Timer had inconsistent results:" printk(KERN_INFO "PM-Timer had inconsistent results:"
" 0x%#llx, 0x%#llx - aborting.\n", value1, value2); " 0x%#llx, 0x%#llx - aborting.\n",
value1, value2);
return -EINVAL; return -EINVAL;
} }
printk(KERN_INFO "PM-Timer had no reasonable result:" udelay(300 * i);
" 0x%#llx - aborting.\n", value1); }
return -ENODEV;
if (good != ACPI_PM_MONOTONICITY_CHECKS) {
printk(KERN_INFO "PM-Timer failed consistency check "
" (0x%#llx) - aborting.\n", value1);
return -ENODEV;
}
pm_good:
if (verify_pmtmr_rate() != 0) if (verify_pmtmr_rate() != 0)
return -ENODEV; return -ENODEV;