xref: /openbmc/linux/drivers/clocksource/acpi_pm.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
182c73e0aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25d0cf410Sjohn stultz /*
35d0cf410Sjohn stultz  * linux/drivers/clocksource/acpi_pm.c
45d0cf410Sjohn stultz  *
55d0cf410Sjohn stultz  * This file contains the ACPI PM based clocksource.
65d0cf410Sjohn stultz  *
75d0cf410Sjohn stultz  * This code was largely moved from the i386 timer_pm.c file
85d0cf410Sjohn stultz  * which was (C) Dominik Brodowski <linux@brodo.de> 2003
95d0cf410Sjohn stultz  * and contained the following comments:
105d0cf410Sjohn stultz  *
115d0cf410Sjohn stultz  * Driver to use the Power Management Timer (PMTMR) available in some
125d0cf410Sjohn stultz  * southbridges as primary timing source for the Linux kernel.
135d0cf410Sjohn stultz  *
145d0cf410Sjohn stultz  * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
155d0cf410Sjohn stultz  * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
165d0cf410Sjohn stultz  */
175d0cf410Sjohn stultz 
18d66bea57SThomas Gleixner #include <linux/acpi_pmtmr.h>
195d0cf410Sjohn stultz #include <linux/clocksource.h>
2008604bd9SArnd Bergmann #include <linux/timex.h>
215d0cf410Sjohn stultz #include <linux/errno.h>
225d0cf410Sjohn stultz #include <linux/init.h>
235d0cf410Sjohn stultz #include <linux/pci.h>
244ab6a219SDominik Brodowski #include <linux/delay.h>
255d0cf410Sjohn stultz #include <asm/io.h>
26*efc8b329SPaul E. McKenney #include <asm/time.h>
275d0cf410Sjohn stultz 
285d0cf410Sjohn stultz /*
295d0cf410Sjohn stultz  * The I/O port the PMTMR resides at.
305d0cf410Sjohn stultz  * The location is detected during setup_arch(),
318ce8e2f9SDaniel Walker  * in arch/i386/kernel/acpi/boot.c
325d0cf410Sjohn stultz  */
337d622d47SAndreas Mohr u32 pmtmr_ioport __read_mostly;
345d0cf410Sjohn stultz 
read_pmtmr(void)355d0cf410Sjohn stultz static inline u32 read_pmtmr(void)
365d0cf410Sjohn stultz {
375d0cf410Sjohn stultz 	/* mask the output to 24 bits */
385d0cf410Sjohn stultz 	return inl(pmtmr_ioport) & ACPI_PM_MASK;
395d0cf410Sjohn stultz }
405d0cf410Sjohn stultz 
acpi_pm_read_verified(void)41d66bea57SThomas Gleixner u32 acpi_pm_read_verified(void)
425d0cf410Sjohn stultz {
435d0cf410Sjohn stultz 	u32 v1 = 0, v2 = 0, v3 = 0;
445d0cf410Sjohn stultz 
455d0cf410Sjohn stultz 	/*
465d0cf410Sjohn stultz 	 * It has been reported that because of various broken
475d0cf410Sjohn stultz 	 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock
487d622d47SAndreas Mohr 	 * source is not latched, you must read it multiple
495d0cf410Sjohn stultz 	 * times to ensure a safe value is read:
505d0cf410Sjohn stultz 	 */
515d0cf410Sjohn stultz 	do {
525d0cf410Sjohn stultz 		v1 = read_pmtmr();
535d0cf410Sjohn stultz 		v2 = read_pmtmr();
545d0cf410Sjohn stultz 		v3 = read_pmtmr();
5578f32668SDaniel Walker 	} while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
5678f32668SDaniel Walker 			  || (v3 > v1 && v3 < v2)));
575d0cf410Sjohn stultz 
58d66bea57SThomas Gleixner 	return v2;
59d66bea57SThomas Gleixner }
60d66bea57SThomas Gleixner 
acpi_pm_read(struct clocksource * cs)61a5a1d1c2SThomas Gleixner static u64 acpi_pm_read(struct clocksource *cs)
625d0cf410Sjohn stultz {
63a5a1d1c2SThomas Gleixner 	return (u64)read_pmtmr();
645d0cf410Sjohn stultz }
655d0cf410Sjohn stultz 
665d0cf410Sjohn stultz static struct clocksource clocksource_acpi_pm = {
675d0cf410Sjohn stultz 	.name		= "acpi_pm",
685d0cf410Sjohn stultz 	.rating		= 200,
695d0cf410Sjohn stultz 	.read		= acpi_pm_read,
70a5a1d1c2SThomas Gleixner 	.mask		= (u64)ACPI_PM_MASK,
7173b08d2aSThomas Gleixner 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
725d0cf410Sjohn stultz };
735d0cf410Sjohn stultz 
745d0cf410Sjohn stultz 
755d0cf410Sjohn stultz #ifdef CONFIG_PCI
761850514bSGreg Kroah-Hartman static int acpi_pm_good;
acpi_pm_good_setup(char * __str)775d0cf410Sjohn stultz static int __init acpi_pm_good_setup(char *__str)
785d0cf410Sjohn stultz {
795d0cf410Sjohn stultz 	acpi_pm_good = 1;
805d0cf410Sjohn stultz 	return 1;
815d0cf410Sjohn stultz }
825d0cf410Sjohn stultz __setup("acpi_pm_good", acpi_pm_good_setup);
835d0cf410Sjohn stultz 
acpi_pm_read_slow(struct clocksource * cs)84a5a1d1c2SThomas Gleixner static u64 acpi_pm_read_slow(struct clocksource *cs)
850a57b783SBjorn Helgaas {
86a5a1d1c2SThomas Gleixner 	return (u64)acpi_pm_read_verified();
870a57b783SBjorn Helgaas }
880a57b783SBjorn Helgaas 
acpi_pm_need_workaround(void)895d0cf410Sjohn stultz static inline void acpi_pm_need_workaround(void)
905d0cf410Sjohn stultz {
91d66bea57SThomas Gleixner 	clocksource_acpi_pm.read = acpi_pm_read_slow;
921ff100d7Sjohn stultz 	clocksource_acpi_pm.rating = 120;
935d0cf410Sjohn stultz }
945d0cf410Sjohn stultz 
955d0cf410Sjohn stultz /*
965d0cf410Sjohn stultz  * PIIX4 Errata:
975d0cf410Sjohn stultz  *
985d0cf410Sjohn stultz  * The power management timer may return improper results when read.
995d0cf410Sjohn stultz  * Although the timer value settles properly after incrementing,
1005d0cf410Sjohn stultz  * while incrementing there is a 3 ns window every 69.8 ns where the
1015d0cf410Sjohn stultz  * timer value is indeterminate (a 4.2% chance that the data will be
1025d0cf410Sjohn stultz  * incorrect when read). As a result, the ACPI free running count up
1035d0cf410Sjohn stultz  * timer specification is violated due to erroneous reads.
1045d0cf410Sjohn stultz  */
acpi_pm_check_blacklist(struct pci_dev * dev)1051850514bSGreg Kroah-Hartman static void acpi_pm_check_blacklist(struct pci_dev *dev)
1065d0cf410Sjohn stultz {
1075d0cf410Sjohn stultz 	if (acpi_pm_good)
1085d0cf410Sjohn stultz 		return;
1095d0cf410Sjohn stultz 
1105d0cf410Sjohn stultz 	/* the bug has been fixed in PIIX4M */
11144c10138SAuke Kok 	if (dev->revision < 3) {
11201414888SAndy Shevchenko 		pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n"
11301414888SAndy Shevchenko 			"* this clock source is slow. Consider trying other clock sources\n");
1145d0cf410Sjohn stultz 
1155d0cf410Sjohn stultz 		acpi_pm_need_workaround();
1165d0cf410Sjohn stultz 	}
1175d0cf410Sjohn stultz }
1185d0cf410Sjohn stultz DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
1195d0cf410Sjohn stultz 			acpi_pm_check_blacklist);
1205d0cf410Sjohn stultz 
acpi_pm_check_graylist(struct pci_dev * dev)1211850514bSGreg Kroah-Hartman static void acpi_pm_check_graylist(struct pci_dev *dev)
1225d0cf410Sjohn stultz {
1235d0cf410Sjohn stultz 	if (acpi_pm_good)
1245d0cf410Sjohn stultz 		return;
1255d0cf410Sjohn stultz 
12601414888SAndy Shevchenko 	pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n"
12701414888SAndy Shevchenko 		"* this clock source is slow. If you are sure your timer does not have\n"
12801414888SAndy Shevchenko 		"* this bug, please use \"acpi_pm_good\" to disable the workaround\n");
1295d0cf410Sjohn stultz 
1305d0cf410Sjohn stultz 	acpi_pm_need_workaround();
1315d0cf410Sjohn stultz }
1325d0cf410Sjohn stultz DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
1335d0cf410Sjohn stultz 			acpi_pm_check_graylist);
13478f32668SDaniel Walker DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
13578f32668SDaniel Walker 			acpi_pm_check_graylist);
1365d0cf410Sjohn stultz #endif
1375d0cf410Sjohn stultz 
138562f9c57Sjohn stultz #ifndef CONFIG_X86_64
1391164dd00SIngo Molnar #include <asm/mach_timer.h>
140562f9c57Sjohn stultz #define PMTMR_EXPECTED_RATE \
141cbf1599bSDeepak Saxena   ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE>>10))
142562f9c57Sjohn stultz /*
143562f9c57Sjohn stultz  * Some boards have the PMTMR running way too fast. We check
144562f9c57Sjohn stultz  * the PMTMR rate against PIT channel 2 to catch these cases.
145562f9c57Sjohn stultz  */
verify_pmtmr_rate(void)146562f9c57Sjohn stultz static int verify_pmtmr_rate(void)
147562f9c57Sjohn stultz {
148a5a1d1c2SThomas Gleixner 	u64 value1, value2;
149562f9c57Sjohn stultz 	unsigned long count, delta;
150562f9c57Sjohn stultz 
151562f9c57Sjohn stultz 	mach_prepare_counter();
1528e19608eSMagnus Damm 	value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
153562f9c57Sjohn stultz 	mach_countup(&count);
1548e19608eSMagnus Damm 	value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
155562f9c57Sjohn stultz 	delta = (value2 - value1) & ACPI_PM_MASK;
156562f9c57Sjohn stultz 
157562f9c57Sjohn stultz 	/* Check that the PMTMR delta is within 5% of what we expect */
158562f9c57Sjohn stultz 	if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
159562f9c57Sjohn stultz 	    delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
16001414888SAndy Shevchenko 		pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n",
161562f9c57Sjohn stultz 			100UL * delta / PMTMR_EXPECTED_RATE);
162562f9c57Sjohn stultz 		return -1;
163562f9c57Sjohn stultz 	}
164562f9c57Sjohn stultz 
165562f9c57Sjohn stultz 	return 0;
166562f9c57Sjohn stultz }
167562f9c57Sjohn stultz #else
168562f9c57Sjohn stultz #define verify_pmtmr_rate() (0)
169562f9c57Sjohn stultz #endif
1705d0cf410Sjohn stultz 
1714ab6a219SDominik Brodowski /* Number of monotonicity checks to perform during initialization */
1724ab6a219SDominik Brodowski #define ACPI_PM_MONOTONICITY_CHECKS 10
173f1926ce6SDominik Brodowski /* Number of reads we try to get two different values */
174f1926ce6SDominik Brodowski #define ACPI_PM_READ_CHECKS 10000
1754ab6a219SDominik Brodowski 
init_acpi_pm_clocksource(void)176d48fc63fSThomas Gleixner static int __init init_acpi_pm_clocksource(void)
1775d0cf410Sjohn stultz {
178a5a1d1c2SThomas Gleixner 	u64 value1, value2;
179f1926ce6SDominik Brodowski 	unsigned int i, j = 0;
1805d0cf410Sjohn stultz 
181d48fc63fSThomas Gleixner 	if (!pmtmr_ioport)
182d48fc63fSThomas Gleixner 		return -ENODEV;
1835d0cf410Sjohn stultz 
1845d0cf410Sjohn stultz 	/* "verify" this timing source: */
1854ab6a219SDominik Brodowski 	for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
186d48fc63fSThomas Gleixner 		udelay(100 * j);
1878e19608eSMagnus Damm 		value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
188f1926ce6SDominik Brodowski 		for (i = 0; i < ACPI_PM_READ_CHECKS; i++) {
1898e19608eSMagnus Damm 			value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
1905d0cf410Sjohn stultz 			if (value2 == value1)
1915d0cf410Sjohn stultz 				continue;
1925d0cf410Sjohn stultz 			if (value2 > value1)
1934ab6a219SDominik Brodowski 				break;
1945d0cf410Sjohn stultz 			if ((value2 < value1) && ((value2) < 0xFFF))
1954ab6a219SDominik Brodowski 				break;
19601414888SAndy Shevchenko 			pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n",
1974ab6a219SDominik Brodowski 				value1, value2);
198db6b175fSKonrad Rzeszutek Wilk 			pmtmr_ioport = 0;
199d48fc63fSThomas Gleixner 			return -EINVAL;
2005d0cf410Sjohn stultz 		}
201f1926ce6SDominik Brodowski 		if (i == ACPI_PM_READ_CHECKS) {
20201414888SAndy Shevchenko 			pr_info("PM-Timer failed consistency check  (%#llx) - aborting.\n",
20301414888SAndy Shevchenko 				value1);
204db6b175fSKonrad Rzeszutek Wilk 			pmtmr_ioport = 0;
205d48fc63fSThomas Gleixner 			return -ENODEV;
2064ab6a219SDominik Brodowski 		}
207f1926ce6SDominik Brodowski 	}
2085d0cf410Sjohn stultz 
209db6b175fSKonrad Rzeszutek Wilk 	if (verify_pmtmr_rate() != 0){
210db6b175fSKonrad Rzeszutek Wilk 		pmtmr_ioport = 0;
211b5195082SArjan van de Ven 		return -ENODEV;
212d48fc63fSThomas Gleixner 	}
213b5195082SArjan van de Ven 
214*efc8b329SPaul E. McKenney 	if (tsc_clocksource_watchdog_disabled())
215*efc8b329SPaul E. McKenney 		clocksource_acpi_pm.flags |= CLOCK_SOURCE_MUST_VERIFY;
216*efc8b329SPaul E. McKenney 	return clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC);
217b5195082SArjan van de Ven }
218b5195082SArjan van de Ven 
2196bb74df4Sjohn stultz /* We use fs_initcall because we want the PCI fixups to have run
2206bb74df4Sjohn stultz  * but we still need to load before device_initcall
2216bb74df4Sjohn stultz  */
2226bb74df4Sjohn stultz fs_initcall(init_acpi_pm_clocksource);
2236b148507SThomas Gleixner 
2246b148507SThomas Gleixner /*
2256b148507SThomas Gleixner  * Allow an override of the IOPort. Stupid BIOSes do not tell us about
2266b148507SThomas Gleixner  * the PMTimer, but we might know where it is.
2276b148507SThomas Gleixner  */
parse_pmtmr(char * arg)2286b148507SThomas Gleixner static int __init parse_pmtmr(char *arg)
2296b148507SThomas Gleixner {
23060e3bf14SDan Carpenter 	unsigned int base;
23160e3bf14SDan Carpenter 	int ret;
2326b148507SThomas Gleixner 
23360e3bf14SDan Carpenter 	ret = kstrtouint(arg, 16, &base);
2346a861abcSRandy Dunlap 	if (ret) {
2356a861abcSRandy Dunlap 		pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg);
2366a861abcSRandy Dunlap 		return 1;
2376a861abcSRandy Dunlap 	}
23860e3bf14SDan Carpenter 
23960e3bf14SDan Carpenter 	pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport,
24060e3bf14SDan Carpenter 		base);
2416b148507SThomas Gleixner 	pmtmr_ioport = base;
2426b148507SThomas Gleixner 
2436b148507SThomas Gleixner 	return 1;
2446b148507SThomas Gleixner }
2456b148507SThomas Gleixner __setup("pmtmr=", parse_pmtmr);
246