^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/drivers/clocksource/acpi_pm.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file contains the ACPI PM based clocksource.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This code was largely moved from the i386 timer_pm.c file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * which was (C) Dominik Brodowski <linux@brodo.de> 2003
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and contained the following comments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Driver to use the Power Management Timer (PMTMR) available in some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * southbridges as primary timing source for the Linux kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/acpi_pmtmr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/clocksource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/timex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * The I/O port the PMTMR resides at.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * The location is detected during setup_arch(),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * in arch/i386/kernel/acpi/boot.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 pmtmr_ioport __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static inline u32 read_pmtmr(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* mask the output to 24 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return inl(pmtmr_ioport) & ACPI_PM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u32 acpi_pm_read_verified(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u32 v1 = 0, v2 = 0, v3 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * It has been reported that because of various broken
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * source is not latched, you must read it multiple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * times to ensure a safe value is read:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) v1 = read_pmtmr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) v2 = read_pmtmr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) v3 = read_pmtmr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) || (v3 > v1 && v3 < v2)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return v2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static u64 acpi_pm_read(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return (u64)read_pmtmr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct clocksource clocksource_acpi_pm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .name = "acpi_pm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .rating = 200,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .read = acpi_pm_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .mask = (u64)ACPI_PM_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .flags = CLOCK_SOURCE_IS_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int acpi_pm_good;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int __init acpi_pm_good_setup(char *__str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) acpi_pm_good = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) __setup("acpi_pm_good", acpi_pm_good_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static u64 acpi_pm_read_slow(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return (u64)acpi_pm_read_verified();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static inline void acpi_pm_need_workaround(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) clocksource_acpi_pm.read = acpi_pm_read_slow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) clocksource_acpi_pm.rating = 120;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * PIIX4 Errata:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * The power management timer may return improper results when read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * Although the timer value settles properly after incrementing,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * while incrementing there is a 3 ns window every 69.8 ns where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * timer value is indeterminate (a 4.2% chance that the data will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * incorrect when read). As a result, the ACPI free running count up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * timer specification is violated due to erroneous reads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static void acpi_pm_check_blacklist(struct pci_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (acpi_pm_good)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* the bug has been fixed in PIIX4M */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (dev->revision < 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) "* this clock source is slow. Consider trying other clock sources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) acpi_pm_need_workaround();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) acpi_pm_check_blacklist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static void acpi_pm_check_graylist(struct pci_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (acpi_pm_good)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) "* this clock source is slow. If you are sure your timer does not have\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) "* this bug, please use \"acpi_pm_good\" to disable the workaround\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) acpi_pm_need_workaround();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) acpi_pm_check_graylist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) acpi_pm_check_graylist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #ifndef CONFIG_X86_64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #include <asm/mach_timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define PMTMR_EXPECTED_RATE \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE>>10))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * Some boards have the PMTMR running way too fast. We check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * the PMTMR rate against PIT channel 2 to catch these cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static int verify_pmtmr_rate(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) u64 value1, value2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned long count, delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) mach_prepare_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) mach_countup(&count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) delta = (value2 - value1) & ACPI_PM_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Check that the PMTMR delta is within 5% of what we expect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 100UL * delta / PMTMR_EXPECTED_RATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #define verify_pmtmr_rate() (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* Number of monotonicity checks to perform during initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) #define ACPI_PM_MONOTONICITY_CHECKS 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* Number of reads we try to get two different values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #define ACPI_PM_READ_CHECKS 10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static int __init init_acpi_pm_clocksource(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) u64 value1, value2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned int i, j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!pmtmr_ioport)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* "verify" this timing source: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) udelay(100 * j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) for (i = 0; i < ACPI_PM_READ_CHECKS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (value2 == value1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (value2 > value1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if ((value2 < value1) && ((value2) < 0xFFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) value1, value2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) pmtmr_ioport = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (i == ACPI_PM_READ_CHECKS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) pr_info("PM-Timer failed consistency check (%#llx) - aborting.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) value1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) pmtmr_ioport = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (verify_pmtmr_rate() != 0){
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pmtmr_ioport = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return clocksource_register_hz(&clocksource_acpi_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) PMTMR_TICKS_PER_SEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* We use fs_initcall because we want the PCI fixups to have run
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * but we still need to load before device_initcall
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) fs_initcall(init_acpi_pm_clocksource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * Allow an override of the IOPort. Stupid BIOSes do not tell us about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * the PMTimer, but we might know where it is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static int __init parse_pmtmr(char *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) unsigned int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ret = kstrtouint(arg, 16, &base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) pmtmr_ioport = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) __setup("pmtmr=", parse_pmtmr);