X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fclocksource%2Facpi_pm.c;h=c20171078d1d6f475f04a23fc0be9e63101d5d76;hb=c465a76af658b443075d6efee1c3131257643020;hp=d42060ede93024481916f3497d479a45e5848184;hpb=6bb74df481223731af6c7e0ff3adb31f6442cfcd;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index d42060e..c201710 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -21,12 +21,13 @@ #include #include #include +#include #include /* * The I/O port the PMTMR resides at. * The location is detected during setup_arch(), - * in arch/i386/acpi/boot.c + * in arch/i386/kernel/acpi/boot.c */ u32 pmtmr_ioport __read_mostly; @@ -71,7 +72,7 @@ static struct clocksource clocksource_acpi_pm = { .rating = 200, .read = acpi_pm_read, .mask = (cycle_t)ACPI_PM_MASK, - .mult = 0, /*to be caluclated*/ + .mult = 0, /*to be calculated*/ .shift = 22, .flags = CLOCK_SOURCE_IS_CONTINUOUS, @@ -90,7 +91,7 @@ __setup("acpi_pm_good", acpi_pm_good_setup); static inline void acpi_pm_need_workaround(void) { clocksource_acpi_pm.read = acpi_pm_read_slow; - clocksource_acpi_pm.rating = 110; + clocksource_acpi_pm.rating = 120; } /* @@ -105,14 +106,11 @@ static inline void acpi_pm_need_workaround(void) */ static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev) { - u8 rev; - if (acpi_pm_good) return; - pci_read_config_byte(dev, PCI_REVISION_ID, &rev); /* the bug has been fixed in PIIX4M */ - if (rev < 3) { + if (dev->revision < 3) { printk(KERN_WARNING "* Found PM-Timer Bug on the chipset." " Due to workarounds for a bug,\n" "* this clock source is slow. Consider trying" @@ -154,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, */ static int verify_pmtmr_rate(void) { - u32 value1, value2; + cycle_t value1, value2; unsigned long count, delta; mach_prepare_counter(); - value1 = read_pmtmr(); + value1 = clocksource_acpi_pm.read(); mach_countup(&count); - value2 = read_pmtmr(); + value2 = clocksource_acpi_pm.read(); delta = (value2 - value1) & ACPI_PM_MASK; /* Check that the PMTMR delta is within 5% of what we expect */ @@ -178,10 +176,15 @@ 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 +/* Number of reads we try to get two different values */ +#define ACPI_PM_READ_CHECKS 10000 + static int __init init_acpi_pm_clocksource(void) { - u32 value1, value2; - unsigned int i; + cycle_t value1, value2; + unsigned int i, j = 0; if (!pmtmr_ioport) return -ENODEV; @@ -190,24 +193,29 @@ static int __init init_acpi_pm_clocksource(void) clocksource_acpi_pm.shift); /* "verify" this timing source: */ - value1 = read_pmtmr(); - for (i = 0; i < 10000; i++) { - value2 = read_pmtmr(); - 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%#x, 0x%#x - aborting.\n", value1, value2); - return -EINVAL; + for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { + udelay(100 * j); + value1 = clocksource_acpi_pm.read(); + for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { + value2 = clocksource_acpi_pm.read(); + if (value2 == value1) + continue; + if (value2 > value1) + break; + if ((value2 < value1) && ((value2) < 0xFFF)) + break; + printk(KERN_INFO "PM-Timer had inconsistent results:" + " 0x%#llx, 0x%#llx - aborting.\n", + value1, value2); + return -EINVAL; + } + if (i == ACPI_PM_READ_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%#x - aborting.\n", value1); - return -ENODEV; -pm_good: if (verify_pmtmr_rate() != 0) return -ENODEV; @@ -218,3 +226,25 @@ pm_good: * but we still need to load before device_initcall */ fs_initcall(init_acpi_pm_clocksource); + +/* + * Allow an override of the IOPort. Stupid BIOSes do not tell us about + * the PMTimer, but we might know where it is. + */ +static int __init parse_pmtmr(char *arg) +{ + unsigned long base; + + if (strict_strtoul(arg, 16, &base)) + return -EINVAL; +#ifdef CONFIG_X86_64 + if (base > UINT_MAX) + return -ERANGE; +#endif + printk(KERN_INFO "PMTMR IOPort override: 0x%04x -> 0x%04lx\n", + pmtmr_ioport, base); + pmtmr_ioport = base; + + return 1; +} +__setup("pmtmr=", parse_pmtmr);