1 1.27 jmcneill /* $NetBSD: acpi_timer.c,v 1.27 2021/07/25 01:43:08 jmcneill Exp $ */ 2 1.16 jruoho 3 1.16 jruoho /*- 4 1.16 jruoho * Copyright (c) 2006 Matthias Drochner <drochner (at) NetBSD.org> 5 1.16 jruoho * All rights reserved. 6 1.16 jruoho * 7 1.16 jruoho * Redistribution and use in source and binary forms, with or without 8 1.16 jruoho * modification, are permitted provided that the following conditions 9 1.16 jruoho * are met: 10 1.16 jruoho * 1. Redistributions of source code must retain the above copyright 11 1.16 jruoho * notice, this list of conditions and the following disclaimer. 12 1.16 jruoho * 2. Redistributions in binary form must reproduce the above copyright 13 1.16 jruoho * notice, this list of conditions and the following disclaimer in the 14 1.16 jruoho * documentation and/or other materials provided with the distribution. 15 1.16 jruoho * 16 1.16 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.16 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.16 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.16 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.16 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.16 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.16 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.16 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.16 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.16 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.16 jruoho * POSSIBILITY OF SUCH DAMAGE. 27 1.16 jruoho */ 28 1.4 xtraeme 29 1.4 xtraeme #include <sys/cdefs.h> 30 1.27 jmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_timer.c,v 1.27 2021/07/25 01:43:08 jmcneill Exp $"); 31 1.1 drochner 32 1.1 drochner #include <sys/types.h> 33 1.1 drochner #include <sys/systm.h> 34 1.1 drochner #include <sys/time.h> 35 1.1 drochner #include <sys/timetc.h> 36 1.15 jruoho 37 1.15 jruoho #include <dev/acpi/acpivar.h> 38 1.10 joerg #include <dev/acpi/acpi_timer.h> 39 1.15 jruoho 40 1.12 jmcneill #include <machine/acpi_machdep.h> 41 1.1 drochner 42 1.25 jmcneill #if (!ACPI_REDUCED_HARDWARE) 43 1.17 jruoho static int acpitimer_test(void); 44 1.1 drochner 45 1.1 drochner static struct timecounter acpi_timecounter = { 46 1.26 rin .tc_get_timecount = acpitimer_read_safe, 47 1.26 rin .tc_counter_mask = 0x00ffffff, 48 1.26 rin .tc_frequency = ACPI_PM_TIMER_FREQUENCY, 49 1.26 rin .tc_name = "ACPI-Safe", 50 1.26 rin .tc_quality = 900, 51 1.1 drochner }; 52 1.1 drochner 53 1.23 jmcneill static bool 54 1.23 jmcneill acpitimer_supported(void) 55 1.23 jmcneill { 56 1.23 jmcneill return AcpiGbl_FADT.PmTimerLength != 0; 57 1.23 jmcneill } 58 1.24 jmcneill #endif 59 1.23 jmcneill 60 1.1 drochner int 61 1.17 jruoho acpitimer_init(struct acpi_softc *sc) 62 1.1 drochner { 63 1.25 jmcneill #if (!ACPI_REDUCED_HARDWARE) 64 1.27 jmcneill ACPI_TABLE_WAET *waet; 65 1.19 jruoho ACPI_STATUS rv; 66 1.1 drochner uint32_t bits; 67 1.2 drochner int i, j; 68 1.1 drochner 69 1.23 jmcneill if (!acpitimer_supported()) 70 1.23 jmcneill return -1; 71 1.23 jmcneill 72 1.19 jruoho rv = AcpiGetTimerResolution(&bits); 73 1.17 jruoho 74 1.19 jruoho if (ACPI_FAILURE(rv)) 75 1.18 jruoho return -1; 76 1.1 drochner 77 1.1 drochner if (bits == 32) 78 1.1 drochner acpi_timecounter.tc_counter_mask = 0xffffffff; 79 1.2 drochner 80 1.17 jruoho for (i = j = 0; i < 10; i++) 81 1.2 drochner j += acpitimer_test(); 82 1.3 xtraeme 83 1.27 jmcneill rv = AcpiGetTable(ACPI_SIG_WAET, 0, (ACPI_TABLE_HEADER **)&waet); 84 1.27 jmcneill if (ACPI_SUCCESS(rv)) { 85 1.27 jmcneill /* 86 1.27 jmcneill * Windows ACPI Emulated Devices Table (WAET) has a hint 87 1.27 jmcneill * to let the OS know that a single read of the PM timer 88 1.27 jmcneill * provides a reliable value. 89 1.27 jmcneill */ 90 1.27 jmcneill if ((waet->Flags & ACPI_WAET_TIMER_ONE_READ) != 0) { 91 1.27 jmcneill j += 10; 92 1.27 jmcneill } 93 1.27 jmcneill } 94 1.27 jmcneill 95 1.2 drochner if (j >= 10) { 96 1.2 drochner acpi_timecounter.tc_name = "ACPI-Fast"; 97 1.2 drochner acpi_timecounter.tc_get_timecount = acpitimer_read_fast; 98 1.2 drochner acpi_timecounter.tc_quality = 1000; 99 1.2 drochner } 100 1.17 jruoho 101 1.1 drochner tc_init(&acpi_timecounter); 102 1.1 drochner 103 1.19 jruoho aprint_debug_dev(sc->sc_dev, "%s %d-bit timer\n", 104 1.19 jruoho acpi_timecounter.tc_name, bits); 105 1.19 jruoho 106 1.17 jruoho return 0; 107 1.24 jmcneill #else 108 1.24 jmcneill return -1; 109 1.24 jmcneill #endif 110 1.2 drochner } 111 1.1 drochner 112 1.14 dyoung int 113 1.14 dyoung acpitimer_detach(void) 114 1.14 dyoung { 115 1.25 jmcneill #if (!ACPI_REDUCED_HARDWARE) 116 1.23 jmcneill if (!acpitimer_supported()) 117 1.23 jmcneill return -1; 118 1.23 jmcneill 119 1.14 dyoung return tc_detach(&acpi_timecounter); 120 1.24 jmcneill #else 121 1.24 jmcneill return -1; 122 1.24 jmcneill #endif 123 1.14 dyoung } 124 1.14 dyoung 125 1.25 jmcneill #if (!ACPI_REDUCED_HARDWARE) 126 1.17 jruoho u_int 127 1.8 christos acpitimer_read_fast(struct timecounter *tc) 128 1.2 drochner { 129 1.2 drochner uint32_t t; 130 1.2 drochner 131 1.17 jruoho (void)AcpiGetTimer(&t); 132 1.17 jruoho 133 1.17 jruoho return t; 134 1.1 drochner } 135 1.1 drochner 136 1.1 drochner /* 137 1.18 jruoho * Some chipsets (PIIX4 variants) do not latch correctly; 138 1.18 jruoho * there is a chance that a transition is hit. 139 1.1 drochner */ 140 1.17 jruoho u_int 141 1.8 christos acpitimer_read_safe(struct timecounter *tc) 142 1.1 drochner { 143 1.1 drochner uint32_t t1, t2, t3; 144 1.1 drochner 145 1.17 jruoho (void)AcpiGetTimer(&t2); 146 1.17 jruoho (void)AcpiGetTimer(&t3); 147 1.17 jruoho 148 1.1 drochner do { 149 1.1 drochner t1 = t2; 150 1.1 drochner t2 = t3; 151 1.17 jruoho 152 1.17 jruoho (void)AcpiGetTimer(&t3); 153 1.17 jruoho 154 1.1 drochner } while ((t1 > t2) || (t2 > t3)); 155 1.17 jruoho 156 1.17 jruoho return t2; 157 1.1 drochner } 158 1.1 drochner 159 1.18 jruoho uint32_t 160 1.2 drochner acpitimer_delta(uint32_t end, uint32_t start) 161 1.2 drochner { 162 1.17 jruoho const u_int mask = acpi_timecounter.tc_counter_mask; 163 1.2 drochner uint32_t delta; 164 1.2 drochner 165 1.2 drochner if (end >= start) 166 1.2 drochner delta = end - start; 167 1.2 drochner else 168 1.2 drochner delta = ((mask - start) + end + 1) & mask; 169 1.2 drochner 170 1.17 jruoho return delta; 171 1.2 drochner } 172 1.2 drochner 173 1.2 drochner #define N 2000 174 1.17 jruoho 175 1.2 drochner static int 176 1.13 cegger acpitimer_test(void) 177 1.2 drochner { 178 1.2 drochner uint32_t last, this, delta; 179 1.2 drochner int minl, maxl, n; 180 1.2 drochner 181 1.2 drochner minl = 10000000; 182 1.2 drochner maxl = 0; 183 1.2 drochner 184 1.12 jmcneill acpi_md_OsDisableInterrupt(); 185 1.17 jruoho 186 1.17 jruoho (void)AcpiGetTimer(&last); 187 1.17 jruoho 188 1.2 drochner for (n = 0; n < N; n++) { 189 1.17 jruoho 190 1.17 jruoho (void)AcpiGetTimer(&this); 191 1.17 jruoho 192 1.2 drochner delta = acpitimer_delta(this, last); 193 1.17 jruoho 194 1.2 drochner if (delta > maxl) 195 1.2 drochner maxl = delta; 196 1.2 drochner else if (delta < minl) 197 1.2 drochner minl = delta; 198 1.17 jruoho 199 1.2 drochner last = this; 200 1.2 drochner } 201 1.17 jruoho 202 1.12 jmcneill acpi_md_OsEnableInterrupt(); 203 1.2 drochner 204 1.2 drochner if (maxl - minl > 2 ) 205 1.2 drochner n = 0; 206 1.2 drochner else if (minl < 0 || maxl == 0) 207 1.2 drochner n = 0; 208 1.2 drochner else 209 1.2 drochner n = 1; 210 1.2 drochner 211 1.17 jruoho return n; 212 1.2 drochner } 213 1.24 jmcneill #endif 214