root/drivers/clocksource/acpi_pm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_pmtmr
  2. acpi_pm_read_verified
  3. acpi_pm_read
  4. acpi_pm_good_setup
  5. acpi_pm_read_slow
  6. acpi_pm_need_workaround
  7. acpi_pm_check_blacklist
  8. acpi_pm_check_graylist
  9. verify_pmtmr_rate
  10. init_acpi_pm_clocksource
  11. parse_pmtmr

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

/* [<][>][^][v][top][bottom][index][help] */